独家|rocksdb compaction限速实践与源码剖析

导语: 磁盘IO利用率是研讨存储的同学十分重视的政策,本文介绍了58存储团队在运用rocksdb时针对IO毛刺场景的调优实践,剖析了rocksdb compaction限速部分的源码,经过调优,有效地削减IO毛刺,削减对实时读写的影响。

布景
58存储团队自研的分布式KV存储产品WTable选用的存储引擎是开源的rocksdb。rocksdb是LSM Tree的存储结构,在后台进行compaction。

在实践过程中发现,当事务方写入数据量较大,会触发许多的compaction操作,占用较高的IO资源,乃至导致IO 100%,呈现IO毛刺,导致实时读写央求推迟变高乃至超时。

本文首要对rocksdb compaction限速部分的源码做多元化的剖析,然后介绍WTable在实践中针对IO毛刺场景的调优。

一、源码剖析
rocksdb是经过RateLimter类来完毕限速功用。RateLimiter有五个参数:
ratebytespersec:每秒flush和compaction的总限速阈值;
refillperiodus:补偿token的周期,默以为100ms;
fairness:低优先级央求(compaction)相较高优先级央求(flush)获取token的概率,默以为10;
mode:三个枚举值,读、写、读写,默许是对写央求进行限速;
autotuned:是否翻开autotune,默以为不翻开。
在一般的rate limiter(autotuned=false)中,token是依照周期分配的,每个周期=refillperiodus,默许值为100ms,则每个周期能分配的token=ratebytespersec100ms/(1000ms)。全局变量availablebytes初始值即为每个周期能分配的token值。央求token时,假定央求的bytes小于availablebytes,直接分配成功并削减相应的availablebytes;假定央求的bytes大于availablebytes,央求进入等候部队,如下图所示,有低优先级央求(low pri)和高优先级央求(high pri)两个待分配token的等候部队,假定每个央求所需的bytes值均为20MB:
独家|rocksdb compaction限速实践与源码剖析

经过竞赛,选出一个仅有的leader,非leader的央求进入等候状况;仅有的leader经过变量numdrains记载因availablebytes耗尽而导致等候的周期数量,并等候当时的周期完毕,进行refill token操作。

经过上述的流程能够正常的看到,仅有leader央求的线程才调进行refill token操作。在refill流程中,首要更新availablebytes值。并依照fairness概率将token次序分配给两个部队中等候的央求,low pri queue部队优先取得token分配的概率为1/fairness。每次分配均会削减相应的availablebytes,将对应的央求移出等候部队,并引发等候的非leader线程成功回来,直至部队清空或availablebytes耗尽。refill流程回来后,需从头竞选leader,新的leader可所以未被分配满意token的旧leader、部队头部未分配token的一般央求(high pri queue头部央求优先)、新来的央求。

假定refill之后,availablebytes更新为50M,而且依照概率选取从high pri queue开始分配token,前两个央求满意条件,分配之后被移出等候部队,availablebytes此刻仅剩10M,不满意下一个央求所需的token值,refill流程完毕,从头竞选leader,等候下一次refill流程,如下图所示:
独家|rocksdb compaction限速实践与源码剖析

autotune rate limiter在一般rate limiter的基础上,增加了动态调整限速阈值的功用,此刻,参数ratebytespersec的意义是限速的上限值。每100个refillperiodus周期调整一次限速阈值,调整的区间为[ratebytespersec/20, ratebytespersec],调整的依据是曾经100个周期的因availablebytes耗尽而导致等候的周期的比率(numdrains差值/100 100%),当这个比率低于低水位(50%),限速阈值下降1.05倍,当比率高于高水位(90%),限速阈值上升1.05倍,在凹凸水位之间,限速阈值不变,假定没有因availablebytes耗尽而导致等候的周期,则限速阈值直接设定为下限值ratebytespersec/20。

二、限速实践
1、一般限速
在初期的实践中,WTable并没有运用autotune方法的rate limiter,仅考虑第一个参数,其他运用默许值。针对某一集群,存在许多离线导入的状况,网卡的流入量如下图所示:
独家|rocksdb compaction限速实践与源码剖析

因为写入量较大,rocksdb会生成许多新的sst文件,有必要进行许多的compaction,当不进行限速时,常常会呈现IO毛刺的状况,如下图所示:
独家|rocksdb compaction限速实践与源码剖析

为此,针对该事务的写入场景,进行试验,设定ratebytespersec为250MB时,io毛刺得到显着改进,如下图所示,IO最高在50%左右。
独家|rocksdb compaction限速实践与源码剖析

2、auto tune限速
上述设定ratebytespersec为250MB是针对特定集群的试验经验值,并不具有通用性。当事务方的写入量更大时,因为限速的原因,rocksdb会呈现write stall的状况,这对在线读写事务是不能承受的。每个集群都设定一个特定的限速阈值不太实践,也不行通用,为此,进一步查验auto tune方法的限速,期望能在不同集群中运用一套装备。

当翻开auto tune(参数autotuned=true)时,参数ratebytespersec的意义是限速的上限值,官方给的参考值是尽量大。

一开始,设定ratebytespersec为2000MB,可是发现并没有起到限速的效果,经过上述的源码剖析,发现限速阈值的调整的区间为[ratebytespersec/20, ratebytespersec],
因而当ratebytespersec太大时,限速阈值的下限值仍较大,并不能起到真实的限速效果。在后续的实践中,将ratebytespersec设定为1000M,此刻的下限值为50M,既能起到限速的效果,处理了io毛刺的问题,又能动态调整限速阈值,防止write stall。这是一个较为通用的装备,在多种写入场景下均可运用,便利安顿运维。
其他
rocksdb的参数十分之多,咱们咱们咱们能够从另一个视点来考虑io毛刺的问题:削减compaction次数。比方,装备sst文件大一些,能够某些特定的程度削减compaction的次数,可是compaction不及时也会引起老的数据不能及时铲除,导致空间扩展,这就需求依据事务方的场景进行取舍了。

其他,咱们也在查验经过直接向rocksdb刺进sst文件的方法来减轻许多离线导入对实时读写的影响,敬请期待!

参考文献:https://github.com/facebook/rocksdb/wiki

作者:江守超,58集团高档存储工程师,担任分布式KV存储系统WTable开发与优化。

独家|rocksdb compaction限速实践与源码剖析