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

【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 前瞻(B 级,草稿边界)

证据等级说明:以下对照来自 PingCAP TiKV 公开设计文档与 RocksDB 事务 Wiki 的 概念对齐不是 TiKV 源码 walkthrough。Percolator 两阶段提交、Raft 复制、Coprocessor 不在本系列 18 篇范围内。

TiKV 在 单个 Region 内使用 RocksDB(或兼容实现)作本地 KV 引擎(第 1 篇 LSM 生态)。分布式事务在 Raft 之上 跑 Percolator 模型,与单机 TransactionDB 的关系可粗分为:

层次 机制 与本文 RocksDB 事务
Region 副本 Raft log + apply Raft 提供复制与共识,不是 RocksDB 事务
分布式 txn Percolator 2PC、锁列、commit TS 语义类似 2PC,锁与 TS 编码在 key 空间
本地引擎 RocksDB CF、MVCC 时间戳 内部 key 含 TS;可见性由 TS + snapshot 决定,而非应用直接调 BeginTransaction

工程关联点(B 级,供第 16/18 篇展开)

本节随 TiKV 版本与 HTAP 续作 可能修订;读者应以 TiKV 官方 Transaction 文档为准。


八、选型简表

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

九、小结

下一篇进入 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. RocksDB 9.x 源码:utilities/transactions/transaction_db_impl.*optimistic_transaction.*write_prepared_txn.*);include/rocksdb/utilities/transaction_db.h(A 级)。
  4. RocksDB 9.x 源码:db/db_impl/db_impl_write.ccCheckCallbacktwo_write_queues_);db/snapshot_impl.hmin_uncommitted_)(A 级)。
  5. 第 4 篇 WAL第 7 篇 Snapshot第 1 篇 TiKV 生态位(A 级边界)。
  6. PingCAP TiKV 文档, Distributed Transaction(Percolator 模型;B 级前瞻,非本篇结论唯一依据)。

同主题继续阅读

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

2026-07-07 · database / storage

【RocksDB 内核机制】选型与存储栈阅读地图

用决策树收束 RocksDB 与 InnoDB、列存、湖仓的适用边界;给出存储引擎三角 + 数据平台全栈阅读地图,对接 query-engine/18 与 postgresql-kernel,并标注 HTAP/TiKV 续作入口。


By .