亿级流量系统架构设计与实战(七)

限流

常见的限流方式

  • 频控 : 控制用户在 N 秒内只可执行 M 次操作。
    • 比如限制用户在 30s 内只能下载 1 次文件 、 在 1h 内最多只能发布 5 条动态 。
  • 单机限流 + 固定阈值某服务的每台服务器在 1s 内最多可处理 M 个请求 , M 值是预先设置好的 。
  • 全局限流 + 固定阈值某服务在 1s 内总共可处理 M 个请求 , 与前者的主要区别在于限流范围是某服务的全部服务实例。
  • 单机自适应限流 : 某服务的每台服务器根据自身服务状况 , 使用各种自动化算法动态判断是否限制请求 , 不再预先设置限流阈值.

频控

Redis 实现频控。

N 秒内执行 1 次

核心 Reids 命令:SET your_key_{xxID} 0 EX 30 NX

服务中执行该命令成功,则可以访问;执行失败,则不可访问,直接返回。

N 秒内最多执行 M 次

核心思想:向 Redis 中设置一个 Key,过期时间为 N 秒,Key 的 value 最大为 M。

这里涉及到 INCR(自增)和 EXPIRE ( 设置过期时间) 两个命令,需要使用 LUA 脚本保证这两个命令的原子性。

以用户在 1h 内最多只能发布 5 条动态为例,其 Lua 脚本实现如下:

local count = redis.call('incr', 'publish_{userID}') // 没有这个key,就加到 1
if count == 1 then // 判断是否为首次设置,如果是,需要设置过期时间
  redis.call('expire', 'publish_{userID}', 3600) // 设置过期时间为 lh
end
return count // 返回最新计数

服务调用该脚本,返回的值 < 5,那么可以访问服务。

单机限流 1 :时间窗口

核心思想:维护了一个初始值不为 0 的数组,每次请求时都需要从数组中减一。

固定时间窗口

比如限制在 1s 内请求量不超过100 个,可以将时间线切分为以 1s 为单位的时间窗口,每个时间窗口都维护这 1s 内允许通过的计数 100。

当请求到来时,先向当前所处的时间窗口申请 1 个计数,如果该时间窗口内的计数大于 0,则计数减 1 并允许请求通过;否则,请求被限流器丢弃。

缺点

  • 窗口边界流量暴增:无法防止时间窗口边界附近的流量暴增,可能会有 2 倍限流阈值的请求通过限流器。
    • 11:30:06 时前 500 ms 没有请求,后 500 ms 请求了 100 次,11:30:07 时前 500 ms 请求了 100 次。也就是在 1 s内请求了 200 次。 远超所设置的阈值。

滑动时间窗口

滑动时间窗口把时间线以更小的时间粒度 ( 如 50ms ) 划分为一个个槽,将限流计数均摊到每个槽,一个时间窗口就是最近时间的 20 个槽的总和。

  1. 这个时间窗口会随着时间的推移不断向后滑动。
  2. 当请求到来时,先在当前时间最近的 20 个槽中查找第一个计数大于 0 的槽。
  3. 如果找到了,则说明在这个时间窗口内依然有限流计数可用 , 将该槽计数减 1 ,请求被允许通过限流器。
  4. 如果在整个时间窗口内所有的槽计数都为 0,则说明已经达到限流阈值 , 请求将被限流器丢弃。

优点

滑动时间窗口限流器可以有效提高限流的准确性,且槽的时间粒度越小,限流的准确性越高。

缺点

  • 内存、CPU开销大:需要维护较多的槽信息 , 判断限流需要在时间窗口内遍历查找可用槽,此实现方式有较大的内存与 CPU 开销 。
  • 不适合对海量请求:此方案开销大,为了对海量请求进行限流设定 , 限流器应该有更加轻量级的实现方式。

单机限流 2 :漏桶算法

漏桶算法请求以任意速率进入服务器,而服务器永远以固定的速率处理排队的请求

如图,水流被视为进入服务器的请求,出水口匀速出水可被视为服务器处理请求的固定速率,当请求过多导致漏桶满了时,将开始拒绝新来的请求。

例子

假设设置漏桶的限流阈值为每秒处理 10 个请求 ( 即请求处理速率是 1 req/100 ms),漏桶的容量为 10,此时同时有 5 个请求流入漏桶中:

  1. 第一个请求进入漏桶,由于此时漏桶为空,所以请求无须排队,可以直接被处理 。
  2. 第二个请求进入漏桶,由于第一个请求刚刚被处理,所以此请求需要排队,严格按照请求处理速率的设置 , 即需要排队 100 ms。
  3. 第三个请求,需要等待第二个请求被处理后再排队 100ms, 所以排队时间是 200 ms。
  4. 以此类推,第四个请求排队 300ms,第五个请求排队 400ms。 如图所示 。

优势

  • 保证无论有多少请求访问服务器,服务器都以固定的速率处理请求。

不足

  • 响应时间会增加:为了以固定速率处理请求,漏桶算法要求请求排队等待,从上游服务视角看,请求的响应时间会增加。
  • 不灵活、不支持突增流量:不支持突增流量,这些流量可能对于服务来说是完全没有压力的。 但请求却在缓慢排队,其实这是对服务性能的浪费

单机限流 3 :令牌桶算法

令牌桶算法:系统以固定的速率向令牌桶中放入令牌,处理请求前,需要从令牌桶中取一个令牌,如果没有令牌可取,则拒绝请求。

令牌桶算法的基本工作流程:

  1. 每秒向令牌桶中放入 r 个令牌 , 即每 1 / r 秒新增一个令牌 。
  2. 令牌桶容量为 b,即最多存放 b 个令牌 , 桶满时新放入的令牌会被丢弃 。
  3. 当一个请求到来时,从令牌桶中获取一个令牌。 如果桶中有令牌 , 则令牌总数减 1 ,请求被允许执行 。
  4. 如果桶中没有可用令牌 , 则该请求被限流。

<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值