其他
独家| rocksdb compaction限速实践与源码分析
导语: 磁盘IO利用率是研究存储的同学十分关注的指标,本文介绍了58存储团队在使用rocksdb时针对IO毛刺场景的调优实践,分析了rocksdb compaction限速部分的源码,通过调优,有效地减少IO毛刺,减少对实时读写的影响。
背景
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:
限速实践
1.普通限速 在初期的实践中,WTable并没有使用auto_tune模式的rate limiter,仅考虑第一个参数,其他使用默认值。针对某一集群,存在大量离线导入的情况,网卡的流入量如下图所示: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同城实时计算平台架构实践
独家|前端高性能队列应用实践探秘