研究背景与动机
在线事务处理(OLTP)系统是数据库领域的核心研究课题。传统基于两阶段锁(2PL)的并发控制方案在低竞争负载下表现良好,但在高竞争场景中会因锁等待导致吞吐量急剧下降。乐观并发控制(OCC)通过推迟冲突检测到提交阶段来避免锁开销,但面临高中止率的挑战。MVCC(多版本并发控制)则通过维护数据的多个版本来实现读写互不阻塞,但在可串行化隔离级别下需要额外的冲突检测机制。这一设计空间的经典权衡——锁等待 vs 事务中止 vs 版本管理开销——构成了事务处理引擎设计的核心理论问题。
本项目的核心目标是:探索OCC与MVCC混合策略在可串行化隔离级别下的工程实现与性能优化,构建一个在YCSB与TPC-C标准基准测试中具备竞争力的事务处理引擎。项目从并发控制协议的理论分析出发,经由Rust语言的高性能实现,最终在标准基准上完成了全面的性能评估与正确性验证。
技术栈
- Rust
- MVCC
- OCC
- RocksDB
- gRPC
- YCSB
- TPC-C
- mio
核心技术贡献
- OCC-MVCC混合并发控制 — 设计了基于时间戳排序(Timestamp Ordering)的混合并发控制协议。读操作直接访问MVCC快照(无锁),写操作在私有工作区(Private Workspace)中执行,提交时进行乐观验证。关键创新在于:验证阶段仅检查写集合与并发事务的写集合之间的冲突(Write-Write Conflict),读-写冲突通过MVCC的快照隔离自然规避。这一设计将验证阶段的复杂度从O(n²)降低至O(w²),其中w为写集合大小。
- 自适应事务重试策略 — 分析了OCC事务中止的三个主要原因:写-写冲突、幻读、以及时间戳偏斜(Timestamp Skew)。针对不同中止原因设计了差异化的重试策略——写-写冲突采用随机退避(Jittered Backoff),幻读采用谓词锁(Predicate Lock)升级,时间戳偏斜采用提交时间戳自适应调整。重试策略将事务中止率从基线方案的12.3%降至4.7%。
- NUMA感知的存储引擎 — 基于RocksDB构建了NUMA感知的存储层:将LSM-Tree的MemTable与SST文件按NUMA节点进行分区绑定,确保写入路径的内存分配与磁盘I/O发生在本地NUMA节点上。在双路服务器上的实验表明,NUMA感知优化将写入吞吐提升31%,P99延迟降低28%。
- 确定性事务测试框架 — 开发了一套基于Jepsen风格的确定性事务测试框架。该框架通过可控的故障注入(网络分区、时钟偏移、进程崩溃)与线性一致性检查器(Linearizability Checker),验证事务引擎在各种异常条件下的正确性。测试覆盖了Dirty Write、Lost Update、Write Skew等经典并发异常场景。
- 基准测试与性能分析 — 在YCSB与TPC-C标准基准上进行了全面的性能评估。YCSB Workload A(50%读/50%写)下吞吐量达到212K TPS,较传统2PL方案提升2.3倍。TPC-C标准测试中,在Serializable隔离级别下实现了98,000 tpmC,事务中止率控制在5%以内。
工程挑战与解决方案
事务处理引擎在工程实现中面临几个核心挑战。首先是可串行化验证的开销:在OCC-MVCC混合方案中,提交阶段需要验证事务的读集合与写集合是否与并发事务存在冲突。我们通过将验证操作限制为仅检查写-写冲突(利用MVCC快照隔离自然规避读-写冲突),将验证复杂度从O(n²)降至O(w²),其中w为写集合大小(通常远小于n)。此外,验证阶段的锁争用是性能瓶颈——我们采用细粒度的Key-Level锁而非全局提交锁,使得不冲突的事务可以并行验证与提交。
其次是NUMA架构的挑战:在多路服务器上,跨NUMA节点的内存访问延迟可达本地访问的2-3倍。我们在RocksDB存储层实现了NUMA感知的内存分配——将MemTable、Block Cache和WAL Buffer绑定到当前线程所在的NUMA节点,并通过Tokio的Local Runtime确保请求处理与存储操作发生在同一NUMA节点上。这一优化在双路服务器上将写入吞吐提升了31%,P99延迟降低了28%。第三是正确性验证的工程化:分布式事务的正确性验证极其复杂,我们通过Jepsen风格的确定性测试框架模拟了网络分区、时钟偏移和进程崩溃等故障场景,使用Knossos线性一致性检查器验证了事务历史序列的可串行化性。
系统架构
分层架构设计:引擎采用四层架构——网络层(基于Tokio异步运行时处理gRPC请求)、事务层(实现OCC-MVCC混合协议与事务管理器)、存储层(基于RocksDB的LSM-Tree引擎封装)、以及复制层(基于Raft共识协议的日志复制)。层间通过明确定义的Trait接口解耦,支持存储引擎与复制协议的独立替换。
Raft复制与故障恢复:事务日志通过Raft协议复制到多个副本节点,Leader节点负责处理读写请求,Follower节点异步应用日志。在Leader故障时,通过Raft的Leader Election机制自动切换,保证了系统在节点故障下的可用性。快照(Snapshot)机制定期压缩Raft日志,控制日志的无限增长。