「GoCN酷Go推荐」漏桶限流库 — uber-go/ratelimit
上次有同学分享了 单机限流器 time/rate 库,讲了 Golang 标准库中基于令牌桶实现限流组件的 time/rate
使用,同时也讲了一些限流算法原理。
这里分享一个 uber 开源的一套基于漏桶实现的用于服务限流的 golang 库 ratelimit。
漏洞算法的理解起来,相较于令牌桶,没有那么直观。因为令牌桶是限制 “令牌” 的速率,拿到令牌的请求才能被放行,而漏桶是限制单位时间内允许通过的请求数目,调用方只能严格按照预定的间隔顺序进行消费调用。
1
ratelimit 的基本使用
官方示例:
import ("fmt""time""go.uber.org/ratelimit"
)func main() {rl := ratelimit.New(100) // per secondprev := time.Now()for i := 0; i < 10; i++ {now := rl.Take()fmt.Println(i, now.Sub(prev))prev = now}
}
在这个例子中,我们给定限流器每秒可以通过 100 个请求,也就是平均每个请求间隔 10ms。因此,最终会每 10ms 打印一行数据。输出结果如下:
// Output:
// 0 0
// 1 10ms
// 2 10ms
// 3 10ms
// 4 10ms
// 5 10ms
// 6 10ms
// 7 10ms
// 8 10ms
// 9 10ms
2
高级用法
最大松弛量
传统的漏桶,每个请求的间隔是固定、匀速的,两次请求 req1 和 req2 之间的延迟至少应该 >=perRequest,然而,在实际上的应用中,流量经常是突发性的。对于突发这种情况,uber-go 对 Leaky Bucket 做了一些改良,引入了最大松弛量(maxSlack)的概念, 表示允许抵消的最长时间
漏桶算法的限速逻辑:
sleepFor = t.perRequest - now.Sub(t.last)
if sleepFor > 0 {t.clock.Sleep(sleepFor)t.last = now.Add(sleepFor)
} else {t.last = now
}
上面计算 sleepFor 的代码,不使用最大松弛量的 sleep 逻辑,严格要求两个请求之间必须间隔 t.perRequest
的时间,那么计算 sleepFor
的代码就是:
t.sleepFor = t.perRequest - now.Sub(t.last)
这样就会有以下问题:
我们假设现在有三个请求,req1
、req2
和 req3
,限速区间为 10ms
。req1
最先到来,当 req1
完成之后 15ms
,req2
才到来,依据限速策略可以对 req2
立即处理,当 req2
完成后,5ms
后, req3
到来,这个时候距离上次请求还不足 10ms
,因此还需要等待 5ms
才能继续执行, 但是,对于这种情况,实际上这三个请求一共消耗了 25ms
才完成,并不是预期的 20ms
。
上面这个 case 模拟了一种请求量突发的状况。但这里我们可以把之前间隔比较长的请求的时间(累加超出 perRequest
的时延),匀给后面的请求判断限流时使用。对于上面的 case,因为 req2
相当于多等了 5ms
,我们可以把这 5ms
移给 req3
使用。加上 req3
本身就是 5ms
之后过来的,一共刚好 10ms
,所以 req3
无需等待,直接可以处理。此时三个请求也恰好一共是 20ms
。如下:
t.sleepFor += t.perRequest - now.Sub(t.last)
if t.sleepFor > 0 {t.clock.Sleep(t.sleepFor)t.last = now.Add(t.sleepFor)t.sleepFor = 0
} else {t.last = now
}
当 t.sleepFor > 0
,代表此前的请求多余出来的时间,无法完全抵消此次的所需量,因此需要 sleep 相应时间, 同时将 t.sleepFor
置为 0。
当 t.sleepFor < 0
,说明此次请求间隔大于预期间隔,将多出来的时间累加到 t.sleepFor
即可。
但是,对于某种情况,请求 1 完成后,请求 2 过了很久到达 ,那么此时对于请求 2 的请求间隔 now.Sub(t.last)
,会非常大。以至于即使后面大量请求瞬时到达,也无法抵消完这个时间。那这样就失去了限流的意义。
为了防止这种情况,ratelimit 就引入了最大松弛量 (maxSlack) 的概念, 该值为负值,表示允许抵消的最长时间,防止以上情况的出现。
// 当计算出来的 sleepFor 超过一个 maxSlack 时,那么就只 sleep 一个 maxSlack 时间,用于两次请求时间间隔过大的场景
if t.sleepFor < t.maxSlack {t.sleepFor = t.maxSlack
}
ratelimit 中 maxSlack 的值为 -10 * time.Second / time.Duration(rate)
, 是十个请求的间隔大小。我们也可以理解为 ratelimit 允许的最大瞬时请求为 10。
用法
ratelimit 的 New 函数,除了可以配置每秒请求数 (QPS), 还提供了一套可选配置项 Option。
func New(rate int, opts ...Option) Limiter
WithoutSlack
上面说到 ratelimit 中引入了最大松弛量的概念,而且默认的最大松弛量为 10 个请求的间隔时间。
但是对于需要严格的限制请求的固定间隔的时,我们可以利用 WithoutSlack 来取消松弛量的影响。
limiter := ratelimit.New(100, ratelimit.WithoutSlack)
另外,ratelimit 还有其他选项,比如WithClock(clock Clock)
可以用来替换默认时钟,来实现精度更高或者特殊需求的计时场景。
3
Reference
uber-go 漏桶限流器使用与原理分析 | 编程沉思录 (cyhone.com)
开源限流组件分析(一):Uber 的 Leaky Bucket - 熊喵君的博客 | PANDAYCHEN
限流算法之一 | hzSomthing (hedzr.com)
uber-go/ratelimit: A Golang blocking leaky-bucket rate limit implementation (github.com)
《酷Go推荐》招募:
各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到
新的库,并且知道怎么用。
大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!戳「阅读原文」,即可报名
扫码也可以加入 GoCN 的大家族哟~
「GoCN酷Go推荐」漏桶限流库 — uber-go/ratelimit相关推荐
- 「GoCN酷Go推荐」Golang的Ealstic链接库
背景介绍 Elasticsearch是一个分布式.高扩展.高实时的搜索与数据分析引擎,用于海量文档的搜索.有些项目会将Elasticsearch当做存储海量数据的数据库使用,可见其查询性能之高效.作为 ...
- 「GoCN酷Go推荐」交互式命令行工具库survey
☆ 什么是 survey? ☆ survey 可以让你方便的在终端上构建交互式和可访问提示的应用,支持ANSI ☆ 安装 ☆ go get github.com/AlecAivazis/survey/ ...
- 「GoCN酷Go推荐」QQ机器人 go-cqhttp
什么是 go-cqhttp?✦ QQ机器人,可以做的事儿太多了,比如一个UP主需要群发多个QQ群,以便通知粉丝们开播:再比如可以检测群内或发给自己的消息,而通过代码直接回复做的简单回复.比如检测群内有 ...
- 「GoCN酷Go推荐」go语言位操作库 — bitset
bitset库实现了bitsets数据结构,这是一种正整数和布尔值映射关系的结构,它比map[uint]bool更高效 什么是bitsets✦ bitsets基本思想是用一个bit位来标记某个元素对应 ...
- 「GoCN酷Go推荐」高性能内存缓存 ristretto
背景 ristretto 是 dgraph 团队开源的一款高性能内存缓存库,旨在解决高并发场景下的缓存性能和吞吐瓶颈.dgraph 专攻的方向是高性能图数据库,ristretto 就是其图数据库和 K ...
- 「GoCN酷Go推荐」快速搭建私有云服务 go-btfs
# 1. go-btfs 是什么?# go-btfs 是一个去中心化的文件存储平台,无论图片.文件.视频等等各类文件.每个人都可以在自己电脑上安装部署 BTFS 节点,然后大家的节点相互连接,构成一个 ...
- 「GoCN酷Go推荐」后现代时代远程办公网络问题的golang开源解决方案 —— PairMesh...
PairMesh是什么? Pairmesh是一款先进的虚拟局域网(VPN)工具,用来搭建与访问安全,易用,高性能的点对点的软件定义虚拟局域网,为远程办公的网络连接问题提供了开箱即用的解决方案. 拥抱开 ...
- 「GoCN酷Go推荐」JSON 数据获取器 JID
01 推荐理由 JSON 格式数据适用范围非常广泛,一个内容丰富的json数据可能很大,使用 JID 可以让你非常舒服的获取到想要到数据. 02 简介 JID 是一个过滤JSON格式数据 cli ...
- 「GoCN酷Go推荐」Golang轻量级桌面程序wails2教学
01 推荐理由 不依赖cgo!不依赖cgo!不依赖cgo!真的不依赖cgo,且跨平台,原生渲染 无嵌入式浏览器,轻量级,生成的文件很小,而且只有一个可执行文件就可运行. 02 功能介绍 后端使用标准 ...
最新文章
- PHP上传图片到数据库和存储到本地文件夹的方法
- php 公交 查询系统,php定做单城市公交路线查询系统
- SAP UI5 初学者教程之二十六 - OData 服务配合 Mock 服务器的使用步骤详解试读版
- .Net Core2.*学习手册
- (C语言)链表的实现集合的相关操作
- vue-cli配置jquery 以及jquery第三方插件
- 一个可以下载Github指定子文件夹的Chrome插件
- 循环、选择要注意的复合语句
- Linux 数据重定向
- 多频电磁感应仪GEM-2介绍
- matlab怎么导入程序出错,Matlab导入数据时出错!十分困扰!
- 闲置路由器做无线打印服务器
- ESP32 文件存储 spiffs
- 多张JPG图片怎么转成一个PDF
- oracle lag使用情景,lag函数用法
- 关于 getWriter() has already been called for this response 的错误解决办法
- 学习笔记---原文网址在第一行
- 2022-2028中国聚合物增材制造设备市场现状研究分析与发展前景预测报告
- ANSYS CMD
- PCB——关于PCB设计倒角需要了解的一切(干货)