RocksDB 笔记:Write stall:为什么会卡住、如何定位
发布于:
本文是「RocksDB 笔记:Write stall:为什么会卡住、如何定位」的工程化笔记,记录语义/模型定义、可观测信号与排障要点。
1. write stall 的本质:系统在“欠账过多”时强制刹车
write stall(或 write stop)通常不是“写路径坏了”,而是 RocksDB 在保护自己:
- flush/compaction 追不上写入
- L0 文件堆积导致读放大恶化
- 内存/磁盘/后台队列接近危险线
于是系统选择:宁可卡写,也不要把整个实例拖到不可恢复的抖动里。
可以将它理解成写入链路上的“保险丝”。
2. 一张根因树:stall 一般是这三类欠账之一
2.1 MemTable/Immutable 欠账(flush 跟不上)
典型信号:
- immutable 数量持续上升
- memtable 相关内存占用持续上升
- flush 变慢或 flush 线程/队列被挤压
要点:写入把“内存缓冲”吃光了,系统只能卡写等待 flush 把欠账还掉。
2.2 L0 欠账(flush 产出太多,L0→L1 compaction 跟不上)
典型信号:
- L0 文件数持续上升(或 L0 size 持续上升)
- compaction backlog 持续增长
- 读放大指标变差(读路径需要触碰更多文件)
要点:flush 很勤快,但 compaction 还债能力不足,L0 堆成“炸弹”。
2.3 compaction 欠账(整体还债能力不足,进入“追债-抖动”循环)
典型信号:
- compaction backlog 长期高位
- compaction/flush 的耗时分位数出现长尾
- 写入 P99 抖动、且随时间逐步恶化
要点:后台长期追不上,系统为了不崩只能频繁限速/卡写。
3. 线上最常见的“诱因”(按出现频率)
- IO 抖动或带宽不足:fsync/journal/邻居噪声/存储队列化,让后台任务长尾。
- 后台任务抢占:备份、重建、scan、压缩、校验把 IO/CPU 吃掉。
- 写入形态问题:大量小写、热点 key、覆盖写多,导致 flush/L0 更频繁。
- CPU 成为瓶颈:NVMe 足够快后,压缩/校验/锁竞争更容易成为主导。
4. 应当先看哪些指标(从“最能证明因果”开始)
- immutable memtable 数量:是否持续上升?
- L0 文件数 / L0 size:是否持续上升并接近阈值?
- compaction backlog:是否在追债?是否越追越多?
- flush / compaction 的耗时分位数:是否出现长尾?
- stall/throttle 次数与持续时间:卡写是偶发还是长期?
5. 排障顺序(强烈建议按这个走)
- 先判定是哪类欠账:immutable 先堆?还是 L0/backlog 先堆?
- 再判定瓶颈类型:IO-bound 还是 CPU-bound?
- 做最小 A/B(验证因果):
- 临时减少写入(限流)看欠账是否下降
- 临时提高后台预算(线程/带宽)看欠账是否下降
- 最后再调参:参数只能改变“缓冲器大小/触发点”,不能凭空制造后台能力。
6. 联读建议
- 你如果看到 immutable/L0 的增长链路:建议联读
rocksdb-note-044-memtable-immutable与rocksdb-note-065-flush-write-buffer-l0 - 你如果怀疑是 CPU/IO 判断错误:建议联读
rocksdb-note-016-cpu-io