来源: - [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