关于我

我的博客|文章首发

go-rate是速率限制器库,基于 Token Bucket(令牌桶)算法实现。 go-rate被用在LangTrend的生产中 用于遵守GitHub API速率限制。

速率限制可以完成一些特殊的功能需求,包括但不限于服务器端垃圾邮件保护、防止api调用饱和等。

库使用说明

构造限流器

我们首先构造一个限流器对象:

limiter := NewLimiter(10, 1);

这里有两个参数:

  1. 第一个参数是 r Limit。代表每秒可以向 Token 桶中产生多少 token。Limit 实际上是 float64 的别名。
  2. 第二个参数是 b int。b 代表 Token 桶的容量大小。

上述的限流器的含义是:拥有一个容量为1的令牌桶,以每钞10个的速度向桶中放令牌。

除了直接指定每秒产生的 Token 个数外,还可以用 Every 方法来指定向 Token 桶中放置 Token 的间隔,例如:

limiter := NewLimiter(Every(100 * time.Millisecond), 1);

以上就表示每 100ms 往桶中放一个 Token。本质上也就是一秒钟产生 10 个。

消费令牌Token

Limiter 提供了三类方法供用户消费 Token,用户可以每次消费一个 Token,也可以一次性消费多个 Token。

而每种方法代表了当 Token 不足时,各自不同的对应手段。

Wait/WaitN

func (lim *Limiter) Wait(ctx context.Context) (err error)
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)

Wait 实际上就是 WaitN(ctx,1)

当使用 Wait 方法消费 Token 时,如果此时桶内 Token 数组不足 (小于 N),那么 Wait 方法将会阻塞一段时间,直至 Token 满足条件。如果充足则直接返回。

这里可以看到,Wait 方法有一个 context 参数。我们可以设置 context 的 Deadline 或者 Timeout,来决定此次 Wait 的最长时间。

Allow/AllowN

Allow 实际上就是 AllowN(time.Now(),1)

AllowN 方法表示,截止到某一时刻,目前桶中数目是否至少为 n 个,满足则返回 true,同时从桶中消费 n 个 token。

反之返回不消费 Token,false。

通常对应这样的线上场景,如果请求速率过快,就直接丢到某些请求。

Reserve/ReserveN

Reserve 相当于 ReserveN(time.Now(), 1)

ReserveN 的用法就相对来说复杂一些,当调用完成后,无论 Token 是否充足,都会返回一个 Reservation * 对象。

你可以调用该对象的 Delay() 方法,该方法返回了需要等待的时间。如果等待时间为 0,则说明不用等待。必须等到等待时间之后,才能进行接下来的工作。

或者,如果不想等待,可以调用 Cancel() 方法,该方法会将 Token 归还。

使用一个伪代码来举例,我们可以如何使用 Reserve 方法。

r := lim.Reserve()
//是否愿意等待
f !r.OK() {
//不愿意等待直接退出
return
} //如果愿意等待,将等待时间抛给用户 time.Sleep代表用户需要等待的时间。
time.Sleep(r.Delay())
Act() // 一段时间后生成生成新的令牌,开始执行相关逻辑

动态调整速率

Limiter 支持可以调整速率和桶大小:

  1. SetLimit(Limit) 改变放入 Token 的速率
  2. SetBurst(int) 改变 Token 桶大小

有了这两个方法,可以根据现有环境和条件以及我们的需求,动态地改变 Token 桶大小和速率。

案例1-单位时间只允许一次邮件发送操作

客户端软件客户点击发送邮件,如果客户一秒钟内点击10次,就会发送10次,这明显是不合适的。如果使用速率限制,我们就可以限制一秒内只能发送一次,实现方法为:

(令牌桶)容量为1,速度为每一秒生成一个令牌,这样可以保证一秒钟只会被执行一次,伪代码实现如下

//初始化 limiter 每秒生成1个令牌,令牌桶容量为20
limiter := rate.NewLimiter(rate.Every(time.Second), 1)
//模拟单位时间执行多次操作
for i := 0; i < 5; i++ {
if limiter.Allow() {
fmt.Println("发送邮件")
} else {
fmt.Println("请求多次,过滤")
}
}
if limiter.Allow() {
fmt.Println("发送邮件")
}

执行结果

发送邮件

请求多次,过滤

请求多次,过滤

请求多次,过滤

请求多次,过滤

发送邮件

我们发现,第一次执行是可以被允许的因为第一次的令牌被允许,之后的请求失败是因为还没有生成新的令牌,所以需要等待1秒,之后又可以进行发送邮件操作。

通过这样一个案例,相信大家对令牌桶的实现场景有了一个基本的了解。

案例2——令牌取出单个和多个

初始化令牌桶容量为20,设置每100毫秒生成一个令牌,即1秒生产10个令牌。编码测试功能

//初始化 limiter 每秒10个令牌,令牌桶容量为20
limiter := rate.NewLimiter(rate.Every(time.Millisecond*100), 20)
for i := 0; i < 25; i++ {
if limiter.Allow() {
fmt.Println("success") //do something
} else {
fmt.Println("busy")
}
} //阻塞直到获取足够的令牌或者上下文取消
ctx, _ := context.WithTimeout(context.Background(), time.Second*2)
fmt.Println("start get token", time.Now())
err := limiter.WaitN(ctx, 20)
if err != nil {
fmt.Println("error", err)
return
}
fmt.Println("success get token", time.Now())

第二段编码阻塞的场景在于,一次性取出20个令牌给予2秒的等待时间,如果有20个令牌可以取出打印成功消息,如果2秒等待时间内没有20个令牌可以取出,程序直接退出,即失败。

参考

https://github.com/beefsack/go-rate

Golang 标准库限流器 time/rate 使用介绍

Golang限流器rate使用

END

欢迎关注公众号 程序员工具集 致力于分享优秀的开源项目、学习资源 、常用工具

回复关键词“关注礼包”,送你一份最全的程序员技能图谱。

go的令牌桶实现库 go-rate的更多相关文章

  1. 漏桶、令牌桶限流的Go语言实现

    限流 限流又称为流量控制(流控),通常是指限制到达系统的并发请求数. 我们生活中也会经常遇到限流的场景,比如:某景区限制每日进入景区的游客数量为8万人:沙河地铁站早高峰通过站外排队逐一放行的方式限制同 ...

  2. 三.Go微服务--令牌桶实现原理

    1. 前言 在上一篇文章 Go微服务: 令牌桶 当中简单的介绍了令牌桶实现的原理,然后利用 /x/time/rate 这个库 10 行代码写了一个基于 ip 的 gin 限流中间件,那这个功能是怎么实 ...

  3. tc令牌桶限速心得

    一.实验拓扑与实验现象 实验拓扑如图所示,在①号机上发送数据,③号机上接受数据,同时在④号机的eth1与eth2网口限制速率为115200kbps,命令如下 tc qdisc add dev eth1 ...

  4. QoS令牌桶工作原理

    QoS的一个重要作用就是对port流量进行监管,也就是限制port流量.但QoS是怎样做到这点的呢?那就是QoS的令牌桶机制了.以下是在笔者刚刚出版的<Cisco/H3C交换机高级配置与管理技术 ...

  5. 15行python代码,帮你理解令牌桶算法

    本文转载自: http://www.tuicool.com/articles/aEBNRnU   在网络中传输数据时,为了防止网络拥塞,需限制流出网络的流量,使流量以比较均匀的速度向外发送,令牌桶算法 ...

  6. CIR,CBS,EBS,PIR,PBS傻傻分不清楚?看这里!—-揭秘令牌桶

    概述 春暖花开的时候,大家都开着汽车外出旅游欣赏美丽的风景,却被堵在高速公路上,你是否为此感到痛苦?但如果有一种机制可以评估高速公路上的车流量.控制车流情况,确保进入高速公路的汽车都能在路上安全畅行, ...

  7. CIR,CBS,EBS,PIR,PBS 名词解释 令牌桶应用

    为了达到上述目的,我们需要对进入网络的流量进行监督,实现CAR(Committed Access Rate). CAR:将进入网络的用户流量的速率限制在约定的范围之内,从而避免引起网络拥塞. CIR( ...

  8. 限流之令牌桶算法——RateLimiter官方文档

    原文链接 作者:Dimitris Andreou  译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证.如果必要的话,每个acquire() 会阻 ...

  9. Redis令牌桶限流

    一 .场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源, 通常来说我们会对于服务器上的各种接口进行调用次数的限制.比如对于某个 用户,他在一个时间段(interval ...

随机推荐

  1. JavaScript Array methods performance compare

    JavaScript Array methods performance compare JavaScript数组方法的性能对比 env $ node -v # v12.18.0 push vs un ...

  2. nodejs 调用win32 api

    video 教程文件 win32 api >node -v v12.16.1 >npm install -g node-gyp >npm i @saleae/ffi >node ...

  3. DAPHNE PATEL:有主见的人,才能活出精彩人生

    有主见的人,会活出什么样子呢?近日,NGK灵石团队技术副总裁DAPHNE 女士给出了答案. DAPHNE PATEL表示,有主见的人,才能活出精彩的人生.为什么这么说呢? DAPHNE PATEL用自 ...

  4. (转载)VoLTE简介

    转载地址:http://www.360doc.cn/article/2909773_637471256.html,本文介绍了移动通信领域相关概念,如CS.PS.VoIP.VoLTE.IMS.CSFB. ...

  5. sklearn中的pipeline的创建与访问

    前期博文提到管道(pipeline)在机器学习实践中的重要性以及必要性,本文则递进一步,探讨实际操作中管道的创建与访问. 已经了解到,管道本质上是一定数量的估计器连接而成的数据处理流,所以成功创建管道 ...

  6. Python算法_爬楼梯(08)

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2输出: 2解释: 有两种方 ...

  7. react小白笔记

    diff算法主要是同级比较,生成数组,进行数组替换 reducer可以接收state,但是绝不能修改state 纯函数指的是:给固定收入,就一定有固定的输出,而且不会有任何副作用[不能例如:new d ...

  8. .NET 云原生架构师训练营(模块二 基础巩固 安全)--学习笔记

    2.8 安全 认证 VS 授权 ASP .NET Core 认证授权中间件 认证 JWT 认证 授权 认证 VS 授权 认证是一个识别用户是谁的过程 授权是一个决定用户可以干什么的过程 401 Una ...

  9. sql注入和union all关联查询的学习总结

    1.后台从页面取值进行sql查询时最好不要直接拼,如下代码: String sql = "SELECT wo.* " + " from push_command pu & ...

  10. 剑指 Offer 49. 丑数 + 小根堆 + 动态规划

    剑指 Offer 49. 丑数 Offer_49 题目详情 解法一:小根堆+哈希表/HashSet 根据丑数的定义,如果a是丑数,那么a2, a3以及a*5都是丑数 可以使用小根堆存储按照从小到大排序 ...