土法炼钢兴趣小组的算法知识备份

【RocksDB 内核机制】事务与 OptimisticTransactionDB:WritePrepared 边界

文章导航

分类入口
databasestorage
标签入口
#rocksdb#transaction#optimistic-transaction-db#write-prepared#write-committed#occ#snapshot#tikv

目录

第 13 篇 把多 CF 共享 WAL 钉住了。WriteBatch + 单次 DB::Write 已保证 批内原子性第 4 篇),但 保证「读-改-写」在并发下无冲突:两个线程各自读旧值、各自提交,后写者覆盖先写者,除非上层自己做锁或版本校验。

RocksDB 在 TransactionDB / OptimisticTransactionDB 上提供 BEGIN / COMMIT / ROLLBACK 式 API,在提交时做冲突检测。本文是系列 第 14 篇,沿 Wiki TransactionsWritePrepared Transactions 说明悲观与乐观路径、三种 WritePolicy 边界,以及 TiKV 与单机 RocksDB 事务的分工(B 级前瞻,Percolator / Raft 留 db-frontier HTAP 与第 18 篇续作)。

本文是「RocksDB 内核机制」系列第 14 篇(共 18 篇)。→ 系列目录

篇目 核心内容
第 13 篇 · Column Family 共享 WAL、独立 LSM
第 14 篇 · 事务与 OCC OptimisticTransactionDB、WritePrepared 边界
第 15 篇 · Checkpoint 与 Ingest 硬链接快照
第 16 篇 · 生产嵌入对照 Flink / TiKV key 编码

版本锚定:RocksDB 9.xutilities/transactions/include/rocksdb/utilities/transaction_db.h)。TiKV 事务章节为 B 级前瞻(PingCAP 设计文档与博客),不声称覆盖 Percolator 实现细节;后续 HTAP 系列可修订本节。


一、WriteBatch 原子性 vs 事务语义

能力 WriteBatch [Optimistic]TransactionDB
多 key 原子提交 是(commit 时写入 batch)
提交前对其他读者可见
并发冲突检测 是(悲观锁或乐观校验)
Read-your-own-writes WriteBatchWithIndex 内建(Transaction::Get
2PC Prepare TransactionDB + WritePrepared

Wiki Transactions(A 级):Transactions provide a way to guarantee that a batch of writes will only be written if there are no conflicts.

Flink RocksDB state 默认 不用 RocksDB 事务 API——一致性靠 checkpoint barrier 与算子单线程 per key 语义(stream/14 交付语义)。理解 RocksDB 事务仍有助于读 TiKV 存储层与 MyRocks 等 真 2PC 嵌入。


二、TransactionDB:悲观锁与 WriteCommitted

TransactionDB::Open 创建带锁表的 DB。Wiki 要点(A 级):

TransactionDB* txn_db;
TransactionDBOptions txndb_opts;
Status s = TransactionDB::Open(options, txndb_opts, path, &txn_db);

Transaction* txn = txn_db->BeginTransaction(write_options);
s = txn->Put("key", "value");
s = txn->Commit();
delete txn;

适用:写冲突频繁、需要 GetForUpdate 建立读-写冲突、或 2PC Prepare/Commit 的数据库引擎(如 MySQL on RocksDB)。代价:锁 striping 开销(Wiki Under the hoodPointLockManager 每 CF 16 条 stripe)。


三、OptimisticTransactionDB:提交时 OCC

乐观事务 Prepare 阶段不加锁Commit 时通过 CheckCallback 校验自首次写入以来是否有其他写者修改相同 key(Wiki OptimisticTransactionDB,A 级)。

OptimisticTransactionDB* txn_db;
OptimisticTransactionDB::Open(options, path, &txn_db);
DB* db = txn_db->GetBaseDB();

OptimisticTransaction* txn = txn_db->BeginTransaction(write_options);
txn->Put("key", "value");
Status s = txn->Commit();  // 冲突则 Non-OK,无 key 落盘
对比 TransactionDB OptimisticTransactionDB
写前加锁 无锁,commit 时检测
非事务写 也走锁 与事务写并发,commit 可能失败
典型 workload 高冲突 OLTP 低冲突、非事务写多
内存 锁表 复用 memtable 历史做冲突检测

Wiki 建议:若 大量事务争抢同一 key,改用 TransactionDB;若 非事务写远多于事务,乐观路径可能更省锁开销。

冲突检测数据源TransactionUtil::CheckKeysForConflicts 对比 key 的 latest sequence 与事务开始写入时记录的 sequence;依赖 memtable 中 足够的历史 buffer——max_write_buffer_size_to_maintain 过小会导致 误报冲突(Commit 失败)(Wiki Tuning / Memory Usage)。


四、读语义:GetForUpdateSetSnapshot、Snapshot

Read-your-own-writes

事务内 Get / MultiGet 先见 本事务未提交写,再查 DB(Wiki 示例,A 级)。

读-写冲突

GetForUpdate 把读过的 key 设为 commit 前提;普通 Get 阻止其他线程改同一 key 后仍 commit 成功。

SetSnapshot()

默认:冲突检测以 key 在本事务内首次写入时刻 为界。调用 SetSnapshot() 后,改为 事务开始快照 为界——快照之后的外部写入会导致 commit 失败(即使外部写发生在本事务写同一 key 之前)。

ReadOptions::snapshot

第 7 篇 相同:指定 读哪个 sequence 截面 单独决定 commit 能否成功。


五、WritePrepared:缩短 2PC Commit 路径

WriteCommitted 把 MemTable 写入压在 Commit 阶段,2PC 串行 commit 时延迟明显。Wiki WritePrepared Transactions(A 级)引入更早落盘:

WritePolicy MemTable 写入时机 读路径额外负担
WriteCommitted Commit 低:MemTable 可见即已提交
WritePrepared Prepare 需判断 prepare_seq 是否已 commit
WriteUnprepared Put 阶段(更激进) 更高

WritePrepared 概要(A 级,Wiki):

  1. Prepare:batch 写 WAL + MemTable,整批共用 prepare_seq(复用 sequence number)。
  2. Commit:WAL 写 commit markercommit_seq 为提交时间戳;CommitCache 记录 prepare_seq → commit_seq
  3. 读路径:IsInSnapshot(prepare_seq, snapshot_seq) 查 CommitCache / delayed_prepared_ / old_commit_map_ 判断可见性。
  4. Abort:对每 key 写 rollback 记录 抵消 prepared 数据(悲观锁保证每 key 仅一个 pending write)。

双写队列two_write_queues=true 时,主队列写 Prepare(WAL+MemTable),次队列写 Commit marker;第 4 篇 提到的 nonmem_write_thread_ 与此相关。Snapshot 取 last published sequence,而非两队列中较大的 raw sequence。

边界(本篇不展开实现)


六、与 Snapshot / MVCC 的关系

第 7 篇Snapshot = sequence 上界 仍是非事务读的基础。事务层在其上叠加:

flowchart TB
  subgraph ReadPath["读路径"]
    SN["ReadOptions::snapshot"]
    WP["WritePrepared IsInSnapshot"]
    GET["DBImpl::GetImpl + GetContext"]
  end
  SN --> GET
  WP --> GET
  subgraph WritePath["写路径"]
    WC["WriteCommitted: commit 才进 mem"]
    WPr["WritePrepared: prepare 进 mem"]
  end

snapshot_impl.hmin_uncommitted_(WritePrepared 用)参与 未提交 prepared 数据 的裁剪(第 7 篇 已标注字段)。Compaction 不能删除 仍被 Snapshot 或 prepared 事务引用 的旧版本——与 GetSnapshot 阻止版本回收的逻辑同族。


七、TiKV 与 Percolator:层级对照(A 级文献 + B 级映射)

证据分层:Percolator 协议本身有 A 级论文;TiKV 「如何落盘」对照来自公开文档(B 级),不是 TiKV 源码 walkthrough。Raft、PD、Coprocessor 全文不在本系列。

7.1 Percolator:分布式 2PC 的奠基

Peng & Dabek, Large-scale Incremental Processing Using Distributed Transactions and NotificationsOSDI 2010,俗称 Percolator)给出 Google 网页索引增量系统的核心事务模型:

概念 Percolator RocksDB TransactionDB 同名物
锁 / 预写 锁列 + primary / secondary lock GetForUpdate / 点锁(单机)
Prepare 写 lock + data(未 commit) WritePrepared:数据先入 MemTable
Commit 写 commit-ts / 清锁 CommitCache + 提交队列
时间戳 全局 TSO 式 commit_ts 序列号 sequence(单机)
复制 Bigtable 行复制 (需外加 Raft)

关键差一层:Percolator 解决 跨机多分片 的原子提交;RocksDB 事务解决 单进程 LSM 上的冲突检测与可见性。名称上的 Prepare/Commit 不能 互换。

7.2 TiKV 三层叠加

层次 机制 与本文 RocksDB 事务
Region 副本 Raft log + apply Raft 提供复制与共识,不是 RocksDB 事务
分布式 txn Percolator 风格 2PC、锁列、commit TS(TiKV 文档;B 级落地) 语义同族,锁与 TS 编码在 key 空间
本地引擎 RocksDB CF、MVCC 时间戳 内部 key 含 TS;可见性由 TS + snapshot 决定,而非应用直接调 BeginTransaction
flowchart TB
  APP["应用 / TiDB"] --> PERC["Percolator 2PC + TSO"]
  PERC --> RAFT["Raft Region"]
  RAFT --> ROCK["RocksDB Put/Get<br/>CF + seq/TS 编码"]
  APP2["单机 MyRocks / 自研"] --> TXN["TransactionDB / OCC"]
  TXN --> ROCK2["同一套 DBImpl 写路径"]

7.3 工程关联与开放问题


八、选型简表

场景 建议
仅需批写原子 WriteBatch
低冲突读-改-写 OptimisticTransactionDB
高冲突或 GetForUpdate TransactionDB
MyRocks / 2PC 引擎 TransactionDB + WritePrepared / WriteUnprepared
Flink state checkpoint 一致性, RocksDB 事务
TiKV Percolator(OSDI 2010)+ Raft(见 §七)

九、小结

下一篇进入 Checkpoint / Backup / External Ingest——Flink 增量 checkpoint 与 bulk load 的运维接口。


上一篇Column Family

下一篇Checkpoint 与 External Ingest

返回 系列目录


参考资料

  1. RocksDB Wiki, Transactions(TransactionDB、OptimisticTransactionDB、GetForUpdate、SetSnapshot、Under the hood;A 级)。
  2. RocksDB Wiki, WritePrepared Transactions(WriteCommitted/Prepared/Unprepared、CommitCache、IsInSnapshot、two_write_queues;A 级)。
  3. Peng, Daniel & Dabek, Frank, Large-scale Incremental Processing Using Distributed Transactions and Notifications(Percolator),OSDI 2010(分布式 2PC 奠基;A 级)。
  4. RocksDB 9.x 源码:utilities/transactions/transaction_db_impl.*optimistic_transaction.*write_prepared_txn.*);include/rocksdb/utilities/transaction_db.h(A 级)。
  5. RocksDB 9.x 源码:db/db_impl/db_impl_write.ccCheckCallbacktwo_write_queues_);db/snapshot_impl.hmin_uncommitted_)(A 级)。
  6. 第 4 篇 WAL第 7 篇 Snapshot第 1 篇 TiKV 生态位
  7. PingCAP TiKV 文档, Distributed Transaction(落地映射;B 级,不能单独支撑协议正确性)。
  8. db-frontier/12 HTAP(分布式事务开放问题入口)。

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .