Benchmark Results (2026081313)
AWS 32コア物理環境における vmemkv と RocksDB/RocksDB-BlobDB/LMDB の性能比較ベンチマーク。08/10時点比、本ラウンドの主要変更は2件。
まずScanBaseSequentialの base 領域読み取りを、単一の固定 madvise 方針から、レコードごとの埋め込みサイズヒントで選ぶ3つの経路
(base_mmap_scan_seq: mmap + MADV_SEQUENTIAL、1ページ以下のレコード用 /
base_mmap_scan: mmap + カーネルのデフォルトreadahead、それより大きいレコード用 /
read_fd: 境界を絞ったpread()、Getの大レコード・非residentケース用)に置き換え、
1つのマッピングを全レコードサイズで共用していた旧設計が引き起こしていた1KB LTM Scanの退行(0.40〜0.78x)を解消(64KB LTMのGet/Hitも2.0〜3.3x、Scan(Zipf)も2.2x改善)。
次に、この3経路化の過程でget_impl()の小レコード(1ページ以下)向けbase領域読み取りが、誤ってScan専用の
base_mmap_scan_seq(MADV_SEQUENTIAL)マッピングを再利用してしまっていたバグを発見・修正。
Getは本質的にランダムアクセスなので、実LTMスワップ圧下でMADV_SEQUENTIALの広いreadahead+drop-behindが1 major faultあたりのカーネル時間を約10倍に増幅させていた
(perf stat実測: 117us vs 11.2us)。既にMADV_RANDOMを持つプライマリのbaseマッピングへ
直接読みに変更(seqlock無し、base-region不変性を利用)することで解消し、1KB LTMのGet/HitがZipf 5.2倍・Uniform 6.5倍改善、+Prefaultと同等かむしろ上回る水準まで回復。
併せてtry_scan_base_record()/try_get_base_record()を単一の
try_read_base_record()エントリポイントへ統合し、マッピング選択方針をBaseReader switch文の1箇所に集約(今回のような取り違えの再発防止)。
In-Memoryや他バリアントへの退行は確認されなかった。詳細はvmemkv_impl.hppの
try_read_base_record()のコメントを参照。
本レポートはこの修正を含む本番マトリクス全体(In-Memory/LTM × 8B/1KB/64KB × 全ストア)を、4台の独立したAWSスポットインスタンスに分割並列実行して取得した最新結果。
Stacking Variants
各最適化の詳細は Design Document を参照。
- RocksDB: LSM-Tree のベースライン比較
- LMDB: B+Tree / mmap ベースの比較対象
- RocksDB-BlobDB: RocksDB の Blob 分離ストレージ変種(大きな Value 向け)
- Baseline: vmemkv 最適化なし
- +BF: + T1 Bloom Filter
- +Inline: +BF + T1 Inline Value(<8B のValueをT1のみで処理)
- +Prefault: +Inline + T2 Async Prefaulting
- +ScanBaseSequential: +Prefault + base領域専用mmap(MADV_SEQUENTIAL)。本ラウンドから Get もこのmmapの高速パスを使う(全部盛り、= VMemKVStore)
Environment
- Instance: AWS i4i.8xlarge (ap-northeast-1) x4 (4並列独立インスタンス、run_4parallel_bench.sh)
- CPU: Intel Xeon Platinum 8375C @ 2.90GHz (32 cores)
- RAM: 247.7 GiB
- RAM (Larger-Than-Memory): cgroup で DRAM を 1GiB に制限、target_ratio=8.0でコーパスを約8倍の規模に構築後、cgroup内で計測(ストアごとに独立したcgroupスコープ + drop_caches)
- Disk: Local NVMe SSD (Swap Media for LTM)
- Kernel: 6.17.0-1019-aws
- Git Rev: 7bf7d6a972ab (clean -- get_impl() base_mmap 高速パスを含む)
Workloads
- Insert: 順次挿入(1/4/16/32 スレッド)
- Get Hit/Miss (Zipf/Uniform): ポイントルックアップ
- Update / Delete: Zipf 分布での更新・削除
- Scan (Zipf/Uniform): レンジスキャン(旧レポートにあった 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 (+Prefault)
vs RocksDB-BlobDB
|
✅ WIN (1.61x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
✅ WIN (1.61x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
✅ WIN (2.64x)
vmemkv (+Inline)
vs RocksDB
|
| Update (Zipf) |
✅ WIN (1.46x)
vmemkv (All opts)
vs RocksDB
|
✅ WIN (1.57x)
vmemkv (+Inline)
vs RocksDB-BlobDB
|
✅ WIN (2.14x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
✅ WIN (3.02x)
vmemkv (+Inline)
vs LMDB
|
| Delete |
✅ WIN (1.57x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
✅ WIN (1.68x)
vmemkv (+BF)
vs RocksDB
|
✅ WIN (1.74x)
vmemkv (+BF)
vs RocksDB
|
✅ WIN (3.61x)
vmemkv (+Inline)
vs RocksDB-BlobDB
|
| Get (Miss) |
✅ WIN (2.76x)
vmemkv (+Prefault)
vs RocksDB
|
✅ WIN (3.08x)
vmemkv (+Prefault)
vs LMDB
|
✅ WIN (2.83x)
vmemkv (+Prefault)
vs LMDB
|
✅ WIN (2.59x)
vmemkv (+Prefault)
vs LMDB
|
| Get (Hit, Zipf) |
✅ WIN (1.35x)
vmemkv (+Inline)
vs LMDB
|
✅ WIN (1.18x)
vmemkv (All opts)
vs LMDB
|
❌ LOSE (0.62x)
vmemkv (+Inline)
vs RocksDB-BlobDB
|
✅ WIN (1.26x)
vmemkv (All opts)
vs RocksDB
|
| Get (Hit, Uniform) |
WIN (1.08x)
vmemkv (+Inline)
vs LMDB
|
WIN (1.11x)
vmemkv (All opts)
vs LMDB
|
LOSE (0.88x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
≈ EVEN (0.99x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
| Scan (Zipf) |
❌ LOSE (0.83x)
vmemkv (+Prefault)
vs LMDB
|
≈ EVEN (1.04x)
vmemkv (All opts)
vs LMDB
|
❌ LOSE (0.77x)
vmemkv (All opts)
vs RocksDB
|
WIN (1.08x)
vmemkv (All opts)
vs LMDB
|
| Scan (Uniform) |
❌ LOSE (0.85x)
vmemkv (+Inline)
vs LMDB
|
WIN (1.11x)
vmemkv (All opts)
vs LMDB
|
✅ WIN (1.32x)
vmemkv (All opts)
vs RocksDB
|
≈ EVEN (0.96x)
vmemkv (All opts)
vs RocksDB-BlobDB
|
| YCSB-E (Timeline Workload) |
✅ WIN (2.80x)
vmemkv (All opts)
vs RocksDB
|
✅ WIN (1.62x)
vmemkv (All opts)
vs RocksDB
|
≈ EVEN (0.98x)
vmemkv (All opts)
vs RocksDB
|
WIN (1.06x)
vmemkv (All opts)
vs RocksDB
|
Tier 1 Reorganize (T1only)
Average and worst-case times to reorganize the active buffer.
| Scenario | 8B | 1KB | 64KB |
|---|---|---|---|
| In-Memory | Avg: 1.36s Max: 2.29s | Avg: 0.66s Max: 0.73s | - |
| LTM | - | Avg: 1.29s Max: 1.48s | Avg: 0.10s Max: 0.16s |
Tier 1+2 Reorganize (Full)
Average and worst-case times for a full T1+T2 reorganize / checkpoint.
| Scenario | 8B | 1KB | 64KB |
|---|---|---|---|
| In-Memory | Avg: 24.48s Max: 40.40s | Avg: 13.53s Max: 21.74s | - |
| LTM | - | Avg: 39.66s Max: 60.00s *(1/4 points timed out) | Avg: 32.08s Max: 58.06s |
Insert Workload
Update (Zipf) Workload
Delete (Zipf) Workload
Get Miss (Zipf) Workload
Get Hit (Zipf) Workload
Get Hit (Uniform) Workload
Scan (Zipf) Workload
Scan (Uniform) Workload
YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)
YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize。
Scan QPS タイムライン
32 threads / 30 secondsReorganize Duration vs. Corpus Size (T1-only vs T1+T2)
単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。
藍色 = T1-only、赤色 = T1+T2。
▲マーカーはタイムアウトを示す。
Reorganize Duration
single-shot, threads:1Insert Workload
Update (Zipf) Workload
Delete (Zipf) Workload
Get Miss (Zipf) Workload
Get Hit (Zipf) Workload
Get Hit (Uniform) Workload
Scan (Zipf) Workload
Scan (Uniform) Workload
YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)
YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize。
Scan QPS タイムライン
32 threads / 30 secondsReorganize Duration vs. Corpus Size (T1-only vs T1+T2)
単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。
藍色 = T1-only、赤色 = T1+T2。
▲マーカーはタイムアウトを示す。
Reorganize Duration
single-shot, threads:1Insert Workload
Update (Zipf) Workload
Delete (Zipf) Workload
Get Miss (Zipf) Workload
Get Hit (Zipf) Workload
Get Hit (Uniform) Workload
Scan (Zipf) Workload
Scan (Uniform) Workload
YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)
YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize。
Scan QPS タイムライン
32 threads / 30 secondsReorganize Duration vs. Corpus Size (T1-only vs T1+T2)
単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。
藍色 = T1-only、赤色 = T1+T2。
▲マーカーはタイムアウトを示す。
Reorganize Duration
single-shot, threads:1Insert Workload
Update (Zipf) Workload
Delete (Zipf) Workload
Get Miss (Zipf) Workload
Get Hit (Zipf) Workload
Get Hit (Uniform) Workload
Scan (Zipf) Workload
Scan (Uniform) Workload
YCSB-E — Scan + Insert 混合スループット(30秒タイムライン)
YCSB-E ワークロード: 95% Scan(100件レンジスキャン)+ 5% Insert を 32スレッドで 30秒間実行。 藍色の点線: 自然発生のT1 Reorganize(Adaptive Soft Limitによる自動トリガー)。 橘色の点線: t=15秒時点で強制的に1回実行されるT1 Reorganize。
Scan QPS タイムライン
32 threads / 30 secondsReorganize Duration vs. Corpus Size (T1-only vs T1+T2)
単発のreorganize()呼び出し1回の所要時間を、コーパスサイズ(件数)を横軸にスイープ計測。
藍色 = T1-only、赤色 = T1+T2。
▲マーカーはタイムアウトを示す。