知识卡片
可串行化的三条实现路径真的串行执行两阶段锁定与可串行化快照隔离
内容
[[写偏差是比丢失更新更隐蔽的多对象写写冲突]][[幻读导致写偏差的通用模式及物化冲突 这个最后手段]]这类问题的根本解法是可串行化隔离——保证事务并发执行的最终结果和它们 按某个顺序一个接一个串行执行完全一样,因此能防住所有可能的竞争条件。实现路径有三条。 真的串行执行:干脆不要并发,单线程按顺序一次跑一个事务,直接绕开了检测/防止冲突的 全部麻烦。这条路直到2007年前后才被认为可行,靠两个前提支撑:内存足够便宜、能把 活跃数据集整个放进内存(避免磁盘I/O等待);OLTP事务通常很短、只涉及少量读写, 长时间的分析查询可以另外走快照隔离的只读路径。为了让单线程吞吐量够用,这类系统 (VoltDB、Redis、Datomic)要求应用把整个事务预先写成存储过程一次性提交,而不是像 传统交互式事务那样一条条语句来回和数据库对话——省下的网络往返时间正是单线程模式 能扛住吞吐量的关键;写入压力太大时可以按数据分区、每个分区各自跑一个独立事务线程, 但跨分区事务需要协调多个分区的存储过程,代价高昂(VoltDB报告跨分区写入吞吐量比 单分区低几个数量级,且不能靠加机器解决)。两阶段锁定(2PL):30年来事实上唯一广泛 使用的可串行化算法,靠共享锁+排它锁把”写会阻塞读、读也会阻塞写”这个更强的互斥关系 落到底,代价是吞吐量和响应时间都明显更差,且死锁频率高、高百分位延迟不稳定。 可串行化快照隔离(SSI):2008年提出的乐观并发控制技术,基于快照隔离,额外加一层 机制侦测事务间的串行化冲突、在提交时才决定是否中止,性能损失比2PL小得多,正逐渐 成为有前景的默认选项(PostgreSQL 9.1起、FoundationDB都用了类似算法)。
结构图:
flowchart TD
A[可串行化隔离] --> B[真的串行执行: 单线程顺序跑]
B --> B1[要求活跃数据在内存+事务预写成存储过程]
B1 -.吞吐受限单核, 需按分区拆分, 跨分区代价高.-> B1
A --> C[两阶段锁定 2PL: 悲观并发控制]
C --> C1[读写互斥, 持锁到事务结束]
C1 -.吞吐量差, 死锁频繁, 延迟不稳定.-> C1
A --> D[可串行化快照隔离 SSI: 乐观并发控制]
D --> D1[基于快照隔离+提交时检测冲突]
D1 -.性能损失比2PL小, 读不阻塞写写不阻塞读.-> D1
参考来源
- 位置:《数据密集型应用系统设计》第七章《事务》"可串行化""真的串行执行""两阶段
锁定""可串行化快照隔离"(源文件:_epub-src/ch7_split_004.html, ch7_split_005.html,
ch7_split_006.html)
- 结论依据:原文说明目前实现可串行化的三种主流技术是真的串行执行、两阶段锁定、
可串行化快照隔离,并分别展开各自的原理和代价(单线程+存储过程/悲观锁+死锁/
乐观检测+提交时中止),直接支撑本卡片对三条路径的结构梳理。
- 原始内容:目前大多数提供可串行化的数据库都使用了三种技术之一……字面意义上地
串行顺序执行事务……两阶段锁定,几十年来唯一可行的选择……乐观并发控制技术,
例如可串行化快照隔离。