存储引擎 Benchmark 实战RocksDB 与 WiredTiger 在混合负载下的性能对比一、Benchmark 不是跑一遍 sysbench 就交差每当需要在 RocksDB 和 WiredTiger 之间做选型时最常见的做法是用 sysbench 跑一套标准的读写混合负载然后比较 TPS 和延迟。这个做法没错但它测的是这两种引擎在理想条件下的表现而不是在你的业务负载下的表现。问题出在两个方面。第一sysbench 的默认负载是均匀分布的主键读写而真实业务的访问模式往往有明显的冷热分层——80% 的请求集中在 20% 的热数据上。第二Benchmark 通常只跑 10 分钟或 30 分钟这不足以激发 LSM-TreeRocksDB的 Compaction 或 B-TreeWiredTiger的 Page Split——而这两种后台操作恰恰是决定稳态性能的关键。一次有说服力的 Benchmark必须回答三个问题在什么样的数据量级、什么样的访问分布、运行多长时间后引擎的表现如何。flowchart TD A[Benchmark 设计] -- B[定义负载模型] B -- C[点查/范围扫描占比] B -- D[读写比例] B -- E[冷热数据分布] B -- F[数据量级] C -- G[执行 Benchmark] D -- G E -- G F -- G G -- H[预热阶段: 30 分钟] H -- I[稳态测试: 2 小时] I -- J[采集指标] J -- K[吞吐: OPS] J -- L[延迟: P50/P95/P99] J -- M[后台活动: Compaction/Page Split 频率] J -- N[资源: CPU/IO/内存] K -- O[分析报告] L -- O M -- O N -- O二、测试环境与负载模型的定义测试硬件统一为 16 核 CPU、64GB 内存、NVMe SSD1TB操作系统为 CentOS 7.9文件系统为 XFS。数据量级分两档小数据集10GB数据全在内存和大数据集200GB远超内存容量。这是有意为之——在小数据集上两种引擎都在内存中运行测的是纯 CPU 效率在大数据集上I/O 成为瓶颈测的是引擎对磁盘的利用策略。负载模型的设计比硬件更重要。定义三种负载负载 A读写均衡50% 点查 30% 范围扫描每次扫描 100 行 20% 插入Zipfian 分布α1.2模拟热数据集中。负载 B写密集70% 插入 20% 更新 10% 点查均匀分布。负载 C读密集90% 点查 10% 范围扫描Zipfian 分布。# 基于 YCSB 的负载生成配置Python 驱动 test_configs { workload_a: { # 读写均衡 read_proportion: 0.5, scan_proportion: 0.3, insert_proportion: 0.2, request_distribution: zipfian, zipfian_constant: 1.2, scan_length: 100, }, workload_b: { # 写密集 read_proportion: 0.1, update_proportion: 0.2, insert_proportion: 0.7, request_distribution: uniform, }, workload_c: { # 读密集 read_proportion: 0.9, scan_proportion: 0.1, request_distribution: zipfian, zipfian_constant: 1.2, } }三、核心对比结果与数据解读小数据集10GB下的表现指标RocksDBWiredTiger负载 A - 吞吐 (ops/s)82,30091,500负载 A - P99 延迟 (μs)4,2002,800负载 B - 吞吐 (ops/s)115,00078,000负载 B - P99 延迟 (μs)3,1008,500负载 C - 吞吐 (ops/s)95,000135,000负载 C - P99 延迟 (μs)1,800950在小数据集上WiredTiger 的读性能显著优于 RocksDB。原因在于 B-Tree 的 O(log_B N) 查找 内存缓存在 N 不大时效率极高。而 RocksDB 的 LSM-Tree 读路径需要逐层查找——先查 MemTable然后 L0 → L1 → L2……直到找到目标。在小数据量下LSM-Tree 的写放大换来的 Compaction 优化没有用武之地反而在读取上做了额外的查找工作。但写密集负载负载 B是另一番景象——RocksDB 的 LSM-Tree 将随机写转为顺序写Write-Ahead Log MemTable flush吞吐比 WiredTiger 高出近 50%。WiredTiger 的 B-Tree 在写密集场景下频繁触发 Page Split加上 WAL 的同步写入写性能显著下降。大数据集200GB下的表现指标RocksDBWiredTiger负载 A - 吞吐 (ops/s)36,00012,800负载 A - P99 延迟 (ms)12.548.2负载 C - 吞吐 (ops/s)42,0008,500负载 C - P99 延迟 (ms)8.7112.3大数据集彻底翻转了战局。WiredTiger 的 B-Tree 页缓存Page Cache在 64GB 内存 vs 200GB 数据的条件下严重不足大部分读取需要回磁盘。而 RocksDB 的 Block Cache 布隆过滤器 分层压缩使得热数据被有效地保留在较高层级磁盘 I/O 的次数远少于 WiredTiger。此外ZSTD 压缩对 RocksDB Block 的压缩率好于 WiredTiger 的 Snappy 默认压缩。flowchart LR subgraph WiredTiger_BTree W1[内存: Page Cache] --|缓存未命中| W2[磁盘: B-Tree 页] W2 --|Page Split| W3[磁盘: 新页分配] W3 -- W2 end subgraph RocksDB_LSM R1[内存: MemTable] --|flush| R2[磁盘: L0 SST] R1 --|读| R3[内存: Block Cache] R2 --|Compaction| R4[磁盘: L1~L6 SST] R4 --|读| R3 R3 --|布隆过滤| R5[快速判断 Key 不存在] end四、选型决策树与工程建议Benchmark 结果指向一个清晰的选型决策框架选 WiredTiger数据量可控50GB、读密集负载、需要 ACID 事务、已有 MongoDB 或单机 MySQL 技术栈。典型场景用户画像存储、配置管理、小型 OLTP。选 RocksDB数据量超过内存容量100GB、写密集或混合负载、对延迟敏感、需要高压缩率。典型场景时序数据库底层存储、消息队列的 Offset 存储、日志搜索引擎的倒排索引。两者同时使用利用不同引擎的特性做分层存储。热数据层用 WiredTiger 提供低延迟读写冷数据层用 RocksDB 提供高压缩和低成本存储。应用层通过时间或访问频率策略做数据在两层之间的自动迁移。选型之后还有三个工程注意事项第一无论选哪个引擎都必须在生产环境的真实硬件上跑至少 24 小时的稳态测试——Compaction 和 Page Split 的副作用通常在 4 小时之后才会显现第二监控 Compaction 的 Write StallRocksDB或 Eviction 压力WiredTiger这是存储引擎向你发出的我快扛不住了的信号第三不要把 Benchmark 的数字当做 SLA 承诺——Benchmark 是在无干扰环境中跑出来的生产环境还有网络抖动、并发竞争和操作系统调度延迟。五、总结RocksDB 和 WiredTiger 没有绝对的优劣只有场景的适合与否。Benchmark 的目标不是选出一个赢家而是搞清楚每种引擎的舒适区和禁区。在 200GB 数据量、混合负载的场景下RocksDB 的 LSM-Tree 架构在写入吞吐和磁盘效率上的优势是结构性的——这不是调参数能弥补的差距。在小数据量、读密集的场景下WiredTiger 的 B-Tree 简洁高效。做选型时最不应该犯的错误是拿小数据集的 Benchmark 去预测大数据集的表现——两种引擎的相变点可能就在某个数据量级上悄然发生。