Skip to main content

锁机制漫聊

19 min read

想纵览从 kernel, 各种 DB,语言,服务 的锁机制

我想写一篇

锁机制漫聊

为标题的 blog

想纵览从 kernel, 各种 DB,语言,服务 的锁机制

## 你觉得怎么写这篇 blog 比较好?大纲?可以向哪些方向拓展?如果我想写好这篇 blog,应该研究哪些方面?看看哪些书?才能写好

这是一个非常有深度的主题,我来帮你规划一下这篇博客的架构和研究方向。

# 建议大纲

## 1. 引言

- 为什么需要锁机制
- 并发问题的本质
- 锁机制在不同层面的应用场景

## 2. 基础概念

- 临界区(Critical Section)
- 死锁(Deadlock)
- 活锁(Livelock)
- 饥饿(Starvation)
- 竞态条件(Race Condition)

## 3. 操作系统级锁机制

### 3.1 内核锁

- 自旋锁(Spinlock)
- 读写锁(RW Lock)
- 互斥锁(Mutex)
- 信号量(Semaphore)
- RCU(Read-Copy Update)

### 3.2 用户空间锁

- Futex(Fast Userspace Mutex)
- POSIX 线程锁
- 条件变量

## 4. 数据库锁机制

### 4.1 MySQL

- 表级锁
- 行级锁
- 意向锁
- 间隙锁
- Next-Key Lock

### 4.2 PostgreSQL

- 表级锁
- 行级锁
- 咨询锁
- 谓词锁

### 4.3 Redis

- RedLock 算法
- 分布式锁实现

## 5. 编程语言级锁机制

### 5.1 Java

- synchronized
- ReentrantLock
- ReadWriteLock
- StampedLock

### 5.2 Go

- sync.Mutex
- sync.RWMutex
- Channel 机制
- atomic 包

### 5.3 Rust

- Mutex
- RwLock
- 所有权系统与锁

## 6. 分布式系统锁机制

- 分布式锁实现方案
- Zookeeper 锁
- etcd 锁
- 基于 Redis 的分布式锁
- 分布式事务

## 7. 锁的性能与优化

- 锁的粒度选择
- 锁竞争与性能
- 无锁编程(Lock-free Programming)
- 乐观锁 vs 悲观锁
- CAS(Compare And Swap)

## 8. 最佳实践与案例分析

- 常见的锁使用模式
- 典型的多线程问题
- 实际项目中的锁使用案例
- 锁相关的性能问题诊断

# 建议研究的方向与资料

## 1. 操作系统层面

### 推荐书籍:

- 《Operating Systems: Three Easy Pieces》
- 《Linux Kernel Development》
- 《Understanding the Linux Kernel》

## 2. 数据库层面

### 推荐书籍:

- 《High Performance MySQL》
- 《PostgreSQL 实战》
- 《Redis 设计与实现》

## 3. 并发编程

### 推荐书籍:

- 《Java Concurrency in Practice》
- 《C++ Concurrency in Action》
- 《Concurrent Programming in Go》

## 4. 分布式系统

### 推荐书籍:

- 《Designing Data-Intensive Applications》
- 《Distributed Systems for Fun and Profit》

# 研究方法建议

1. **源码研究**

- Linux kernel 中的锁实现
- 各个数据库的锁实现
- 不同编程语言的锁实现

2. **实验验证**

- 搭建测试环境
- 编写测试用例
- 性能测试与对比

3. **问题分析**

- 收集实际项目中的锁相关问题
- 分析死锁案例
- 性能瓶颈分析

4. **工具使用**
- 学习使用各种调试工具
- 性能分析工具
- 死锁检测工具

# 建议关注的重点

1. **理论基础**

- 并发理论
- 死锁理论
- 一致性模型

2. **实现机制**

- 硬件层面的原子操作
- 操作系统的调度机制
- 不同锁的实现原理

3. **性能考量**

- 锁的开销
- 竞争处理
- 扩展性问题

4. **实践经验**
- 设计模式
- 最佳实践
- 常见陷阱

# 写作建议

1. **循序渐进**

- 从基础概念开始
- 逐步深入到复杂主题
- 适当的类比和图示

2. **实例驱动**

- 提供具体的代码示例
- 分析真实的案例
- 包含性能测试数据

3. **对比分析**

- 不同实现方案的对比
- 优劣势分析
- 适用场景讨论

4. **实用性**
- 提供实际可用的最佳实践
- 包含常见问题的解决方案
- 性能优化建议

这个主题确实很有深度,建议可以分多篇文章逐步展开,每个主题都可以深入展开成一篇独立的文章。研究过程中要注意理论与实践相结合,多做实验验证,多看源码实现。希望这个规划对你有帮助!
能否帮我找一些别人写的类似主题的 blog 吗?最好中文和英文都提供一些

---

我来帮你搜集一些关于锁机制的高质量博客文章。

中文文章:

1. [深入理解互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景](https://www.jianshu.com/p/ef8de88b1343)

- 作者从实践角度详细对比了各种锁的特点和使用场景

2. [浅谈数据库并发控制 - 锁和 MVCC](https://draveness.me/database-concurrency-control/)

- draveness 的文章,质量很高,主要讲数据库中的锁实现

3. [操作系统:锁的本质](https://www.cnblogs.com/xiaolincoding/p/13675202.html)

- 小林 coding 的文章,从底层讲解锁的实现原理

4. [Redis 分布式锁的实现原理与最佳实践](https://www.infoq.cn/article/dvaaj71f4fbqsxmgvdce)
- InfoQ 上的文章,专注于分布式锁的实现

英文文章:

1. [Locks in Operating Systems](https://www.cs.cornell.edu/courses/cs4410/2015su/lectures/lec06-spin.html)

- Cornell 大学的课程材料,非常专业的锁机制讲解

2. [Understanding MySQL InnoDB Locking](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html)

- MySQL 官方文档,详细介绍了 InnoDB 的锁机制

3. [Linux Kernel Locking](https://www.kernel.org/doc/html/latest/locking/index.html)

- Linux 内核官方文档,介绍了内核中的各种锁实现

4. [Lock-Free Programming](http://preshing.com/20120612/an-introduction-to-lock-free-programming/)
- 详细介绍无锁编程的概念和实践

系列文章:

1. Martin Kleppmann 的博客

- [Distributed Systems Series](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html)
- 分布式系统专家的深度好文

2. 酷壳陈皓的系列文章
- [https://coolshell.cn/tag/锁](https://coolshell.cn/tag/锁)
- 包含多篇关于并发编程和锁机制的文章

学术论文:

1. "The Art of Multiprocessor Programming"

- Maurice Herlihy 的经典著作,深入讲解并发编程

2. "A Critique of ANSI SQL Isolation Levels"
- 经典论文,讨论数据库事务隔离级别

GitHub 项目:

1. [concurrency-limits](https://github.com/Netflix/concurrency-limits)

- Netflix 的并发限制库,包含很多锁相关的实现

2. [awesome-distributed-systems](https://github.com/theanalyst/awesome-distributed-systems)
- 分布式系统资源集合,包含很多关于分布式锁的资料

建议阅读顺序:

1. 先从中文博客入手,建立基本概念

- 小林 coding 的文章
- draveness 的文章

2. 深入理解原理

- Cornell 的课程材料
- Linux 内核文档

3. 实践应用

- MySQL 官方文档
- Redis 分布式锁文章

4. 前沿研究
- Martin Kleppmann 的博客
- 相关学术论文

注意事项:

1. 注意文章的时效性,锁机制在不断演进
2. 关注各种实现的优劣对比
3. 结合实际场景来理解
4. 动手实践验证文章中的概念

这些资源应该能给你提供不同层面和深度的参考。建议先大致浏览,然后根据你文章的重点选择性深入阅读。如果你需要特定主题的更多资源,我可以进一步推荐。

5.4 服务幂等性设计 | 深入高可用系统原理与设计

计算机系统里的锁到底是啥

相关概念除了

## 乐观锁、死锁、哲学家就餐问题 还有啥?

在计算机系统中,锁是一种用于控制对共享资源访问的同步机制,目的是防止多个执行单元(如线程、进程)同时访问共享资源而导致数据不一致或其他并发问题。除了乐观锁、死锁、哲学家就餐问题相关概念外,还有以下常见的锁概念:

### 1. 悲观锁

- **原理
**:悲观锁认为在其整个数据处理过程中,其他执行单元极有可能会对共享资源进行修改。因此,在获取数据时,就对数据进行加锁,阻止其他执行单元访问,直到该锁被释放。
- **应用场景
**:适用于写操作频繁,且读取数据后需要对数据进行修改的场景,如银行转账操作,在整个转账流程中,需要锁定账户金额,防止其他操作同时修改账户余额。

### 2. 读写锁

- **原理
**:读写锁区分了读操作和写操作的并发控制。它允许多个执行单元同时进行读操作,因为读操作不会修改数据,不会产生数据不一致问题。但当有一个执行单元进行写操作时,会阻止其他读、写操作,以保证数据的一致性。读写锁通常有两种状态:读锁(共享锁)和写锁(排他锁)。
- **应用场景
**:适用于读多写少的场景,例如数据库中的数据查询场景,大量用户同时读取数据,而写操作相对较少。此时使用读写锁可以提高系统的并发性能。

### 3. 自旋锁

- **原理
**:当一个线程尝试获取自旋锁时,如果锁已经被其他线程持有,该线程不会立即进入睡眠状态,而是在原地循环等待,不断尝试获取锁,直到锁被释放。自旋锁适用于锁被持有时间较短的情况,因为线程自旋等待避免了线程上下文切换带来的开销。
- **应用场景
**:常用于内核态中,一些临界区执行时间很短的场景。例如在多核 CPU 的系统中,内核中某些数据结构的访问控制,使用自旋锁可以在不进行线程上下文切换的情况下,快速获取锁并执行临界区代码。

### 4. 互斥锁

- **原理
**:互斥锁是一种最基本的锁类型,它保证在同一时刻只有一个执行单元能够访问共享资源,就像一个“通行证”,谁拿到了就能访问资源,其他单元只能等待。当一个线程获取了互斥锁,其他线程想要获取该锁时,就会被阻塞,直到持有锁的线程释放锁。
- **应用场景
**:广泛应用于各种需要保证数据一致性的场景,如多线程访问共享内存区域、文件操作等。例如,多个线程同时向一个文件写入数据时,为防止数据混乱,使用互斥锁保证同一时间只有一个线程能进行写入操作。

### 5. 公平锁与非公平锁

- **原理**
- **公平锁
**:公平锁保证等待时间最长的线程最先获取锁,按照线程请求锁的顺序来分配锁,就像排队一样,先来先得。这种机制确保了所有线程都有公平获取锁的机会。
- **非公平锁
**:非公平锁则不保证线程获取锁的顺序,在锁可用时,任何等待锁的线程都有机会竞争获取锁,可能会出现后请求锁的线程先于等待时间长的线程获取锁的情况。
- **应用场景**
- **公平锁**:适用于对公平性要求较高的场景,例如一些资源调度系统,需要保证每个任务都能按照提交顺序依次获得资源。
- **非公平锁
**:在性能要求较高,且对公平性要求不那么严格的场景中使用。由于非公平锁在竞争锁时不需要按照顺序排队,减少了线程切换的开销,能提高系统的整体吞吐量,如高并发的网络服务器场景。
计算机系统里,各种语言有锁,各种服务有锁,什么都有锁

## 那最早的锁机制是跟什么相关的呢?是 kernel 吗?

最早的锁机制与操作系统内核紧密相关 。在早期计算机系统多道程序设计发展阶段,引入锁机制用于解决并发访问问题:

- **多道程序设计背景
**:20 世纪 60 年代,计算机从单道程序执行发展到多道程序设计,允许多个程序同时驻留在内存并交替执行,提高 CPU 利用率。但多个程序可能共享诸如内存、I/O 设备等资源,若不加控制,会引发数据不一致等问题。例如,多个程序同时向打印机发送数据,会导致打印内容混乱。
- **内核中锁机制诞生
**:操作系统内核作为管理计算机硬件与软件资源的核心,为应对多道程序并发访问共享资源的问题,引入锁机制。通过锁,内核可控制对共享资源的访问,保证同一时刻只有一个程序能使用特定资源。例如,内核利用锁保护临界区(共享资源访问代码段),进程进入临界区前需获取锁,访问结束后释放锁,其他进程才能获取锁进入。
- **早期锁机制形式
**:早期锁机制相对简单,以互斥锁为典型,确保对共享资源的互斥访问。随着计算机系统发展,锁机制不断丰富,出现读写锁、自旋锁等多种类型,满足不同场景需求。但无论如何演变,锁机制最初都是在内核中为解决多道程序并发访问共享资源问题而诞生。
## 那 kernel 里有乐观锁吗?

在操作系统内核中,虽然不像在一些高级语言的并发编程框架中那样广泛使用乐观锁,但实际上内核里是存在乐观锁机制的应用场景和实现的。

### 1. 乐观锁在内核中的应用场景

- **数据访问冲突概率低的场景**:内核中某些数据结构的访问场景,并发访问冲突的概率相对较低。例如,一些内核子系统中,特定数据结构的更新操作并不频繁,且大部分时间内多个执行单元(如内核线程)对其进行读取操作时不会发生冲突。在这种情况下,使用乐观锁可以避免悲观锁带来的频繁加锁、解锁开销,从而提高系统性能。
- **无锁数据结构操作**:在构建无锁数据结构时,乐观锁概念经常被用到。例如,在一些基于链表或哈希表的无锁数据结构实现中,内核开发者会利用乐观锁的思想,让线程先尝试执行操作,假设在操作过程中不会发生冲突。只有在检测到冲突时,才采取相应的回滚或重试策略。

### 2. 内核中乐观锁的实现方式举例

- **基于版本号(Epoch)的机制**:在内核的某些同步机制中,会使用类似版本号的概念。例如,对于一些内核数据结构,每次对其进行修改时,都会增加一个版本号。当一个线程想要读取数据时,它会记录当前的版本号。在读取操作完成后,再次检查版本号。如果版本号没有变化,说明在读取过程中没有其他线程对数据进行修改,读取操作成功;如果版本号发生了变化,说明有其他线程修改了数据,当前线程需要根据具体情况选择重试或采取其他措施。这就是一种乐观锁的实现方式,通过版本号来乐观地假设读取过程中不会发生冲突。
- **原子操作结合重试**:内核利用 CPU 提供的原子操作指令(如比较并交换指令,即 CAS 指令)来实现乐观锁。例如,在尝试对某个共享变量进行更新时,先读取当前变量的值,根据业务逻辑计算出要更新的新值,然后使用 CAS 指令尝试将变量从当前值更新为新值。如果 CAS 操作成功,说明在这期间没有其他线程修改该变量,更新操作完成;如果 CAS 操作失败,说明有其他线程已经修改了变量,当前线程需要重试整个操作。这种基于原子操作结合重试的方式,体现了乐观锁的思想,即先乐观地尝试操作,失败后再处理冲突。
  • **基于版本号(Epoch)的机制 **:在内核的某些同步机制中,会使用类似版本号的概念。例如,对于一些内核数据结构,每次对其进行修改时,都会增加一个版本号。当一个线程想要读取数据时,它会记录当前的版本号。在读取操作完成后,再次检查版本号。如果版本号没有变化,说明在读取过程中没有其他线程对数据进行修改,读取操作成功;如果版本号发生了变化,说明有其他线程修改了数据,当前线程需要根据具体情况选择重试或采取其他措施。这就是一种乐观锁的实现方式,通过版本号来乐观地假设读取过程中不会发生冲突。
  • **原子操作结合重试 **:内核利用 CPU 提供的原子操作指令(如比较并交换指令,即 CAS 指令)来实现乐观锁。例如,在尝试对某个共享变量进行更新时,先读取当前变量的值,根据业务逻辑计算出要更新的新值,然后使用 CAS 指令尝试将变量从当前值更新为新值。如果 CAS 操作成功,说明在这期间没有其他线程修改该变量,更新操作完成;如果 CAS 操作失败,说明有其他线程已经修改了变量,当前线程需要重试整个操作。这种基于原子操作结合重试的方式,体现了乐观锁的思想,即先乐观地尝试操作,失败后再处理冲突。

聊聊Mysql锁机制 | 暗夜零星

聊一聊数据库中的锁分类(乐观锁、悲观锁、共享锁、排它锁、表级锁、行级锁、页面锁) - 蓝涩街灯 - 博客园

MySQL共享锁、排他锁、悲观锁、乐观锁

MVCC由浅入深学习!我们知道,根据MySQL的锁机制,写锁和读锁是冲突的,所以MySQl通过MVCC(多版本并发控制) - 掘金

能否再给我提供一些大纲吗?从不同的角度出发的不同大纲。我想挑一个写法。

---


我来提供几个不同视角的大纲方案,你可以根据自己的偏好选择或混合使用。

# 方案一:从抽象层次递进的角度

1. 什么是锁

- 锁的本质
- 为什么需要锁
- 锁要解决的核心问题

2. 硬件级别的原子操作

- CPU 原子指令
- 内存屏障
- Cache 一致性协议

3. 操作系统级别

- 系统调用
- 内核锁实现
- 用户态锁实现

4. 编程语言级别

- 各语言的锁抽象
- 实现差异
- 最佳实践

5. 框架和中间件级别

- 数据库锁
- 分布式锁
- 消息队列

6. 应用层面
- 设计模式
- 实践经验
- 性能优化


# 方案二:从问题导向的角度




1. 并发问题的本质

- 共享资源
- 竞态条件
- 一致性要求

2. 锁的基本特性

- 互斥性
- 可重入性
- 公平性
- 等待机制

3. 常见并发问题及解决方案

- 死锁问题
- 活锁问题
- 饥饿问题
- 优先级反转

4. 性能相关问题

- 锁竞争
- 上下文切换
- 缓存一致性
- 扩展性瓶颈

5. 分布式场景的挑战

- 网络延迟
- 部分失败
- 一致性问题
- CAP 理论

6. 实践总结
- 设计原则
- 调试技巧
- 性能调优
- 最佳实践


# 方案三:从演进历史的角度

1. 单线程时代

- 最初的计算机
- 单进程模型
- 协作式多任务

2. 多进程/线程时代

- 抢占式调度
- 进程间通信
- 线程同步原语

3. 多核时代

- 缓存一致性
- 内存模型
- 无锁编程

4. 分布式时代

- 分布式锁
- 一致性协议
- 最终一致性

5. 未来展望
- 新型硬件特性
- 新的编程模型
- 趋势预测


# 方案四:从实现机制的角度

1. 锁的基本实现机制

- 自旋锁
- 互斥锁
- 读写锁
- 条件变量

2. 乐观并发控制

- CAS 操作
- 版本控制
- MVCC

3. 悲观并发控制

- 二阶段锁定
- 死锁预防
- 死锁检测

4. 特殊用途的锁

- 意向锁
- 区间锁
- 谓词锁

5. 分布式协调
- 领导者选举
- 分布式互斥
- 共识算法


# 方案五:从应用场景的角度

1. 操作系统调度

- 进程调度
- 资源管理
- 设备驱动

2. 数据库系统

- 并发控制
- 事务处理
- 恢复机制

3. 高并发服务

- 连接池
- 线程池
- 限流器

4. 分布式系统

- 分布式事务
- 配置管理
- 服务协调

5. 实时系统
- 优先级继承
- 优先级天花板
- 实时调度


# 方案六:从工程实践的角度

1. 锁的选择原则

- 场景分析
- 性能需求
- 正确性保证

2. 常见陷阱

- 死锁场景
- 性能问题
- 常见错误

3. 调试与诊断

- 工具使用
- 日志分析
- 性能分析

4. 测试策略

- 单元测试
- 压力测试
- 故障注入

5. 最佳实践
- 设计模式
- 代码规范
- 性能优化


建议:
1. 可以选择一个主要框架,然后从其他框架中借鉴有价值的部分
2. 考虑你的目标读者群体,选择合适的深度和广度
3. 可以先写一个简单的大纲,然后逐步扩充
4. 建议加入具体的示例和案例分析
5. 考虑是否要包含性能测试数据

你更倾向于哪个角度?我可以帮你进一步细化选定的大纲。

彻底掌握 MySQL InnoDB 的锁机制 - Lucky 小黄人^_^ - 博客园

013. 跨行程序员 driftluo 的 Rust 历程 - RustTalk | 小宇宙 - 听播客,上小宇宙 48:53 如何在热点路径上选择适合的锁类型?——探讨同步锁和异步锁的性能开销。