Tuning RocksDB - Statistics

RocksDB 是一个性能非常强悍的 Key-Value 存储引擎,很多项目包括我们的 TiKV 都使用它来存储数据。但 RocksDB 也因其复杂的配置著称,要让 RocksDB 在不同的机器上面都能有很好的性能,并不是一件容易的事情。很多时候,千辛万苦在一台机器上面的配的配置,在另一台机器上面性能就是不行。

RocksDB 官方专门写了一篇文章,来讲如何 tuning RocksDB,这里,我会结合我们在 TiKV 里面对于 RocksDB 的调优经验,详细的对其解释一下,当然也不会完全翻译。一方面是跟大家共同学习,另一个方面则是让自己更加熟悉 RocksDB。

要了解如何优化 RocksDB,首先需要知道 RocksDB 的核心是 LSM ,不过这个现在外面已经有太多的文章了,就不做过多说明了。不过如果有可能,还是可能写写 RocksDB 具体是如何处理 LSM 的。

Amplification factors

调优 RocksDB 通常就是在三个 amplification 之间做取舍的。

  • Write amplification - 也就是我们最经常碰到的写放大,假设我们每秒写入 10MB 的数据,但观察到硬盘的写入是 30MB,那么写放大就是 3。所以对于写入压力比较大的应用来说,我们要做的就是尽量减小写放大。写放大能通过 RocksDB 自己的统计看到。
  • Read amplification - 读放大,对于一个 query 需要读取硬盘的次数。譬如一个 query 我们读取了 5 pages,那么读放大就是 5。读放大没法通过 RocksDB 自己的统计很好的查看,通常会通过 iostat 等命令进行评估。
  • Space amplification - 空间放大,这个比较好理解,假设我需要存储 10MB 的数据,但实际硬盘占用了 30MB,那么空间放大就是 3。

RocksDB Statistics

在实际调优 RocksDB 的时候,我们用的最多的就是 RocksDB 自己的统计信息,RocksDB 自己有一个 stats_dump_period_sec 参数,可以定期的将统计刷到 RocksDB 自己的 LOG 文件里面。当然,我们也可以直接通过 db->GetProperty("rocksdb.stats") 以及 options.statistics.ToString() 在程序里面直接得到相关的统计信息。

对于 TiKV 来说,现阶段我们使用了 4 个 Column Family,所以统计如下:

** Compaction Stats [default] **
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} KeyIn KeyDrop
----------------------------------------------------------------------------------------------------------------------------------------------------------
  L0      0/0       0.00   0.0      0.0     0.0      0.0      98.5     98.5       0.0   0.0      0.0    205.4       491      1089    0.451       0      0
  L1      5/0     128.68   1.1    127.7    98.7     29.0     120.0     91.0       0.0   1.2    179.1    168.3       730       269    2.715    875M   105M
  L2     98/0    1381.58   1.2    176.2    91.0     85.2     120.8     35.6       0.0   1.3     18.8     12.9      9624      2904    3.314   1588M  6900K
  L3    472/0   12650.65   1.0     97.3     8.5     88.7      96.2      7.5      26.9  11.3     12.7     12.6      7841       571   13.732   1109M    17M
  L4   3228/0   98210.34   0.8    145.3     9.0    136.4     133.8     -2.6      25.6  14.9     12.9     11.9     11502       687   16.742   1775M   392M
 Sum   3803/0   112371.25   0.0    546.5   207.2    339.3     569.4    230.1      52.5   5.8     18.5     19.3     30189      5520    5.469   5350M   523M
 Int      0/0       0.00   0.0      3.7     2.1      1.6       3.7      2.1       0.4   4.8     24.3     24.3       157        50    3.134     34M  4871K
Uptime(secs): 70217.9 total, 70217.9 interval
Flush(GB): cumulative 98.538, interval 0.775
AddFile(GB): cumulative 0.000, interval 0.000
AddFile(Total Files): cumulative 0, interval 0
AddFile(L0 Files): cumulative 0, interval 0
AddFile(Keys): cumulative 0, interval 0
Cumulative compaction: 569.35 GB write, 8.30 MB/s write, 546.53 GB read, 7.97 MB/s read, 30189.2 seconds
Interval compaction: 3.73 GB write, 0.05 MB/s write, 3.72 GB read, 0.05 MB/s read, 156.7 seconds
Stalls(count): 0 level0_slowdown, 0 level0_slowdown_with_compaction, 0 level0_numfiles, 0 level0_numfiles_with_compaction, 0 stop for pending_compaction_bytes, 0 slowdown for pending_compaction_bytes, 0 memtable_compaction, 0 memtable_slowdown, interval 0 total count

** Compaction Stats [raft] **
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} KeyIn KeyDrop
----------------------------------------------------------------------------------------------------------------------------------------------------------
  L0      1/0     102.02   0.2      0.0     0.0      0.0     866.7    866.7       0.0   0.0      0.0    440.3      2016      9404    0.214       0      0
  L1      4/0      96.85  19.9    974.5   866.6    107.9     331.6    223.8       0.0   0.4    703.6    239.4      1418      1923    0.738    741M   197M
  L2      7/3      24.49   0.5    339.3   223.7    115.5     130.4     14.9       0.0   0.6     30.0     11.5     11563      7513    1.539    694M    37M
  L3    185/77   5793.93   0.3   1180.5    13.8   1166.7    1171.3      4.6       1.0  84.7     12.0     11.9    100814      1760   57.280    602M   266M
 Sum    197/80   6017.28   0.0   2494.3  1104.2   1390.1    2500.1   1109.9       1.0   2.9     22.1     22.1    115810     20600    5.622   2038M   500M
 Int      0/0       0.00   0.0     32.2     9.4     22.8      32.0      9.2       0.0   4.3     16.7     16.5      1979       181   10.931     26M  7633K
Uptime(secs): 70217.9 total, 70217.9 interval
Flush(GB): cumulative 866.720, interval 7.361
AddFile(GB): cumulative 0.000, interval 0.000
AddFile(Total Files): cumulative 0, interval 0
AddFile(L0 Files): cumulative 0, interval 0
AddFile(Keys): cumulative 0, interval 0
Cumulative compaction: 2500.08 GB write, 36.46 MB/s write, 2494.33 GB read, 36.38 MB/s read, 115810.5 seconds
Interval compaction: 31.96 GB write, 0.47 MB/s write, 32.17 GB read, 0.47 MB/s read, 1978.5 seconds
Stalls(count): 0 level0_slowdown, 0 level0_slowdown_with_compaction, 0 level0_numfiles, 0 level0_numfiles_with_compaction, 0 stop for pending_compaction_bytes, 0 slowdown for pending_compaction_bytes, 0 memtable_compaction, 0 memtable_slowdown, interval 0 total count

** DB Stats **
Uptime(secs): 70217.9 total, 600.1 interval
Cumulative writes: 305M writes, 13G keys, 303M commit groups, 1.0 writes per commit group, ingest: 2090.72 GB, 30.49 MB/s
Cumulative WAL: 305M writes, 0 syncs, 305710569.00 writes per sync, written: 2090.72 GB, 30.49 MB/s
Cumulative stall: 00:03:12.944 H:M:S, 0.3 percent
Interval writes: 3971K writes, 124M keys, 3943K commit groups, 1.0 writes per commit group, ingest: 18679.94 MB, 31.13 MB/s
Interval WAL: 3971K writes, 0 syncs, 3971919.00 writes per sync, written: 18.24 MB, 31.13 MB/s
Interval stall: 00:00:0.000 H:M:S, 0.0 percent

上面因为统计量比较大,我们只输出了 default 和 raft 两个 CF compaction 的统计,以及整个 DB 的统计。

Compaction stats

Compaction stats 就是在 level N 和 N + 1 层做 compaction 的统计,在 N + 1 层输出结果。

  • Level:也就是 LSM 的 level,Sum 表示的是所有 level 的总和,而 Int 则表示从上一次 stats 到现在的数据。
  • Files:有两个值 a/b,a 用来表示当前 level 有多少文件,而 b 则用来表示当前用多少个线程正在对这层 level 做 compaction。
  • Size(MB}:当前 level 总共多大,用 MB 表示。
  • Score:除开 level 0,其他几层的 score 都是通过 (current level size) / (max level size) 来计算,通常 0 和 1 是正常的,但如果大于 1 了,表明这层 level 就需要做 compaction 了。对于 level 0,我们通过 (current number of files) / (file number compaction trigger) 来计算。
  • Read(GB}:对 level N 和 N + 1 做 compaction 的时候总的读取数据量
  • Rn(GB}:对 level N 和 N + 1 做 compaction 的时候从 level N 读取的数据量
  • Rnp1(GB}:对 level N 和 N + 1 做 compaction 的时候从 level N + 1读取的数据量
  • Write(GB}:对 level N 和 N + 1 做 compaction 的时候总的写入数据量
  • Wnew(GB}:新写入 level N + 1 的数据量,使用 (total bytes written to N+1) - (bytes read from N+1 during compaction with level N)
  • Moved(GB}:直接移动到 level N + 1 的数据量。这里仅仅只会更新 manifest,并没有其他 IO 操作,表明之前在 level X 的文件现在在 level Y 了。
  • W-Amp:从 level N 到 N + 1 的写放大,使用 (total bytes written to level N+1) / (total bytes read from level N) 计算。
  • Rd(MB/s}:在 level N 到 N + 1 做 compaction 的时候读取速度。使用 Read(GB) * 1024 / duration 计算,duration 就是从 N 到 N + 1 compaction 的时间。
  • Wr(MB/s}:在 level N 到 N + 1 做 compaction 的时候写入速度,类似 Rd(MB/s)
  • Comp(sec}:在 level N 到 N + 1 做 compaction 的总的时间。
  • Comp(cnt}:在 level N 到 N + 1 做 compaction 的总的次数。
  • Avg(sec}:在 level N 到 N + 1 做 compaction 平均时间。
  • KeyIn:在 level N 到 N + 1 做 compaction 的时候比较的 record 的数量
  • KeyDrop:在 level N 到 N + 1 做 compaction 的时候直接丢弃的 record 的数量

具体相关的计算可以参考 RocksDB internal_stats.cc 里面的 PrintLevelStats 函数。

紧跟着 Compaction 的各个 Level 的统计,是这个 CF 这次 compaction 的一些汇总统计。Cumulative 是到现在为止累加的统计,Interval 则是从上一次统计到现在的变更数据。这里不做过多说明,重点关注的是

Stalls(count): 0 level0_slowdown, 0 level0_slowdown_with_compaction, 0 level0_numfiles, 0 level0_numfiles_with_compaction, 0 stop for pending_compaction_bytes, 0 slowdown for pending_compaction_bytes, 0 memtable_compaction, 0 memtable_slowdown, interval 0 total count

如果出现了 Stall,就表明外面写入的压力太大,RocksDB compaction 不及时,这样就会开始阻塞写入了。

DB Stats

除了不同 CF 的各个 level 的 compaction stats,我们也会得到一个总的汇总的统计,主要关注:

  • Uptime:从启动到现在的时间
  • writes:
    • writes - 总的写入次数
    • keys - 总的写入 key 的数量
    • commit groups - 总的 group 提交的数量
    • writes per commit group - 每个 group 提交包含的写入次数
    • ingest - 直接 ingest 到 DB 的数量
    • MB/s - 写入的速度
  • WAL:
    • writes - 总的写入次数
    • syncs - 强制 sync 的次数
    • writes - 每次 sync 有多少次写入
    • written - 总的写入数据量
    • MB/s - 写入的速度
  • stall:
    • H:M:S - 总的 stall 的时间
    • percent - stall 的时间在总时间的比例

More statistics

除了上面的 statistics,RocksDB 还提供了一个更加细粒度的 statistics,我们需要手动 options.statistics = rocksdb::CreateDBStatistics() 打开,但它会影响性能。根据 RocksDB 官方的文档,打开这个 statistics 会损失 5-10% 的性能,但 TiKV 这边实测其实没到,所以我们默认是打开的。

通过 statistics,我们可以观察更多的统计信息,譬如每层 level 的读数据延迟:

** Level 0 read latency histogram (micros):
Count: 3834542 Average: 19.1113  StdDev: 143.36
Min: 0  Median: 13.6954  Max: 58656
Percentiles: P50: 13.70 P75: 16.70 P99: 42.01 P99.9: 838.63 P99.99: 6676.77

上面就是对于 level 0 的读取延迟 histogram 统计,看一看到读取的次数,瓶颈的时间,标准方差等。

然后还有 cache 的一些统计,譬如:

rocksdb.block.cache.miss COUNT : 349550104
rocksdb.block.cache.hit COUNT : 11172137213

上面表示 cache 总共 miss 了多少次,hit 了多少次。

当然还有 stall 的相关统计:

rocksdb.stall.micros COUNT : 192944077
rocksdb.db.write.stall statistics Percentiles :=> 50 : 0.825706 95 : 4683.057851 99 : 29772.380952

上面表示 stall 总的时间,以及 histogram。

在 TiKV 里面,我们通过 statistics 相关的接口,取出相关的数据,将其发送给 Prometheus,这样我们就能通过 Prometheus 来监控 RockSB 了。

小结

通常上面的 statistics,我们其实还不能确定某一个操作慢到底是怎么导致的。譬如我们 seek 某一个 key,但发现时间非常长,这时候我们就可以通过 Perf Context and IO Stats Context对一个操作进行分析,但实际对于一个运行的服务器程序,这种方式并不方便,所以在 TiKV 中我们并没有使用,但不排除以后也会研究,以及通过 tracing 接口显示的对一些操作打开。

在 TiKV 中,我们定时 10 分钟会将 Statistics 输出,同时也支持将 Statistics 及时的输出到 TiKV 自己的 LOG 里面供我们分析性能瓶颈。很多时候,我们不可能一次在不同的机器上面将 RocksDB 的参数配对,所以我们都是首先根据机器性能评估一个可用配置,然后在实际测试,通过 Statistics 以及系统其他的指标来动态调优的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容