土法炼钢兴趣小组的算法知识备份

【RocksDB 内核机制】经典故障与排查

文章导航

分类入口
databasestorage
标签入口
#rocksdb#troubleshooting#l0-compaction#write-stall#block-cache#enospc#getproperty#log-interpretation

目录

第 10–12 篇 讲过 leveled 不变式、StopWritesTriggerWriteController stall 状态机。第 16 篇 把 Flink 增量 checkpoint 与 SST 文件语义对齐。生产里运维同学更常遇到的是:延迟突然放大、磁盘占用爬升、checkpoint sync 变长、进程「像 hang 住」却不报错——四类症状往往对应 L0 堆积、compaction 跟不上、Block Cache 失效、磁盘 ENOSPC 触发的 write stall。

本文是系列 第 17 篇,给出 可核对的信号源DB::GetProperty 键名(RocksDB 9.x db/internal_stats.cc,A 级)、LOG 中 ROCKS_LOG_WARN 行格式(db/column_family.cc,A 级)、Statistics tick 与 storage/76 磁盘耗尽 的应用层表现。参数 cookbook 仍见 storage/32;Flink 作业侧见 stream/13 状态调优

版本锚定:RocksDB 9.x(property 名以 include/rocksdb/db.h DB::Properties 为准)。
环境说明:WSL2 Linux 6.6.x,RocksDB 9.4.0reproduce/build_rocksdb.sh);复现见 reproduce/run_db_bench.sh exp11run_properties.sh。§七 引用本机 exp11 实测片段(与 第 11 篇 一致);LOG 行格式来自源码字符串(A 级)。


一、排查框架:先分层再下钻

flowchart TD
  SYM["Symptom: slow write / read / hang"]
  SYM --> Q1{"rocksdb.is-write-stopped = true?"}
  Q1 -->|yes| STALL["Write stall chain<br/>see LOG + cf-write-stall-stats"]
  Q1 -->|no| Q2{"L0 files high?"}
  Q2 -->|yes| L0["L0 pile-up<br/>compaction backlog"]
  Q2 -->|no| Q3{"block cache hit ratio low?"}
  Q3 -->|yes| CACHE["Block cache pressure"]
  Q3 -->|no| Q4{"df shows full / ENOSPC?"}
  Q4 -->|yes| DISK["Disk full behavior<br/>storage/76"]
  Q4 -->|no| OTHER["Snapshots / hot CF / ingest"]
层级 先问什么 首选信号
文件系统 块/inode/元数据是否耗尽? df -hdf -i;Btrfs btrfs filesystem usage
LSM 结构 L0 是否失控?pending bytes 是否爆表? rocksdb.num-files-at-level0rocksdb.estimate-pending-compaction-bytes
缓存 读路径是否反复落盘? rocksdb.block.cache.hit/miss(Statistics)
控制 是否处于 stop / delay? rocksdb.is-write-stoppedrocksdb.actual-delayed-write-rate
嵌入场景 是单 CF 还是 Flink 多 CF 共 slot? TM 上 per-subtask LOG;Flink native metrics

1.1 Stall 是背压,不是「神秘 hang」

Write stall 在 Wiki(A 级)与 bLSM(SIGMOD 2012)语境下是 故意降速或停写,给 flush/compaction 时间消化 debt——排查时先确认 是否处于设计内的 backpressure,再调参。与 ENOSPC、JVM GC、Flink barrier 对齐等 外层 stall 叠加时,仅看 RocksDB property 不够;但 rocksdb.is-write-stopped 与 LOG Stalling/Stopping writes 仍是 内核层第一手信号(机制详见 第 11 篇)。


二、GetProperty:常用键名

RocksDB 在 db/internal_stats.cc 注册 property,公开名带 rocksdb. 前缀(A 级源码)。下表按故障类型分组;完整列表见 Wiki StatisticsDB::Properties

2.1 LSM 结构与 compaction

Property 含义 典型异常
rocksdb.num-files-at-level{N} \(N\) 层 SST 文件数 L0 \(\gg\) level0_slowdown_writes_trigger(默认 20)
rocksdb.stats 文本摘要(层深、文件数、score) 快速肉眼扫描;等同 db_bench --benchmarks=stats
rocksdb.levelstats 各层详细统计 对比 L0 vs L1+ 字节分布
rocksdb.estimate-pending-compaction-bytes 待 compaction 字节估计 接近 soft_pending_compaction_bytes_limit → delay
rocksdb.compaction-pending 是否有 compaction 待调度 长期 1 且 L0 涨 → 线程/IO 不足
rocksdb.num-running-compactions 正在运行的 compaction 数 长期 < max_background_jobs 且 pending 高 → 磁盘或 CPU 瓶颈
rocksdb.num-running-flushes 正在运行的 flush 数 与 immutable memtable 堆积对照

2.2 MemTable 与 write stall

Property 含义 典型异常
rocksdb.num-immutable-mem-table 未 flush 的 immutable memtable 数 接近 max_write_buffer_number → flush 跟不上
rocksdb.mem-table-flush-pending 是否有 flush 等待 checkpoint 前强制 flush 时常为 1
rocksdb.is-write-stopped 是否 完全停写 true → 见 LOG Stopping writes
rocksdb.actual-delayed-write-rate 当前 delay 模式限速(bytes/s) 非 0 → Stalling writes
rocksdb.cf-write-stall-stats CF 级 stall 计数摘要 区分 L0 / memtable / pending bytes 原因
rocksdb.db-write-stall-stats DB 级 stall 计数 多 CF 汇总

2.3 空间与 Block Cache

Property 含义 典型异常
rocksdb.live-sst-files-size live SST 总字节 远大于逻辑 key 体积 → 写放大 / tombstone
rocksdb.total-sst-files-size 含 obsolete 的 SST 体积 与 live 差过大 → compaction 未及时回收
rocksdb.block-cache-capacity Block Cache 容量 block-cache-usage 对照
rocksdb.block-cache-usage 已用 cache 顶满 + miss 高 → 读放大
rocksdb.block-cache-pinned-usage pin 住的块 index/filter pin 过高挤占 data
rocksdb.estimate-table-readers-mem Table Cache 等估计 打开 SST 过多

2.4 读取方式


三、L0 堆积

3.1 机制回顾

Leveled compaction 要求 L1+ 层 key 范围不重叠L0 允许多文件 key 范围重叠第 10 篇)。写入过快或 flush 过多时,L0 文件数上升 → 点查需 probe 多个 L0 SST → 读放大上升;超过 level0_slowdown_writes_trigger 进入 delay,超过 level0_stop_writes_trigger 进入 stop第 11 篇)。

3.2 LOG 判读

ColumnFamilyData::RecalculateWriteStallConditionsdb/column_family.cc 打印 WARN(A 级,以下为 源码格式%d / %s 为运行时填充):

Delay(仍接受写入,但限速)

[default] Stalling writes because we have %d level-0 files rate %lu

Stop(前台写阻塞)

[default] Stopping writes because we have %d level-0 files

CF 名 [default] 在 Flink 中为具体 state 名(如 [count])。若同一 LOG 段 反复出现%d 接近 level0_stop_writes_trigger,说明 L0 compaction 跟不上 flush 产出

增量 checkpoint 前 同步 Flush短期推升 L0 文件数第 16 篇)。若 checkpoint 间隔内 L0 已常年偏高,syncDuration 与 stall 叠加——stream/13 建议同时看 state 膨胀rocksdb.num-files-at-level0

3.4 处置方向(机制层,非参数大全)

  1. 确认 compaction 是否在跑num-running-compactionsLOGCompaction start / Compaction finished
  2. 区分写太快 vs compaction 太慢:写速率、RateLimiter第 12 篇)、磁盘带宽。
  3. 临时缓解CompactRange、调低 level0_slowdown_writes_trigger提前 stall 而非根治——长期需增 max_background_jobs 或降写入、改 Universal(写放大权衡见 storage/31)。
  4. 嵌入场景:Flink 单 subtask 过热时,先查 KeyGroup 倾斜(stream/13),再查该 subtask 本地 LOG。

四、Compaction 跟不上

4.1 pending bytes 链路

除 L0 文件数 外,RocksDB 还跟踪 estimated pending compaction bytes。超过 soft_pending_compaction_bytes_limitdelay;超过 hard_pending_compaction_bytes_limitstop

LOG 格式(源码 column_family.cc):

[default] Stalling writes because of estimated pending compaction bytes %lu rate %lu
[default] Stopping writes because of estimated pending compaction bytes %lu

对应 property:rocksdb.estimate-pending-compaction-bytes

4.2 常见根因

根因 信号 说明
磁盘带宽饱和 iostat 高 util;compaction 耗时长 与 Flink checkpoint 上传 叠加(stream/13)
max_background_jobs 过小 num-running-compactions 长期打满 第 12 篇
大 value / 宽列 live-sst-files-size 涨速异常 考虑 BlobDB 或 value 拆分(超出本篇)
disable_auto_compactions=true compaction-pending 长期为 1 且无进展 运维误配或 ingest 窗口
快照 / checkpoint 引用 num-snapshots 高;旧 SST 不删 空间涨但 compaction 「无效」

4.3 Compaction 与读放大

Compaction 落后时 tombstone 与多版本 entry 滞留,读路径 需扫描更多 entry(第 8 篇 Iterator)。表现为 Get/Iterator 延迟升而 L0 文件数未必唯一指标——需同时看 live-sst-files-sizeestimate-num-keys 的比值。


五、Block Cache 未命中

5.1 读路径回顾

点查经 Table Cache → Filter → Index → Data Block(第 9 篇)。Block Cache miss 每次触发磁盘读;L0 文件多时,即使 Bloom 过滤,Index/Data 块 miss 仍显著。

5.2 Statistics tick

启用 Options.statistics = CreateDBStatistics() 后(db_bench --statistics=1),常用 tick(include/rocksdb/statistics.h,A 级):

Tick 含义
rocksdb.block.cache.hit Block Cache 命中
rocksdb.block.cache.miss Block Cache 未命中
rocksdb.block.cache.add 新块入 cache
rocksdb.block.cache.bytes.insert 入 cache 字节

命中率 \(\approx \frac{\Delta hit}{\Delta hit + \Delta miss}\)(采样窗口内需取增量,非累计绝对值)。

Flink 默认 state.backend.rocksdb.memory.managed=true,在 slot 级划分 Write Buffer vs Block Cache(stream/12 第 4.2 节)。写缓冲占满 50% 时,读热点 scan 易出现 cache 抖动——stream/13 建议大状态 避免 full MapState.entries() scan,与 cache 容量无关的算法层优化。

5.4 误判


六、ENOSPC 与 write stall

6.1 文件系统层

磁盘从 70% 填充到 ENOSPC 的行为因 ext4/XFS/Btrfs 而异(storage/76)。对 RocksDB 嵌入场景,关键结论是:

6.2 RocksDB 应用层行为

RocksDB ErrorHandlerStatus::NoSpace() 的处理(db/error_handler.cc 及测试 error_handler_fs_test.cc,A 级):

Wiki Background Error Handling(A 级)说明:no_space 类错误在默认配置下常导致 无限期 stall——监控上表现为 p99 延迟无穷大、CPU 不高、无明确 Java 异常(Flink TM 典型「假死」)。

DB::GetProperty("rocksdb.background-errors") 非零时应 立即查磁盘rocksdb.is-write-stopped

6.3 与 storage/76 的对照

现象 storage/76 视角 RocksDB 视角
df 100% ENOSPC、分配器退化 flush/compaction 失败 → stall
df 70% 但写失败 Btrfs metadata / inode 同上 + 查 df -i
应用 hang 「Kafka/RocksDB stall」 LOG stall + is-write-stopped
恢复 删文件、扩卷、Btrfs balance 释放空间后 stall 自动解除(默认)

应急:先腾磁盘(删 obsolete SST 需 compaction 完成或从 checkpoint 链 pruning;Flink 远程 shared state 亦占空间),再重启仅作最后手段。

6.4 MemTable 触发的 stall(非 ENOSPC)

immutable memtable 过多时 LOG 另有:

[default] Stalling writes because we have %d immutable memtables (waiting for flush), max_write_buffer_number is set to %d rate %lu
[default] Stopping writes because we have %d immutable memtables (waiting for flush), max_write_buffer_number is set to %d

这与 ENOSPC 症状相似(写慢),但 df 仍有空间——用 num-immutable-mem-table 区分。


七、db_bench 复现(exp11)

脚本 reproduce/run_db_bench.sh exp11 压低 L0 阈值以 试图 观察 stall 行为(机制验证,非保证触发):

cd post/db/rocksdb/reproduce
./build_rocksdb.sh
export DB_BENCH="${PWD}/rocksdb/db_bench"
./run_db_bench.sh    # 含 exp11;或单独跑 exp11 段

exp11 核心参数:

db_bench --benchmarks=fillrandom --num=500000 --value_size=256 \
  --level0_slowdown_writes_trigger=2 \
  --level0_stop_writes_trigger=4 \
  --db="${OUT_DIR}/bench_dbs/exp11_stall" --statistics=1

本机实测(WSL2,i9-12900K,RocksDB 9.4.0,2026-07-07;reproduce/output/exp11_stall.txt,经删减):

fillrandom   :       2.901 micros/op 344660 ops/sec 1.451 seconds 500000 operations
rocksdb.stall.micros COUNT : 0
Write Stall (count): total-delays: 0, total-stops: 0

解读(与第 11 篇 §七 一致):尽管 slowdown=2stop=4,在 高速 SSD + 1.45s 跑完可能 stall=0——这不否定 §1.1 状态机;只说明 短跑 exp11 不能替代生产 LOG 排查。稳定复现 stall 需更长 --duration、更慢磁盘,或实验环境 pause compaction。

若 stall 非零,预期还有:LOG 出现 §3.2 的 Stalling/Stopping writesrocksdb.cf-write-stall-stats 计数上升。

run_properties.sh 在短跑后保留 output/log_tail.txt 供 LOG 格式对照(输出经删减后引用)。

7.1 开放问题

  1. 跨层归因:Flink syncDuration 变长时,如何区分 RocksDB stall vs 远程 state 上传 vs GC?需 时间线对齐(checkpoint 事件 + TM LOG + GetProperty 采样);无单一 metrics 公式
  2. 可观测性缺口Statistics tick 是累计量,生产 tail 需 增量采样PerfContext;OpenTelemetry 导出仍在演进,版本以 release note 为准。
  3. 自动根因:能否从 LOG + property 训练推荐 max_background_jobs / compaction style?工业 AutoTune 实验与论文侧 workload-aware compaction 并存,默认仍以人工 POC 为主。

八、嵌入场景速查

场景 优先文件/命令 内核信号
Flink checkpoint 慢 TM rocksdb-localdir、Flink REST syncDuration mem-table-flush-pending、L0 stall LOG
TiKV 读抖 TiKV metrics + 本地 RocksDB LOG num-files-at-level0pending-compaction-bytes
Kafka Streams restore 慢 changelog lag、本地 store 目录 同单机 LSM;另查 consumer
MyRocks / 自建 LOGrocksdb.stats 全文同上

九、小结

下一篇 选型与存储栈阅读地图 收束 RocksDB vs InnoDB vs 列存 vs 湖仓,并给出全栈阅读路径。


上一篇生产嵌入对照

下一篇选型与存储栈阅读地图

返回 系列目录


参考资料

  1. RocksDB Wiki, Troubleshooting / Write Stalls / Background Error Handling / Statistics(A 级)。
  2. RocksDB 9.x 源码:db/internal_stats.cc(property 名);db/column_family.ccRecalculateWriteStallConditions LOG);db/write_thread.cc(stall 队列);db/error_handler.cc(NoSpace;A 级)。
  3. Sears & Ramanan, bLSM, SIGMOD 2012(stall / 多核 compaction 学术锚点;A 级)。
  4. storage/76 磁盘空间耗尽(ENOSPC 链、RocksDB stall 默认行为)。
  5. storage/31 LSM 调参storage/32 RocksDB 实践(调参边界)。
  6. 本系列 第 10–12 篇(compaction / stall);第 11 篇 exp11第 16 篇(Flink 交叉)。
  7. 本机 exp11:reproduce/output/exp11_stall.txt(stall.micros=0,2026-07-07)。
  8. stream-processing 第 13 篇(Flink 侧调优)。

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-07-07 · database / storage

【RocksDB 内核机制】Universal、FIFO 与 Write Stall

对照 Universal/FIFO/TTL compaction 策略,从 GetWriteStallConditionAndCause 与 WriteController 的 Stop/Delay token,到 DBImpl::DelayWrite 状态机、LOG 与 GetProperty 判读;exp11 用极低 L0 阈值触发 stall。


By .