技术深度解析
Keybench的核心创新在于其架构设计,该架构旨在将工作负载定义与引擎执行解耦。其核心是一个基于YAML的配置系统,允许用户定义复杂的多阶段测试场景。一个典型的测试可能从批量加载阶段开始,过渡到具有指定Zipfian分布的混合读写阶段,最后以只读延迟扫描结束。每个阶段都可以指定操作数量、键大小分布、值大小分布和并发级别。这与仅支持固定命令集和均匀随机访问模式的`redis-benchmark`等工具有着显著区别。
可扩展性通过插件架构实现。Keybench定义了一个最小的C API,任何键值存储都可以实现。该项目已附带用于Redis(通过hiredis)、RocksDB(通过C++ API)、LevelDB、LMDB和SQLite(作为基线)的插件。社区可以通过实现少量回调函数来添加新引擎:`open`、`close`、`get`、`put`、`delete`和`batch_write`。这种设计借鉴了Google的Fio用于存储基准测试的方法,但针对键值语义进行了定制。
技术上最有趣的方面之一是Keybench如何处理写放大的测量。在基于LSM树的引擎(如RocksDB和LevelDB)中,写放大是一个关键的性能和耐久性因素。Keybench检测引擎的内部统计信息(例如RocksDB的`rocksdb.db.write-amplification`属性),并将其与用户可见的写入吞吐量相关联。这使得开发人员能够看到,例如,RocksDB上10,000 ops/sec的写入工作负载可能实际上对存储设备产生50,000次物理写入,从而揭示了压缩的真实成本。
基准测试数据:混合工作负载下的第90百分位延迟(p99)
| 引擎 | 读取延迟(p99, μs) | 写入延迟(p99, μs) | 内存使用(MB) | 写放大因子 |
|---|---|---|---|---|
| Redis(内存型) | 45 | 52 | 1,024 | 1.0 |
| RocksDB(LSM,默认) | 210 | 380 | 512 | 4.2 |
| LevelDB(LSM) | 340 | 520 | 480 | 6.1 |
| LMDB(B+树,mmap) | 98 | 150 | 1,100 | 1.1 |
*数据要点:* 该表揭示了经典的权衡:像Redis这样的内存存储提供最低的延迟,但内存成本最高;而像RocksDB这样基于LSM的引擎则牺牲延迟以换取内存效率和持久性。Keybench揭示写放大(RocksDB为4.2倍)的能力对于SSD耐久性规划至关重要。
另一个技术亮点是Keybench对可配置持久性保证的支持。开发人员可以指定每次写入是同步的(每次操作后fsync)、异步的(缓冲)还是批量的。这一点至关重要,因为这些模式之间的性能差异可能高达一个数量级。例如,使用`appendfsync always`的Redis吞吐量可能降至其异步吞吐量的10%。Keybench使这种权衡变得明确,允许工程师根据其一致性要求做出明智的决策。
关键参与者与案例研究
键值存储生态系统由几个主要参与者主导,每个都有独特的设计理念。Redis Labs(现为Redis Ltd.)长期以来一直将其产品定位为缓存和实时数据的事实标准。其优势在于简单性和低延迟,但缺乏基于磁盘引擎的持久性和存储效率。RocksDB最初由Facebook(Meta)的工程师Dhruba Borthakur和Igor Canadi开发,是许多大规模系统(包括Apache Flink、TiKV和CockroachDB)的支柱。其LSM树架构擅长处理写入密集型工作负载,但存在读取放大和压缩开销的问题。LMDB由Symas创建,使用带有内存映射文件的B+树,提供出色的读取性能和低写放大,但其单写入器事务模型限制了并发性。
Keybench的设计对于构建AI基础设施的公司尤其相关。例如,像Tecton和Feast这样的特征存储依赖键值存储来实现预计算特征的低延迟检索。模型缓存(例如NVIDIA的Triton Inference Server使用的缓存)需要亚毫秒级的查找时间。Keybench允许这些团队运行针对其特定访问模式的目标基准测试——例如,90%读取、10%写入,键值大小比为1:10。
对比表:键值存储性能特征
| 特性 | Redis | RocksDB | LMDB |
|---|---|---|---|
| 存储模型 | 内存型 + 可选持久化 | 磁盘上的LSM树 | 带mmap的B+树 |
| 写放大 | 1.0(无压缩) | 2-10倍(压缩) | 1.0-1.5倍(页分裂) |
| 并发模型 | 单线程事件循环 | 多线程压缩 | 单写入器,多读取器 |
| 典型用例 | 缓存、会话存储 | 嵌入式数据库、流处理 | 读取密集型、嵌入式