这次的项目我们重点关注RocksDB中的一个环节:Rate Limiter。其实Rate Limiter的思想在很多其他系统中也很常用。

在RocksDB中,后台会实时运行compaction和flush操作,这些都会对磁盘进行大量的写操作。可以通过Rate Limiter来控制最大写入速度的上限。因为在某些场景下,突发的大量写入会导致很大的read latency,从而影响系统性能。

Rate Limiter的基本原理是令牌桶算法:系统每秒往桶里丢数量为1/QPS的令牌(满了为止),写请求只有拿到了令牌才能处理。当桶里没有令牌时便可拒绝服务(阻塞)。它在RocksDB中的实现可以参考这里

Rate Limiter中可以调节的有以下几个参数

  • int64_t rate_bytes_per_sec:控制 compaction 和 flush 每秒总写入量的上限。一般情况下只需要调节这一个参数。
  • int64_t refill_period_us:控制 tokens 多久再次填满,譬如 rate_limit_bytes_per_sec 是 10MB/s,而 refill_period_us 是 100ms,那么每 100ms 的流量就是 1MB/s。
  • int32_t fairness:用来控制 high 和 low priority 的请求,防止 low priority 的请求饿死。

更详细的介绍可以直接看rate_limiter.h:

 // Create a RateLimiter object, which can be shared among RocksDB instances to control write rate of flush and compaction.
// @rate_bytes_per_sec: this is the only parameter you want to set most of the time. It controls the total write rate of compaction and flush in bytes per second. Currently, RocksDB does not enforce rate limit for anything other than flush and compaction, e.g. write to WAL.
// @refill_period_us: this controls how often tokens are refilled. For example, when rate_bytes_per_sec is set to 10MB/s and refill_period_us is set to 100ms, then 1MB is refilled every 100ms internally. Larger value can lead to burstier writes while smaller value introduces more CPU overhead. The default should work for most cases.
// @fairness: RateLimiter accepts high-pri requests and low-pri requests. A low-pri request is usually blocked in favor of hi-pri request. Currently, RocksDB assigns low-pri to request from compaction and high-pri to request from flush. Low-pri requests can get blocked if flush requests come in continuously. This fairness parameter grants low-pri requests permission by 1/fairness chance even though high-pri requests exist to avoid starvation. You should be good by leaving it at default 10.
// @mode: Mode indicates which types of operations count against the limit.
// @auto_tuned: Enables dynamic adjustment of rate limit within the range `[rate_bytes_per_sec / 20, rate_bytes_per_sec]`, according to the recent demand for background I/O.
extern RateLimiter* NewGenericRateLimiter(
int64_t rate_bytes_per_sec, int64_t refill_period_us = * ,
int32_t fairness = ,
RateLimiter::Mode mode = RateLimiter::Mode::kWritesOnly,
bool auto_tuned = false); } // namespace rocksdb

这里有个bool auto_tuned,这是RocksDB中带的一个Auto tune Rate Limiter的模块。因为这个rate_bytes_per_sec(写入速度的上限)是很难手动调节的,太大了没效果,太小了又会导致大量写操作无法继续。所以RocksDB提供了这个模块来自动调节。当开启这个模块时,参数rate_bytes_per_sec的含义就变成了定义写入速度上限的上限(In this case rate_bytes_per_sec will indicate the upper-bound of the window within which a rate limit will be picked dynamically.)。之后这个auto tuner会周期性监测I/O写入量,并相应增大/减小写入量上限的值(重新设置rate_bytes_per_sec_和refill_bytes_per_period_)。这里的benchmark显示Auto-tune Rate Limiter可以有效减少write突然增加的程度。


Rate Limiter的用法

可以通过NewGenericRateLimiter类来新建一个Rate Limiter。可以对每个RocksDB实例单独搞一个,也可以让所有实例共享一个来control the aggregated write rate of flush and compaction。

 RateLimiter* rate_limiter = NewGenericRateLimiter(
rate_bytes_per_sec /* int64_t */,
refill_period_us /* int64_t */,
fairness /* int32_t */);

这里面三个参数的含义上面介绍过啦。

Although tokens are refilled with a certain interval set by refill_period_us, the maximum bytes that can be granted in a single burst have to be bounded since we are not happy to see that tokens are accumulated for a long time and then consumed by a single burst request which definitely does not agree with our intention. GetSingleBurstBytes() returns this upper bound of tokens.

使用时,在每次写请求之前,都要申请token。如果当前请求无法满足(也就是被限速了),请求就会被阻塞,直到token被填充到足够完成请求。

 // block if tokens are not enough
rate_limiter->Request( /* bytes */, rocksdb::Env::IO_HIGH); // perform a write operation
Status s = db->Flush();

在运行过程中,也可以通过 SetBytesPerSecond(int64_t bytes_per_second) 动态修改Rate Limiter的流量。

Ref:

https://rocksdb.org.cn/doc/Rate-Limiter.html

https://github.com/facebook/rocksdb/wiki/Rate-Limiter

https://www.cnblogs.com/cchust/p/6007486.html

https://github.com/facebook/rocksdb/wiki/Statistics

RocksDB Compaction:

https://rimzy.net/category/graphs/

http://yinqiwen.github.io/Ardb/2014/09/13/ardb-practice.html

https://www.reddit.com/r/IAmA/comments/3de3cv/we_are_rocksdb_engineering_team_ask_us_anything/

https://www.cnblogs.com/pdev/p/11277784.html

http://mysql.taobao.org/monthly/2018/11/05/

http://mysql.taobao.org/monthly/2018/12/08/

https://github.com/facebook/rocksdb/wiki/Basic-Operations

..

RocksDB Rate Limiter源码解析的更多相关文章

  1. kube-proxy源码解析

    kubernetes离线安装包,仅需三步 kube-proxy源码解析 ipvs相对于iptables模式具备较高的性能与稳定性, 本文讲以此模式的源码解析为主,如果想去了解iptables模式的原理 ...

  2. Theano:LSTM源码解析

    最难读的Theano代码 这份LSTM代码的作者,感觉和前面Tutorial代码作者不是同一个人.对于Theano.Python的手法使用得非常娴熟. 尤其是在两重并行设计上: ①LSTM各个门之间并 ...

  3. OKHttp源码解析

    http://frodoking.github.io/2015/03/12/android-okhttp/ Android为我们提供了两种HTTP交互的方式:HttpURLConnection 和 A ...

  4. 第三十六节,目标检测之yolo源码解析

    在一个月前,我就已经介绍了yolo目标检测的原理,后来也把tensorflow实现代码仔细看了一遍.但是由于这个暑假事情比较大,就一直搁浅了下来,趁今天有时间,就把源码解析一下.关于yolo目标检测的 ...

  5. TiKV 源码解析系列 - Raft 的优化

    本系列文章主要面向 TiKV 社区开发者,重点介绍 TiKV 的系统架构,源码结构,流程解析.目的是使得开发者阅读之后,能对 TiKV 项目有一个初步了解,更好的参与进入 TiKV 的开发中.本文是本 ...

  6. can-utils源码解析cansend

    前言 本文主要介绍socketCan中的发送函数cansend的源码解析. 代码 /* * cansend.c - simple command line tool to send CAN-frame ...

  7. [源码解析] Flink UDAF 背后做了什么

    [源码解析] Flink UDAF 背后做了什么 目录 [源码解析] Flink UDAF 背后做了什么 0x00 摘要 0x01 概念 1.1 概念 1.2 疑问 1.3 UDAF示例代码 0x02 ...

  8. [源码解析] 并行分布式框架 Celery 之架构 (2)

    [源码解析] 并行分布式框架 Celery 之架构 (2) 目录 [源码解析] 并行分布式框架 Celery 之架构 (2) 0x00 摘要 0x01 上文回顾 0x02 worker的思考 2.1 ...

  9. [源码解析] 并行分布式框架 Celery 之 worker 启动 (2)

    [源码解析] 并行分布式框架 Celery 之 worker 启动 (2) 目录 [源码解析] 并行分布式框架 Celery 之 worker 启动 (2) 0x00 摘要 0x01 前文回顾 0x2 ...

随机推荐

  1. BZOJ 2217: [Poi2011]Lollipop 构造 + 思维

    Description 有一个长度为n的序列a1,a2,...,an.其中ai要么是1("W"),要么是2("T").现在有m个询问,每个询问是询问有没有一个连 ...

  2. Devexpress MVC Gridview 获取到增删改的所有行数据(JSON) 并使用SQL事物保存数据

    //ModalChargeGridView Gridview的名字//Con_Shp_Chg 数据库表名//ConShpChgUID UID或者是标识列//gs_Language 语言(中英文)//l ...

  3. Vue(核心思想)

    1.Es6语法普及 let和var的区别: var:定义变量时,在全局范围内都有效;所以在变量没有声明之前就能使用,值为undefined, 称为变量提升; let:声明的变量一定要在声明后使用,而且 ...

  4. 二分类算法的评价指标:准确率、精准率、召回率、混淆矩阵、AUC

    评价指标是针对同样的数据,输入不同的算法,或者输入相同的算法但参数不同而给出这个算法或者参数好坏的定量指标. 以下为了方便讲解,都以二分类问题为前提进行介绍,其实多分类问题下这些概念都可以得到推广. ...

  5. sed将一个文件插入到另一个文件(合并两个文件)

    将before.sh的内容插入到catalina.sh的第一行之后 sed -i '1r /srv/tomcat8/bin/before.sh' /srv/tomcat8/bin/catalina.s ...

  6. ps 和 pstree的用法

    ps 查看某个具体的命令进程: ps -C cmd-name: 如: ps -C httpd // 如果有多个名字相同的进程, 如httpd... 应该是它下面的子进程, 这时会显示第一个进程id. ...

  7. 四、IDEA创建SpringBoot项目

    1.从官网下载之后直接导入IDEA: 下载完成解压之后如下图: IDEA导入该项目: 之后一路next即可 导入成功之后你可能会发现左下角一直有个进度条在进行,傻傻的同学可能以为是在下载jar包,下个 ...

  8. 写入mongodb

    https://blog.csdn.net/u013421629/article/details/78885079 https://www.jianshu.com/p/7d14c3ad810f  可视 ...

  9. Octavia 创建 Listener、Pool、Member、L7policy、L7 rule 与 Health Manager 的实现与分析

    目录 文章目录 目录 创建 Listener 创建 Pool 创建 Member CalculateDelta HandleNetworkDeltas AmphoraePostNetworkPlug ...

  10. Visual Studio Code 折叠代码快捷键

    为了快速阅读不熟悉的代码, 最好可以打开一个文件能先将具体实现折叠起来的,进行一个大概的认识,vscode中有这些折叠快捷键: ctrl+shift+[是折叠 ctrl+k ctrl+0 是折叠全部 ...