滑动窗口限流算法实现流量控制

一、为什么要限流

在大型互联网项目中,瞬时的请求量是成千上万的,但系统的处理能力往往存在临界阈值。当流量洪峰来临时,如何避免系统被击穿?实现方式有很多种,例如:令牌桶算法,漏桶算法、固定窗口算法、滑动窗口算法。这里我将梳理分布式系统中滑动窗口限流算法的实现,并基于Redisson的RRateLimiter给出可落地的解决方案。

二、为什么用滑动窗口算法

其他三种算法的痛点如下:

  • 固定窗口:存在临界时刻双倍流量冲击问题
  • 令牌桶算法:虽然允许突发流量,但预热机制复杂
  • 漏桶算法:强制平滑流量,无法应对合理突发

而滑动窗口:

  • 时间片为单位滑动统计
  • 精准控制单位时间内的请求量
  • 有效解决传统算法的临界突变问题

滑动窗口算法有两个重要概念,即 请求速率窗口大小,也就是在规定的窗口大小中,请求数量不能超过给定的请求速率值。

如何去实现呢,常见的实现方案即使用redis的zset去实现,通过将加入的请求的请求时间作为每个请求的score,进行排序,每次新的请求进入的时候,若请求数小于等于剩余可接收请求个数,那么则将请求记入zset。

Redisson的RRateLimiter通过lua脚本包装好了相关的算法,我们直接看它的实现。

三、Redisson RRateLimiter原理解析

直接看Redisson RRateLimiter 的lua脚本部分,这里参考RRateLimiter原理解析


-- 速率
local rate = redis.call("hget", KEYS[1], "rate")
-- 时间区间(ms)
local interval = redis.call("hget", KEYS[1], "interval")
local type = redis.call("hget", KEYS[1], "type")
assert(rate ~= false and interval ~= false and type ~= false, "RateLimiter is not initialized")

-- {name}:value 分析后面的代码,这个key记录的是当前令牌桶中的令牌数
local valueName = KEYS[2]

-- {name}:permits 这个key是一个zset,记录了请求的令牌数,score则为请求的时间戳
local permitsName = KEYS[4]

-- 单机限流才会用到,集群模式不用关注
if type == "1" then
    valueName = KEYS[3]
    permitsName = KEYS[5]
end

-- 原版本有bug(https://github.com/redisson/redisson/issues/3197),最新版将这行代码提前了
-- rate为1 arg1这里是 请求的令牌数量(默认是1)。rate必须比请求的令牌数大
assert(tonumber(rate) >= tonumber(ARGV[1])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值