Hasty Briefsbeta

双语

How MVCC and Transactions Work in RocksDB

5 hours ago
  • RocksDB 使用 LSM 树结构,每次写入都会创建键的新版本,从而实现 MVCC 的一半功能;另一半则需要快照和能感知正在进行的读取操作的垃圾回收机制。
  • 每次写入都会分配一个单调递增的序列号;读取操作在开始时捕获已发布的序列号以查看一致快照,并跳过更高的序列号。
  • 内存表是一个并发跳表,按用户键升序和序列号降序排列;原子写入使用写入批处理来原子性地分配序列号,确保不会出现部分更新可见的情况。
  • 快照会固定一个序列号,并阻止压缩删除仍需要的版本;引用计数的 SuperVersion 结构协调安全清理内存表和 SST 文件。
  • 悲观事务在写入操作时锁定键以进行早期冲突检测;乐观事务将冲突检查推迟到提交时间,使用轻量级哈希互斥锁进行验证。
  • 隔离级别范围从读已提交(无快照)到快照隔离和可序列化(使用 get_for_update 锁定读取的键并防止写偏斜)。
  • 余额转账示例展示了如何使用快照和 get_for_update 的事务防止丢失更新和竞争条件。
  • 性能对比:悲观事务在争用键上表现更好,通过阻塞和避免重做;乐观事务在冲突稀少且重试成本低时表现优异。
  • RocksDB 原生事务被 MyRocks 和 ArangoDB 使用;像 TiDB 和 CockroachDB 这样的分布式数据库在键值存储之上实现自己的事务层。
  • 核心复杂性在于并发控制,而非 MVCC 本身;序列号是快照、原子批处理和冲突检测的基本原语。