AWS 32コア物理環境における vmemkv と RocksDB の性能比較ベンチマーク。

Stacking Variants

各最適化の詳細は Design Document を参照。

  • RocksDB: LSM-Tree のベースライン比較
  • LMDB: B+Tree / mmap ベースの比較対象
  • RocksDB-BlobDB: RocksDB の Blob 分離ストレージ変種(大きな Value 向け)
  • Baseline: vmemkv 最適化なし
  • +BF: + T1 Bloom Filter
  • +Simd: +BF + SIMD Scan(T1 sorted_region の SIMD 線形探索)
  • +Inline: +Simd + T1 Inline Value (<8B のValueをT1のみで処理)
  • +Prefault: +Inline + T2 Async Prefaulting(全部盛り)

Environment

  • Instance: AWS i4i.8xlarge (ap-northeast-1)
  • CPU: Intel Xeon Platinum 8375C @ 2.90GHz (32 cores)
  • L2 Cache: 1,280 KiB × 16 (per-core private)
  • RAM: 66.3 GB
  • RAM (Larger-Than-Memory): cgroup で DRAM を 1GiB に制限し予めデータ量を4GiBぶん挿入した状態で開始
  • Disk: Local NVMe SSD (Swap Media for LTM)
  • Kernel: 6.17.0-1019-aws
  • Git Rev: a4d892aa58d8 (dirty)

Workloads

  • Insert: 順次挿入(1/4/16/32 スレッド)
  • Get Hit/Miss (Zipf/Uniform): ポイントルックアップ
  • Update / Delete: Zipf 分布での更新・削除
  • Scan After Reorg (Zipf/Uniform): T1 reorganize 後(sorted_region のみ)のレンジスキャン。VMemKV 内部専用
  • Scan After Full Reorg T1+T2 (Zipf/Uniform): T1+T2 完全 reorganize 後のレンジスキャン。全エンジン比較可能
  • YCSB-E: 95% Scan + 5% Insert 混合(32スレッド / 30秒タイムライン)

Overall Notes & Annotations

Workload Winners & Relative Speedup

Best VMemKV variant vs. whichever rival (RocksDB, LMDB, RocksDB-BlobDB) is FASTEST at that cell, at 32 threads (max concurrency tested) -- not the best-of-any-thread-count-or-rival figure, since both axes are known to shrink (sometimes invert) the ratio if picked favorably. The rival actually being compared against is named in small text under each badge.

Workload 8B In-Memory 1KB In-Memory 1KB LTM 64KB LTM
Insert
✅ WIN (1.50x) vmemkv (+BF) vs RocksDB
✅ WIN (1.63x) vmemkv (+Prefault) vs RocksDB-BlobDB
✅ WIN (1.52x) vmemkv (+Inline) vs RocksDB
✅ WIN (3.02x) vmemkv (Baseline) vs RocksDB-BlobDB
Update (Zipf)
✅ WIN (1.47x) vmemkv (+Inline) vs RocksDB
✅ WIN (1.58x) vmemkv (+Prefault) vs RocksDB-BlobDB
✅ WIN (2.07x) vmemkv (NoMadvise) vs RocksDB-BlobDB
✅ WIN (3.03x) vmemkv (+BF) vs LMDB
Delete
✅ WIN (1.57x) vmemkv (NoMadvise) vs RocksDB-BlobDB
✅ WIN (1.63x) vmemkv (+BF) vs RocksDB
✅ WIN (1.76x) vmemkv (Baseline) vs RocksDB-BlobDB
✅ WIN (3.73x) vmemkv (+Simd) vs RocksDB-BlobDB
Get (Miss)
✅ WIN (2.74x) vmemkv (+Inline) vs RocksDB-BlobDB
✅ WIN (2.99x) vmemkv (+Inline) vs RocksDB
✅ WIN (2.79x) vmemkv (+Simd) vs RocksDB
✅ WIN (2.48x) vmemkv (+Inline) vs LMDB
Get (Hit, Zipf)
✅ WIN (1.36x) vmemkv (+Prefault) vs LMDB
✅ WIN (1.16x) vmemkv (NoMadvise) vs LMDB
❌ LOSE (0.63x) vmemkv (+Inline) vs RocksDB-BlobDB
❌ LOSE (0.29x) vmemkv (+Inline) vs RocksDB-BlobDB
Get (Hit, Uniform)
WIN (1.07x) vmemkv (+Inline) vs LMDB
WIN (1.13x) vmemkv (+Prefault) vs LMDB
❌ LOSE (0.83x) vmemkv (+Inline) vs RocksDB-BlobDB
❌ LOSE (0.24x) vmemkv (+Inline) vs RocksDB-BlobDB
Scan (T1 Reorg) Zipf
❌ LOSE (0.64x) vmemkv (+Inline) vs LMDB
≈ EVEN (0.97x) vmemkv (+Inline) vs LMDB
❌ LOSE (0.07x) vmemkv (+Inline) vs RocksDB
❌ LOSE (0.21x) vmemkv (+Inline) vs LMDB
Scan (T1 Reorg) Uniform
❌ LOSE (0.65x) vmemkv (+Prefault) vs LMDB
≈ EVEN (0.97x) vmemkv (+Prefault) vs LMDB
❌ LOSE (0.10x) vmemkv (+Inline) vs RocksDB
❌ LOSE (0.23x) vmemkv (+Inline) vs RocksDB-BlobDB
Scan (T1+T2 Reorg) Zipf
❌ LOSE (0.64x) vmemkv (+Inline) vs LMDB
LOSE (0.89x) vmemkv (+Inline) vs LMDB
❌ LOSE (0.39x) vmemkv (+Prefault) vs RocksDB
❌ LOSE (0.23x) vmemkv (+Simd) vs LMDB
Scan (T1+T2 Reorg) Uniform
❌ LOSE (0.65x) vmemkv (+Inline) vs LMDB
WIN (1.09x) vmemkv (Baseline) vs LMDB
❌ LOSE (0.47x) vmemkv (+Inline) vs RocksDB
❌ LOSE (0.24x) vmemkv (NoMadvise) vs RocksDB-BlobDB
YCSB-E (Timeline Workload)
✅ WIN (2.88x) vmemkv (+Prefault) vs RocksDB-BlobDB
✅ WIN (1.54x) vmemkv (+BF) vs RocksDB
❌ LOSE (0.37x) vmemkv (Baseline) vs RocksDB
❌ LOSE (0.21x) vmemkv (+BF) vs LMDB

Tier 1 Reorganize (T1only)

Average and worst-case (at 100% capacity) times to reorganize active buffer.

Scenario 8B 1KB 64KB
In-MemoryAvg: 1.51s
Max: 2.91s
Avg: 0.70s
Max: 0.83s
-
LTM-Avg: 1.19s
Max: 1.34s
Avg: 0.11s
Max: 0.18s

Tier 1 + Tier 2 Reorganize (T1+T2)

Average and worst-case times to merge Tier 1 buffer and rewrite Tier 2 flat files.

Scenario 8B 1KB 64KB
In-MemoryAvg: 20.41s
Max: 33.52s
Avg: 12.93s
Max: 20.74s
-
LTM-Timeout (>60s)Avg: 28.36s
Max: 38.39s*
*(ratios >= 0.75 timed out)

Insert Workload

実験概要: ユニークキーを空のストアに順次挿入する際の書き込みスループット。Scan 非アクティブ時は Soft Limit = APPEND_CAP の 50% で動作。

Update (Zipf) Workload

実験概要: Zipf 分布での既存キーに対する更新スループット(ステートフルな上書き)。

Delete (Zipf) Workload

実験概要: T1 Tombstone 付与による並行削除スループット。

Get Miss (Zipf) Workload

実験概要: 存在しないキーへの読み取り。Bloom Filter の偽陽性回避効果を評価。

Get Hit (Zipf) Workload

実験概要: Zipf 分布での既存キーへのポイントルックアップ(キャッシュフレンドリー)。

Get Hit (Uniform) Workload

実験概要: Uniform 分布での既存キーへのポイントルックアップ(極端なキャッシュミス)。

Scan After Reorg (Zipf)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Zipf 分布 100 件レンジスキャンの上限値。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし(T1+T2 完全 reorg 後の全エンジン比較は下記「Scan After Full Reorg (T1+T2)」参照)。

Scan After Reorg (Uniform)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Uniform 分布 100 件レンジスキャン。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし。

Scan After Full Reorg (T1+T2) (Zipf)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Zipf 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

Scan After Full Reorg (T1+T2) (Uniform)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Uniform 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)

YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 Workload-Adaptive Soft Limit により、スキャン検出時に append_region を L2キャッシュ容量(~26,000件 / 1MB ÷ 40B)以下に保つ。Reorg 直後に走査対象が sorted_region のみになりスキャン QPS が V字回復する。
藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize(LTMなど、30秒のタイムウィンドウ内で自然発生が保証されないシナリオ用の強制トリガー。自然発生と混同しないよう区別して表示)。

Scan QPS タイムライン

32 threads / 30 seconds

Reorganize Duration vs. Corpus Size (T1-only vs T1+T2)

単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。 populate自体は計測対象外(reorganize()本体のみ内部60秒でタイムアウト、外側の実行スクリプトはさらに緩い300秒のバックストップ)。 藍色 = T1-only(force_t2_gc=false)、 赤色 = T1+T2(force_t2_gc=true)。 ▲マーカーはタイムアウト(60秒到達、実際の所要時間はそれ以上)を示す。

Reorganize Duration

single-shot, threads:1

Insert Workload

実験概要: ユニークキーを空のストアに順次挿入する際の書き込みスループット。Scan 非アクティブ時は Soft Limit = APPEND_CAP の 50% で動作。

Update (Zipf) Workload

実験概要: Zipf 分布での既存キーに対する更新スループット(ステートフルな上書き)。

Delete (Zipf) Workload

実験概要: T1 Tombstone 付与による並行削除スループット。

Get Miss (Zipf) Workload

実験概要: 存在しないキーへの読み取り。Bloom Filter の偽陽性回避効果を評価。

Get Hit (Zipf) Workload

実験概要: Zipf 分布での既存キーへのポイントルックアップ(キャッシュフレンドリー)。

Get Hit (Uniform) Workload

実験概要: Uniform 分布での既存キーへのポイントルックアップ(極端なキャッシュミス)。

Scan After Reorg (Zipf)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Zipf 分布 100 件レンジスキャンの上限値。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし(T1+T2 完全 reorg 後の全エンジン比較は下記「Scan After Full Reorg (T1+T2)」参照)。

Scan After Reorg (Uniform)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Uniform 分布 100 件レンジスキャン。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし。

Scan After Full Reorg (T1+T2) (Zipf)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Zipf 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

Scan After Full Reorg (T1+T2) (Uniform)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Uniform 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)

YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 Workload-Adaptive Soft Limit により、スキャン検出時に append_region を L2キャッシュ容量(~26,000件 / 1MB ÷ 40B)以下に保つ。Reorg 直後に走査対象が sorted_region のみになりスキャン QPS が V字回復する。
藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize(LTMなど、30秒のタイムウィンドウ内で自然発生が保証されないシナリオ用の強制トリガー。自然発生と混同しないよう区別して表示)。

Scan QPS タイムライン

32 threads / 30 seconds

Reorganize Duration vs. Corpus Size (T1-only vs T1+T2)

単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。 populate自体は計測対象外(reorganize()本体のみ内部60秒でタイムアウト、外側の実行スクリプトはさらに緩い300秒のバックストップ)。 藍色 = T1-only(force_t2_gc=false)、 赤色 = T1+T2(force_t2_gc=true)。 ▲マーカーはタイムアウト(60秒到達、実際の所要時間はそれ以上)を示す。

Reorganize Duration

single-shot, threads:1

Insert Workload

実験概要: ユニークキーを空のストアに順次挿入する際の書き込みスループット。Scan 非アクティブ時は Soft Limit = APPEND_CAP の 50% で動作。

Update (Zipf) Workload

実験概要: Zipf 分布での既存キーに対する更新スループット(ステートフルな上書き)。

Delete (Zipf) Workload

実験概要: T1 Tombstone 付与による並行削除スループット。

Get Miss (Zipf) Workload

実験概要: 存在しないキーへの読み取り。Bloom Filter の偽陽性回避効果を評価。

Get Hit (Zipf) Workload

実験概要: Zipf 分布での既存キーへのポイントルックアップ(キャッシュフレンドリー)。

Get Hit (Uniform) Workload

実験概要: Uniform 分布での既存キーへのポイントルックアップ(極端なキャッシュミス)。

Scan After Reorg (Zipf)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Zipf 分布 100 件レンジスキャンの上限値。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし(T1+T2 完全 reorg 後の全エンジン比較は下記「Scan After Full Reorg (T1+T2)」参照)。

Scan After Reorg (Uniform)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Uniform 分布 100 件レンジスキャン。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし。

Scan After Full Reorg (T1+T2) (Zipf)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Zipf 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

Scan After Full Reorg (T1+T2) (Uniform)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Uniform 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)

YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 Workload-Adaptive Soft Limit により、スキャン検出時に append_region を L2キャッシュ容量(~26,000件 / 1MB ÷ 40B)以下に保つ。Reorg 直後に走査対象が sorted_region のみになりスキャン QPS が V字回復する。
藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize(LTMなど、30秒のタイムウィンドウ内で自然発生が保証されないシナリオ用の強制トリガー。自然発生と混同しないよう区別して表示)。

Scan QPS タイムライン

32 threads / 30 seconds

Reorganize Duration vs. Corpus Size (T1-only vs T1+T2)

単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。 populate自体は計測対象外(reorganize()本体のみ内部60秒でタイムアウト、外側の実行スクリプトはさらに緩い300秒のバックストップ)。 藍色 = T1-only(force_t2_gc=false)、 赤色 = T1+T2(force_t2_gc=true)。 ▲マーカーはタイムアウト(60秒到達、実際の所要時間はそれ以上)を示す。

Reorganize Duration

single-shot, threads:1

Insert Workload

実験概要: ユニークキーを空のストアに順次挿入する際の書き込みスループット。Scan 非アクティブ時は Soft Limit = APPEND_CAP の 50% で動作。

Update (Zipf) Workload

実験概要: Zipf 分布での既存キーに対する更新スループット(ステートフルな上書き)。

Delete (Zipf) Workload

実験概要: T1 Tombstone 付与による並行削除スループット。

Get Miss (Zipf) Workload

実験概要: 存在しないキーへの読み取り。Bloom Filter の偽陽性回避効果を評価。

Get Hit (Zipf) Workload

実験概要: Zipf 分布での既存キーへのポイントルックアップ(キャッシュフレンドリー)。

Get Hit (Uniform) Workload

実験概要: Uniform 分布での既存キーへのポイントルックアップ(極端なキャッシュミス)。

Scan After Reorg (Zipf)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Zipf 分布 100 件レンジスキャンの上限値。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし(T1+T2 完全 reorg 後の全エンジン比較は下記「Scan After Full Reorg (T1+T2)」参照)。

Scan After Reorg (Uniform)

実験概要: T1 reorganize 完了後(sorted_region のみ、T2 は未反映)での Uniform 分布 100 件レンジスキャン。VMemKV 内部専用の中間状態で、他エンジンに相当する概念がないため比較対象なし。

Scan After Full Reorg (T1+T2) (Zipf)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Zipf 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

Scan After Full Reorg (T1+T2) (Uniform)

実験概要: T1 sorted_region + T2 flat file 全体の完全 reorganize 完了後での Uniform 分布 100 件レンジスキャン。RocksDB/LMDB/RocksDB-BlobDB は同一データロード後、各エンジン内部の compaction/最適化が完了した状態として比較(全エンジン共通の比較軸)。

YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)

YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 Workload-Adaptive Soft Limit により、スキャン検出時に append_region を L2キャッシュ容量(~26,000件 / 1MB ÷ 40B)以下に保つ。Reorg 直後に走査対象が sorted_region のみになりスキャン QPS が V字回復する。
藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize(LTMなど、30秒のタイムウィンドウ内で自然発生が保証されないシナリオ用の強制トリガー。自然発生と混同しないよう区別して表示)。

Scan QPS タイムライン

32 threads / 30 seconds

Reorganize Duration vs. Corpus Size (T1-only vs T1+T2)

単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。 populate自体は計測対象外(reorganize()本体のみ内部60秒でタイムアウト、外側の実行スクリプトはさらに緩い300秒のバックストップ)。 藍色 = T1-only(force_t2_gc=false)、 赤色 = T1+T2(force_t2_gc=true)。 ▲マーカーはタイムアウト(60秒到達、実際の所要時間はそれ以上)を示す。

Reorganize Duration

single-shot, threads:1