来源:
- [rocksdb_wiki/RocksDB-Tuning-Guide.md](https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)
- [Compaction Stats and DB Status](https://github.com/facebook/rocksdb/wiki/Compaction-Stats-and-DB-Status)
# 1. Amplification factors
- **写放大**:写入到设备的数据量 / 写入到DB的
- **读放大**:每个请求读磁盘的次数
- **空间放大**:磁盘占用 / DB 写入
---------
# 2. Rocksdb statistics
- 查看方式:
- **stats_dump_period_sec**
- 每隔 stats_dump_period_sec 秒输出一次统计信息到 LOG 中
- 也可以通过 `db->GetProperty("rocksdb.stats")` 手动获取
```
** Compaction Stats **
Level Files Size(MB) Score Read(GB) Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) Comp(cnt) Avg(sec) Stall(sec) Stall(cnt) Avg(ms) KeyIn KeyDrop
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
L0 2/0 15 0.5 0.0 0.0 0.0 32.8 32.8 0.0 0.0 0.0 23.0 1457 4346 0.335 0.00 0 0.00 0 0
L1 22/0 125 1.0 163.7 32.8 130.9 165.5 34.6 0.0 5.1 25.6 25.9 6549 1086 6.031 0.00 0 0.00 1287667342 0
L2 227/0 1276 1.0 262.7 34.4 228.4 262.7 34.3 0.1 7.6 26.0 26.0 10344 4137 2.500 0.00 0 0.00 1023585700 0
L3 1634/0 12794 1.0 259.7 31.7 228.1 254.1 26.1 1.5 8.0 20.8 20.4 12787 3758 3.403 0.00 0 0.00 1128138363 0
L4 1819/0 15132 0.1 3.9 2.0 2.0 3.6 1.6 13.1 1.8 20.1 18.4 201 206 0.974 0.00 0 0.00 91486994 0
Sum 3704/0 29342 0.0 690.1 100.8 589.3 718.7 129.4 14.8 21.9 22.5 23.5 31338 13533 2.316 0.00 0 0.00 3530878399 0
Int 0/0 0 0.0 2.1 0.3 1.8 2.2 0.4 0.0 24.3 24.0 24.9 91 42 2.164 0.00 0 0.00 11718977 0
Flush(GB): accumulative 32.786, interval 0.091
Stalls(secs): 0.000 level0_slowdown, 0.000 level0_numfiles, 0.000 memtable_compaction, 0.000 leveln_slowdown_soft, 0.000 leveln_slowdown_hard
Stalls(count): 0 level0_slowdown, 0 level0_numfiles, 0 memtable_compaction, 0 leveln_slowdown_soft, 0 leveln_slowdown_hard
** DB Stats **
Uptime(secs): 128748.3 total, 300.1 interval
Cumulative writes: 1288457363 writes, 14173030838 keys, 357293118 batches, 3.6 writes per batch, 3055.92 GB user ingest, stall micros: 7067721262
Cumulative WAL: 1251702527 writes, 357293117 syncs, 3.50 writes per sync, 3055.92 GB written
Interval writes: 3621943 writes, 39841373 keys, 1013611 batches, 3.6 writes per batch, 8797.4 MB user ingest, stall micros: 112418835
Interval WAL: 3511027 writes, 1013611 syncs, 3.46 writes per sync, 8.59 MB written
```
## 2.1 Compaction stats
- Level-N 和 N + 1 之间的 compaction 会统计到 level N + 1 上
指标含义:
- **Level**:Sum表示所有历史总和,Int表示区间累计值
- **Files**:a / b 两个值,
- **a**:本层有多少文件;
- **b**:有多少文件涉及 compaction
- **Score**:compaction分数,大于 1 表示需要 compaction
- L0: 文件个数 / number_tigger
- 其他层:current_level_size / max_level_size
- **Read(GB)**:compaction期间读取的字节数,包含上下两层
- **Rn(GB)**: level N 读取的 bytes
- **Rnp1(GB)**: level N+1 读取的 bytes
- **Write(GB)**: compaction 写入的数据量
- **Wnew(GB)**:新写入到 N + 1 层的数据(刨除从 N+1 读取的数据)
- **Moved(GB)**:compaction时直接 move 到 N +1 层的数据量(不涉及IO)
- **W-Amp**:两层之间的写放大:写入到 N+1 的数据量 / 从 N 层读取的数据量
- **Rd(MB/s)**:compaction 平均读取速率
- **Wr(MB/s)**:compaction 平均写入速率
- **Rn(cnt)**:从 level N 读取的文件个数
- **Rnp1(cnt)**:从 level N+1 层读取的文件数量
- **Wnp1(cnt)**:
- **Comp(sec)**:compaction 耗费的总时长
- **Comp(cnt)**:compaction 的次数
- **Avg(sec)**:一次 compaction 的平均时长
- **Stall(sec)**: 因为 level N+1 未compacted 而导致的 write stall 的时长
- **Stall(cnt)**: 同上,stall 的次数
- **KeyIn**: compaction 期间比较了多少个 key
- **KeyDrop**:drop 的 records 数量(未写入)
## 2.2 General stats
```
Uptime(secs): 7094.3 total, 120.0 interval
Cumulative writes: 140M writes, 561M keys, 126M commit groups, 1.1 writes per commit group, ingest: 695.77 GB, 100.43 MB/s
Cumulative WAL: 140M writes, 0 syncs, 140456226.00 writes per sync, written: 695.77 GB, 100.43 MB/s
Cumulative stall: 00:00:0.000 H:M:S, 0.0 percent
Interval writes: 1877K writes, 7495K keys, 1636K commit groups, 1.1 writes per commit group, ingest: 9520.85 MB, 79.34 MB/s
Interval WAL: 1877K writes, 0 syncs, 1877057.00 writes per sync, written: 9.30 GB, 79.34 MB/s
Interval stall: 00:00:0.000 H:M:S, 0.0 perce
```
- **Uptime(secs)**:
- total:DB 启动后过了多少秒
- interval:距离上次 stats dump 过了多少秒
- **Cumulative / Interval Writes**:
- writes:多少次 Put 调用
- keys:写入的 key 的数量
- commit groups:组提交的数量
- writes per commit group:
- ingest:写入到 DB 的字节数(不包含comacption)
--------
# 3. Possibilities of Performance Bottlenecks
## 3.1 System Metrics
有时性能受限于系统指标饱和,而且症状有时是意想不到的。
用户需要查询系统指标,来确定某个系统指标是否使用过高。
检查以下指标是否异常:
- **Disk Write Bandwidth**
- 通常 Rocksdb compaction 写入可能会超出 SSD 的承受能力,就可能会引发 **write stalling**
- 或者导致**读变慢**(compaction不及时,LSM 结构 skewed),通过 Pref context 可以发现一次读需要读过多的 SST files ;
- **措施**:tuning compaction
- **Disk Read IOPS**
- 需要保证持续性的 read IOPS 不要超过硬件的规格
- 过高后的**措施**:
- 开始检查 compaction
- 尝试提高 block cache hit rate
- 有时是由于 reading index,filter 或者 large data blocks,处理方式也不同
- **CPU**
- 通过是由于 read path,也可能是 compactions 导致
- 许多选项可能有影响:compaction、compression、bloom filters、block size 等
- **Space**
- 通过不会是一个瓶颈
- 如果用户想要承载更大数据量,那么 compaction 和 compression 是主要的调优方向。
- [[rocksdb-space-tuning]]
## 3.2 Amplification factors
- **Write amplificatoin**
- 如果过高,则磁盘吞吐可能会成为瓶颈,也会影响 flash lifetime
- 两种观测方式
- `DB::GetProperty("rocksdb.stats", &stats)`
- 观察磁盘写入带宽 和 DB 写入速度
- **Read amplification**
- 含义:每次查询读盘次数
- logical read:包含读取 cache
- pyhsical read:读物理盘,可以通过 iostat 输出来观察
- **Space amplification**
- [[rocksdb-space-tuning]]
## 3.3 Slownes while system metrics are not saturated
系统指标不高,但是性能仍然不好,可能的原因:
- **Compaction不够快**:调整 compaction 的并发
- **写入 IO 不够快**:导致写 WAL 和 memtable 不够快,可以的优化手段:
- 尝试 unordered write
- 手动 flush WAL
- 使用 多个DB 并行写入
- **读延迟敏感**:用户希望延迟更低
- 通过 [Perf Context and IO Stats Context](https://github.com/facebook/rocksdb/wiki/Perf-Context-and-IO-Stats-Context) 来查看耗时情况
-----------
# 4. Tuning Flushes and Compactions
## 4.1 Parallelism options
- 增加 flush 和 compaction 的后台线程数:
```cpp
options.env->SetBackgroundThreads(num_threads, Env::Priority::HIGH);
options.env->SetBackgroundThreads(num_threads, Env::Priority::LOW);
```
## 4.2 Compaction Priority( leveled compaction)
- Rocksdb 的默认 `compaction_pri = kMinOverlappingRatio`,大多数情况是最优的。
## 4.3 Tigger compaction on deletes
- 当删除大量 rows 后,一些 SST files 内可能会存在大量 tombstones,从而影响 range scan 性能。
- Rocksdb 如果检测到某个 Key range 内的 tombstones 密度很高,就会马上触发 compaction 来 compact 这些 tombstones。但无法保证很及时。
- 关键类:**CompactOnDeletionCollectorFactory**
## 4.4 Periodic and TTL Compaction
- `options.ttl`
- `options.periodic_compaction_seconds`:确保每个文件间隔一段时间后一定会被 compaction,这样 compaction filter 就随之可以把数据清理掉
## 4.5 Flush Options
- **write_buffer_size**
- **max_write_buffer_number**:最大 memtables 的个数(包括 active 和 immutable 的)
- **min_write_buffer_number_to_merge**:flush 前**至少**先 merge 多少个 memtables
- 如果设置成2, 则至少有 2 个 immutable memtables 后才触发 flush(一个不会触发)
- 通过 merge 可能可以减少写入到存储的数据量(比如对一个key更新了多次)
- 但是 Get() 时需要线性遍历所有 immutable memtables 来检查 key 是否存在,因此设置太高会可能会**影响读性能**
## 4.6 Level Style Compaction
- 不同 level 或者 不同 key ranges 的 compaction 是独立的,可以并行执行。
### L0 -> L1
- L0 -> L1 的 compaction 是特殊的,L0 的文件范围可能覆盖整个 key space。
- Compaction 时可能涉及所有 L1 文件
- 当 L1 的所有文件都在跟 L0 进行 compact,**L1 -> L2 的 compaction 就无法进行**,只能等待 L0 -> L1 的 compaction 完成。
- 如果 L0-> L1 compaction 很慢,那么系统大部分时间都只在运行 L0 -> L1 compaction(其他 compaction 必须等待它完成)
- 为了让 L0 -> L1 的 compaction 尽可能快,通常配置成 **L0 的大小和 L1 相近**。
### 放大系数分析
- 假设: L1 大小为512 MB,level 放大倍数为 10,L2 为 5 GB,L3 为 51 GB,L4 为 512 GB,DB 大小为 500 GB
- **空间放大**:$(512MB + 512MB + 5GB + 51GB + 512 GB) \ / \ (500GB) = 1.14$
- **写放大**:
- 每写入 1 字节,先写到 L0,L0 与 L1 大小一样,因此 L0 -> L1 compaction 的写放大是 2
- L1 -> L2,需要 compact L2 中 10 倍数据,因此写放大是 10
- 总的写放大为:$1 + 2 + 10 + 10 + 10 = 33$
### 相关参数
- **level0_file_num_compaction_trigger**:
- L0 文件个数大于配置后,触发 L0 -> L1 compaction
- 估算 L0 的大小:`write_buffer_size * min_write_buffer_number_to_merge * level0_file_num_compaction_trigger`
- **max_bytes_for_level_base**:L1 的总大小。推荐配置为 L0 的大小。
- **max_bytes_for_level_multiplier**:默认是10,每层的 size 放大倍数,一般不推荐更改
- **target_file_size_base**:L1 层每个文件的大小
- 推荐设置为 `max_bytes_for_level_base / 10`,即 L1 有 10 个文件
- **target_file_size_multiplier**:默认为1,每层文件大小的放大倍数
- **compression_per_level**:
- 通常 L0 和 L1 不压缩
- 高层次的可以使用压缩率更高的算法
- **num_levels**
- 设置大了也是安全的(空层次不影响性能)
----
# 5.Tuning Other Options
## 5.1 General options
- **filter_policy**:有单点读可以配置 bloom filter
- **block_cache**:缓存未压缩的 blocks
- **max_open_files**:-1 为不限制
- **table_cache_numshardbits**:如果 table cache 的锁竞争很大,可以考虑增大该选项
- **block_size**:
- 增大:index 数据更少,可以降低内存占用和空间放大,但是会**增加读放大**
## 5.2 Sharing cache and thread pool
- 多个 DB 可以共享 block cache 和 thread pool。
## 5.3 Prefix databases
### prefix_extractor
- 用来定义 key prefixes
- key prefixes 可以进行的优化:
- 定义 prefix bloom filters,可以减少 range queries 的读放大
- 使用 hash-map-based memtables,可以避免 memtable 的 binary search costs
- table files 使用 hash index