从 Redo Log 到秒杀:我对数据库并发控制的一次彻底复盘
从 Redo Log 到秒杀:我对数据库并发控制的一次彻底复盘
https://github.com/fanqingsong/seckill
refs:
https://github.com/fanqingsong/seckill-demo
https://github.com/fanqingsong/itstack-demo-design


太棒了,这个需求来得太及时了 👍
我们把前面的讨论从“聊天”升级为“博客级总结”,既保留深度,又适合对外输出。
下面我给你整理了一份结构清晰、逻辑递进、可直接发表的总结内容,你只需按自己风格润色即可。
从 Redo Log 到秒杀架构:我对数据库并发控制的完整梳理
本文基于一次深度技术讨论整理而成,涵盖了事务、日志、MVCC、锁机制以及高并发场景下的架构设计。希望能帮你把零散的知识点串联成体系。
一、开篇:数据库是如何“记住”一切的?
事务是数据库的灵魂,而 ACID 是事务的四大支柱。在 InnoDB 中,这套机制并不是靠单一组件实现的,而是靠一套精密的协作体系。
1. 持久性(Durability):Redo Log 的安全网
为了保证“已提交的事务绝不丢失”,InnoDB 采用了 WAL(Write-Ahead Logging,预写日志) 机制。
- Redo Log 记录的是数据页的物理变更(“在某个偏移量写了什么值”)。
- 事务提交时,必须先将 Redo Log 从内存刷入磁盘(fsync)。
- 即使数据页还没来得及写入磁盘就发生断电,重启后依然可以通过 Redo Log 重做(Redo) 已提交的修改。
2. 原子性(Atomicity):Undo Log 的后悔药
- Undo Log 记录的是数据的旧值。
- 当事务执行失败或调用
ROLLBACK时,利用 Undo Log 将数据恢复到修改前的状态。 - 同时,Undo Log 也是 MVCC(多版本并发控制) 的基石。
二、隔离性(Isolation):并发控制的两套武器
隔离性解决的是“多个事务同时执行时,如何互不干扰”。InnoDB 主要依靠 MVCC 和 锁 两套机制。
1. MVCC:读写互不阻塞的魔法
MVCC 的核心思想是:为数据维护多个历史版本。
- 隐藏字段:每行记录包含
trx_id(事务ID)和roll_ptr(指向 Undo Log 的指针)。 - Read View(快照):事务启动时生成一个“快照”,之后的普通
SELECT都基于这个快照读取历史版本。 - 快照读 vs 当前读:
- 普通
SELECT 是快照读,利用 MVCC 无锁读取,性能极高。 UPDATE/DELETE/SELECT FOR UPDATE 是当前读,必须读取最新版本并加锁,绕过 MVCC。
- 普通
2. 锁机制:解决写冲突的底线
当 MVCC 无法满足强一致性要求时,就需要锁出场。
- 共享锁(S 锁 / 读锁):允许多个事务同时读取,但阻止其他事务修改。适用于“我读的时候,别人别改”的场景。
- 排他锁(X 锁 / 写锁):事务独占资源。
UPDATE和SELECT FOR UPDATE加的都是 X 锁,强度最高,会阻塞其他一切的读写尝试。
三、并发控制的哲学:乐观 vs 悲观
理解了底层锁,我们上升到设计思想层面:乐观并发控制与悲观并发控制。
|
维度
|
悲观并发
|
乐观并发
|
|---|---|---|
|
核心思想
|
假设冲突一定会发生,先上锁,后处理。
|
假设冲突概率很低,先处理,提交时校验。
|
|
实现手段
|
依赖数据库的 S/X 锁。
|
依赖 版本号、CAS 或 业务状态机。
|
|
冲突处理
|
阻塞等待,直到获取锁。
|
提交失败,应用层重试。
|
|
适用场景
|
金融核心、库存扣减(强一致)。
|
配置更新、用户资料修改(高并发)。
|
关键认知:MVCC 本质上是一种乐观的读策略(无锁读),而数据库的写操作永远是悲观的(必须加锁)。
四、实战升华:秒杀架构中的一致性博弈
理论最终要服务于实战。以“秒杀库存”为例,我们看到了不同技术方案的权衡。
1. 为什么不能直接用数据库锁?
纯悲观锁(
FOR UPDATE)在秒杀场景下是灾难:- 10 万 QPS 的请求会导致大量线程阻塞,数据库连接池瞬间耗尽。
- 行锁竞争激烈,RT(响应时间)飙升。
2. 正确的架构:缓存预扣 + 异步落库
成熟的秒杀方案通常采用 乐观思想 + 最终一致性:
- Redis 原子扣减:利用 Redis 单线程和 Lua 脚本,在内存中完成库存的极速预占。这是抗并发的关键。
- 消息队列(MQ)解耦:将扣减成功的请求放入队列,削峰填谷。
- 数据库最终确认:消费者异步读取 MQ,利用数据库的 悲观锁(FOR UPDATE) 进行最终的库存校验和扣减,保证数据的绝对准确。
3. 链路中的身份传递
在整个分布式链路中,用户 ID 和订单 ID 必须通过消息体在系统中传递,而不是依赖下游去 Redis 反查。这样才能保证 Redis、MQ 和数据库三者之间的数据一致性。
五、结语
从 Redo/Undo Log 的物理实现,到 MVCC 的版本链,再到 S/X 锁的互斥逻辑,最后落地到秒杀架构的高并发设计。数据库技术就像一个精密的钟表:
- Redo Log 保证了即使摔在地上(宕机),指针也不会乱走;
- MVCC 让读指针和写指针互不干扰;
- 锁 则在必要时强制让指针停下来,等待同步。
理解这些底层原理,不仅能帮我们写出更健壮的代码,更能让我们在面对高并发挑战时,做出最合理的技术选型。
📝 博客写作建议
- 配图:建议配上 Redo Log 循环写入图、MVCC 版本链图 和 秒杀架构流程图,会非常加分。
- 代码块:文中的 SQL 和 Lua 脚本建议用代码块高亮展示。
- 标题优化:你可以根据博客平台的调性,把标题改得更吸引人,例如:
- 《别再死记硬背 ACID 了,聊聊 InnoDB 背后的生存法则》
- 《从 Redo Log 到秒杀:我对数据库并发控制的一次彻底复盘》
需要我再帮你提炼几个适合发朋友圈或公众号的金句吗?😄
出处:http://www.cnblogs.com/lightsong/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

浙公网安备 33010602011771号