常见限流算法和go语言time/rate go.uber.org/ratelimit讲解

1 背景

保护服务节点或者数据节点,防止瞬时流量过大造成服务和数据崩溃,导致服务不可用

2 主流限流算法

2.1 固定/滑动窗口限流算法
2.1.1 固定窗口限流
实现过程:
也叫计数器算法,顾名思义就是固定一个窗口,在这个时间窗口下维护一个累加的计数器,每来一个请求计数器+1,并判断计数是否超过阈值,
超过阈值则拒绝请求直到下一个时间窗口将计数器清零再继续放行请求

优点: 原理简单 实现也简单
缺点: 限流策略太粗糙,无法限制两个时间窗口临界时的瞬时流量,比如:
        我们设置限流策略为时间窗口为1s 限制请求个数为100,有可能会出现这种情况:
        第1s的100个请求都集中在第500ms-1000ms内,第2s的请求都集中在第0ms-500ms内,那在这2s内,有200个请求发生在了
        第500ms到1500ms这1s内,显然不符合我们原来的预期

固定窗口

2.1.2 滑动窗口限流
实现过程:
滑动窗口算法是固定窗口的一种改进,但根本上并没有真正解决固定窗口算法的临界突发流量问题
滑动窗口算法将一个大的时间窗口分成多个小窗口,每次大窗口向后滑动一个小窗口,并保证大的窗口内流量不会超出最大值,这种实现比固定窗口的流量曲线更加平滑

假设还是1s限制100请求,将1s分为10个小窗口,[[t1_start,t1_end], [t2_start, t2_end]...[t10_start, t1_end]],每个小窗口维护一个自己的计数器
1. 判断请求时间是否在当前大窗口内,是则3
2. 大窗口往后一定一个小窗口 [[t2_start, t2_end]...[t11_start, t11_end]] 执行1
3. 判断大窗口下所有小窗口的计数器之和是否>=100 是则拒绝请求 否则放行,并且小窗口计数器+1

优点: 限流比固定窗口更加平滑
缺点: 虽然解决了临界突发流量问题,但是还是会存在流量突刺,比如 1s限流100 结果100个请求全发生在前10ms内

滑动窗口

2.2 漏桶算法
还有一种漏桶算法,算法内维护一个容器,请求进来时相当于水流进容器,处理请求时相当于水从容器流出。容器有一个最大容量,
并且水匀速从桶内流出。
实现过程:
可以维护一个固定长度队列,新的请求过来后,队列未满则放入队列,队列已满则拒绝请求,
然后再维护一个线程池,定期从队列里获取并处理请求

优点: 没有了流量突刺问题
缺点: 无法应对流量突发问题
2.3 令牌桶
令牌桶算是漏桶算法的一种改进算法,解决漏桶无法应对突发流量的问题,
想象有一个固定大小的桶,系统会以恒定速率向桶中放 Token,桶满则暂时不放。
而用户则从桶中取Token,如果有剩余token就可以一直取。如果没有剩余token,则需要等到系统中被放置了token才行。

实现过程:
其实我们并不需要真正去维护一个桶或者队列,这样的效率比较低, 比如golang标准库golang.org/x/time/rate,
通过一个计数器即可完成限流。具体实现可以看下面的介绍

令牌桶image

3 golang标准库库实现限流算法

官方地址: golang.org/x/time/rate

github地址:github.com/golang/time/rate

原文章链接

3.1 构造一个限流器
limiter := NewLimiter(10, 1);
这里有两个参数:
第一个参数是 r Limit。代表每秒可以向token桶中产生多少token。Limit 实际上是 float64 的别名。
第二个参数是 b int。b代表 token 桶的容量大小。
那么,对于以上例子来说,其构造出的限流器含义为,其令牌桶大小为1, 以每秒10个token 的速率向桶中放置 token

除了直接指定每秒产生的 token 个数外,还可以用 Every 方法来指定向 token 桶中放置 token 的间隔,例如:
limit := Every(100 * time.Millisecond);
limiter := NewLimiter(limit, 1);
以上就表示每 100ms 往桶中放一个 token。本质上也就是一秒钟产生 10 个。

Limiter 提供了三类方法供用户消费 token,用户可以每次消费一个 token,也可以一次性消费多个 token。
而每种方法代表了当 token 不足时,各自不同的对应手段
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值