ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DDIA 导读(七):事务

DDIA 导读(七):事务 本文是《Designing Data-Intensive Applications》DDIA中文译名《数据密集型应用系统设计》第 7 章的导读。DDIA 是 Martin Kleppmann 所著的分布式系统经典本系列逐章导读把书的核心概念讲清楚。一句话主旨事务是把多个操作打包成一个原子单元的抽象——要么全做要么全不做。但全做全不做在并发和故障下要付出代价而代价的大小取决于你选多强的隔离级别。本章的核心不是 ACID 的定义而是隔离级别的谱系从最弱的读未提交到最强的可串行化每一级挡掉一类并发异常也付出一份性能代价。核心概念拆解1. ACID——四个保证但 A 和 I 是重点靠 undo log / WAL靠锁/MVCC靠 WAL fsync应用层约束A 原子性全做或全不做C 一致性不变量不被破坏I 隔离性并发如串行D 持久性提交了就不丢回滚机制并发控制预写日志应用保证A 原子性一组操作要么全成功要么全回滚。靠 undo log / WAL 实现。C 一致性数据的业务不变量如余额不为负在事务后仍成立。C 是应用层责任数据库提供 A/I/D 帮你达到 C但 C 本身要应用定义。I 隔离性并发事务互不干扰效果如同串行执行。这是本章主角——完整隔离可串行化代价高所以有各级别。D 持久性事务提交后即使断电也不丢。靠 WAL fsync。A、I、D 是数据库机制C 主要是应用责任。第 7 章几乎全在讲 I隔离级别因为 I 是性能与正确性权衡的主战场。2. 隔离级别的谱系——每级挡一类异常这是本章的重头。并发事务会互相干扰产生各种异常anomaly。隔离级别从弱到强每级挡掉一类异常代价是性能下降。挡脏读挡不可重复读挡幻读(部分)挡写偏斜/完整读未提交 Read Uncommitted能读到别人未提交的(脏读)读已提交 Read Committed只读已提交的, 但同一行两次读可能不同(不可重复读)可重复读 Repeatable Read同一行多次读一致, 但范围查询可能多/少行(幻读)快照隔离 Snapshot Isolation读一个一致快照, 写写冲突靠乐观检测可串行化 Serializable完全等价于串行, 无任何异常四种并发异常从轻到重① 脏读Dirty Read——读到别人还没提交的数据。对方回滚了你读的就成了从未存在过的数据。读未提交级别下发生读已提交挡掉。② 不可重复读Non-repeatable Read——同一事务里读同一行两次值变了别人提交了更新。读已提交下发生可重复读挡掉。③ 幻读Phantom Read——同一事务里范围查询两次结果集行数变了别人提交了插入/删除。可重复读挡行级读一致但挡不住范围新增快照隔离挡掉。④ 写偏斜Write Skew——两个事务各自读了一致快照基于快照各自做决策并写入两个写入合在一起违反了业务约束但单独看都不违规。快照隔离挡不住这个只有可串行化挡得住。写偏斜是快照隔离的盲区也是最难直觉理解的异常。经典例子值班规则要求至少一人值班A 和 B 都在值班两人同时申请休假——各自快照里看到对方在值班我走没关系都提交休假结果没人值班。单独看每个事务都合规合起来违反约束。只有可串行化能防。问题→方案问题——并发操作互相干扰产生异常。场景——多个事务同时读写相同数据弱隔离下出现脏读/不可重复读/幻读/写偏斜。方案——隔离级别谱系每升一级挡掉一类异常代价是性能下降。读已提交挡脏读可重复读挡不可重复读快照隔离靠 MVCC 让读写不互锁读历史版本、写写冲突先到先赢可串行化靠 2PL 或 SSI 挡写偏斜。选哪级 你能容忍哪种异常 vs 愿付多少性能代价。3. 快照隔离SI——现代主流事务2(开始于t20)数据库(MVCC)事务1(开始于t10)事务2(开始于t20)数据库(MVCC)事务1(开始于t10)快照隔离: 事务看到自己开始时刻的一致视图读X(看到t10时的快照版本)写X新值并提交再读X(仍看到t10快照, 不受T2影响)核心机制——MVCC多版本并发控制每行数据有多个版本带时间戳/事务号事务开始时拍一个快照——只看开始时刻已提交的版本读不阻塞写写不阻塞读各看各版本——读写不互锁这是 SI 高性能的关键写写冲突检测两个事务同时改同一行后提交的被检测到冲突并回滚first-committer-wins大多数现代 OLAP/HTAP 系统都用 MVCC 快照隔离。分析负载以读为主弱隔离够用且快得多。4. 乐观锁 vs 悲观锁——两种并发控制思路乐观锁 (Optimistic)无冲突有冲突读改(不加锁)提交时检测冲突?提交成功回滚重试悲观锁 (Pessimistic)先加锁改数据提交/释放锁悲观锁先锁再改。冲突多时高效少重试但锁等待开销大、死锁风险。乐观锁OCC先干再提交时验证。冲突少时高效无锁开销冲突多时大量重试反而慢。5. 两阶段锁2PL——可串行化的经典实现直觉事务分两阶段——扩张阶段只加锁不释放和收缩阶段只释放不加锁。只要严格遵守 2PL结果必然可串行化。违反: 提前释放再抢新锁扩张阶段按需加锁, 不释放收缩阶段释放锁, 不再加锁可能不可串行化2PL 的代价锁等待多并发度低死锁A 等 B 的锁B 等 A 的锁 → 要检测并杀一个性能远不如 MVCC用纯 2PL 的在减少因为锁开销大、死锁频繁。大多数用 MVCC 快照隔离只在需要可串行化时才上 2PL 或 SSISerializable Snapshot Isolation一种结合快照和冲突检测的可串行化方案。6. 可串行化的现代实现——SSISSISerializable Snapshot Isolation在快照隔离基础上额外检测写偏斜模式的冲突——跟踪事务的读依赖若多个事务的读依赖可能形成写偏斜abort 其中一个。比 2PL 性能好仍是 MVCC 无锁读但比 SI 有额外跟踪开销。DDIA 重点是让你知道可串行化有三条路线实际串行执行VoltDB/Redis、2PL、SSI其中 SSI 是现代更好的选择但大多数系统默认不开快照隔离够用且更快。Mermaid隔离级别与异常对照隔离级别(从弱到强)并发异常(从轻到重)有有有有挡脏读 Dirty Read不可重复读 Non-repeatable Read幻读 Phantom写偏斜 Write Skew读未提交⚠️脏读读已提交⚠️不可重复读可重复读⚠️幻读快照隔离 SI⚠️写偏斜可串行化✅无异常, 最慢下一篇第 8 章——分布式系统的麻烦。分布式系统的部分失效、不可靠网络与时钟。
返回列表