iis8.5限速没有效果怎么回事_独家| rocksdb compaction限速实践与源码分析

b5dafce29800cf1e073214936772b67b.png 0bd104225e4486af0cb0d333ae42205b.gif

导语: 磁盘IO利用率是研究存储的同学十分关注的指标,本文介绍了58存储团队在使用rocksdb时针对IO毛刺场景的调优实践,分析了rocksdb compaction限速部分的源码,通过调优,有效地减少IO毛刺,减少对实时读写的影响。

e5c1a61fa2f45d86c6562ac70a90b3a6.gif

背景

58存储团队自研的分布式KV存储产品WTable采用的存储引擎是开源的rocksdb。 rocksdb是LSMTree的存储结构,在后台进行compaction。 在实践过程中发现,当业务方写入数据量较大,会触发大量的compaction操作,占用较高的IO资源,甚至导致IO 100%,出现IO毛刺,导致实时读写请求延迟变高甚至超时。 本文首先对rocksdb compaction限速部分的源码进行分析,然后介绍WTable在实践中针对IO毛刺场景的调优 。

源码分析

rocksdb是通过RateLimter类来实现限速功能。 RateLimiter有五个参数: rate_bytes_per_sec:每秒flush和compaction的总限速阈值; refill_period_us:补充token的周期,默认为100ms; fairness:低优先级请求(compaction)相较高优先级请求(flush)获取token的概率,默认为10; mode:三个枚举值,读、写、读写,默认是对写请求进行限速; auto_tuned:是否开启auto_tune,默认为不开启。

在普通的rate limiter(auto_tuned=false)中,token是按照周期分配的,每个周期=refill_period_us,默认值为100ms,则每个周期能分配的token=rate_bytes_per_sec*100ms/(1000ms)。全局变量available_bytes_初始值即为每个周期能分配的token值。请求token时,如果请求的bytes小于available_bytes_,直接分配成功并减少相应的available_bytes_;如果请求的bytes大于available_bytes_,请求进入等待队列,如下图所示,有低优先级请求(lowpri)和高优先级请求(high pri)两个待分配token的等待队列,假定每个请求所需的bytes值均为20MB:

b07828026516f49e9315aa4822b2b261.png

通过竞争,选出一个唯一的leader_,非leader的请求进入等待状态;唯一的leader_通过变量num_drains_记录因available_bytes_耗尽而导致等待的周期数量,并等待当前的周期结束,进行refilltoken操作。 通过上述的流程可以看到,仅有leader_请求的线程才能进行refill token操作。在refill流程中,首先更新available_bytes_值。并按照fairness概率将token顺序分配给两个队列中等待的请求,low pri queue队列优先获得token分配的概率为1/fairness。每次分配均会减少相应的available_bytes_,将对应的请求移出等待队列,并唤起等待的非leader_线程成功返回,直至队列清空或available_bytes_耗尽。refill流程返回后,需重新竞选leader_,新的leader_可以是未被分配足够token的旧leader_、队列头部未分配token的普通请求(high pri queue头部请求优先)、新来的请求。 假设refill之后,available_bytes_更新为50M,并且按照概率选取从high pri queue开始分配token,前两个请求满足条件,分配之后被移出等待队列,available_bytes_此时仅剩10M,不满足下一个请求所需的token值,refill流程结束,重新竞选leader_,等待下一次refill流程,如下图所示:

f630aaed4d7368a07d3c1570975540d3.png

auto_tune rate limiter在普通rate limiter的基础上,增加了动态调整限速阈值的功能,此时,参数rate_bytes_per_sec的含义是限速的上限值。每100个refill_period_us周期调整一次限速阈值,调整的区间为[rate_bytes_per_sec/20,rate_bytes_per_sec],调整的依据是过去100个周期的因available_bytes_耗尽而导致等待的周期的比率(num_drains_差值/100 *100%),当这个比率低于低水位(50%),限速阈值降低1.05倍,当比率高于高水位(90%),限速阈值上升1.05倍,在高低水位之间,限速阈值不变,如果没有因available_bytes_耗尽而导致等待的周期,则限速阈值直接设定为下限值rate_bytes_per_sec/20。

限速实践

1.普通限速   在初期的实践中,WTable并没有使用auto_tune模式的rate limiter,仅考虑第一个参数,其他使用默认值。针对某一集群,存在大量离线导入的情况,网卡的流入量如下图所示:

4e1682c1237cc4ffc2b904d660d8b5c8.png

由于写入量较大,rocksdb会生成很多新的sst文件,需要进行大量的compaction,当不进行限速时,经常会出现IO毛刺的情况,如下图所示:

906ead4fa7e7cc485ada4bcd6d2b9924.png

为此,针对该业务的写入场景,进行试验,设定rate_bytes_per_sec为250MB时,io毛刺得到明显改善,如下图所示,IO最高在50%左右。  

afbb8ac0cb6d5697e5ff761dd0ff8236.png

2.auto tune限速 上述设定rate_bytes_per_sec为250MB是针对特定集群的实验经验值,并不具备通用性。当业务方的写入量更大时,由于限速的缘故,rocksdb会出现write stall的情况,这对在线读写业务是不能接受的。每个集群都设定一个特定的限速阈值不太现实,也不够通用,为此,进一步测试auto tune方式的限速,希望能在不同集群中使用一套配置。 当开启auto tune(参数auto_tuned=true)时,参数rate_bytes_per_sec的含义是限速的上限值,官方给的参考值是尽量大。   一开始,设定rate_bytes_per_sec为2000MB,但是发现并没有起到限速的效果,通过上述的源码分析,发现限速阈值的调整的区间为[rate_bytes_per_sec/20, rate_bytes_per_sec], 因此当rate_bytes_per_sec太大时,限速阈值的下限值仍较大,并不能起到真正的限速作用。在后续的实践中,将rate_bytes_per_sec设定为1000M,此时的下限值为50M,既能起到限速的作用,解决了io毛刺的问题,又能动态调整限速阈值,避免write stall。这是一个较为通用的配置,在多种写入场景下均可使用,方便部署运维。

其他

rocksdb的参数非常之多,我们可以从另一个角度来考虑io毛刺的问题:减少compaction次数。比如,配置sst文件大一些,可以一定程度减少compaction的次数,但是compaction不及时也会引起老的数据不能及时清除,导致空间放大,这就需要根据业务方的场景进行取舍了。 另外,我们也在尝试通过直接向rocksdb插入sst文件的方式来减轻大量离线导入对实时读写的影响,敬请期待! 参考文献: https://github.com/facebook/rocksdb/wiki 作者简介: 江守超,58集团高级存储工程师,负责分布式KV存储系统WTable开发与优化。

END

相关推荐: 独家|一文了解58安全画像系统演进之路 独家|58同城实时计算平台架构实践 独家|前端高性能队列应用实践探秘 7bfced3300321c7c2b0df786cf4818fb.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值