Redis应用-滑动窗口实现

2,778 阅读3分钟

概览

滑动窗口概念起源于网络通信,是一种流量控制机制。基于对指定窗口的指标统计,可以用于触发后续的处理措施。

例如分布式系统中,滑动窗口可以实现服务接口的限流。

本文针对滑动窗口在接口限流中的应用,分别提供了普通版(基于本地计数),分布式版(基于Redis计数)滑动窗口的实现。

算法思路

接口限流一般是指一定单位时间内,对于某个接口的请求量不允许超过某个阈值,如果超出阈值,则会拒绝请求。

算法思路包括如下核心点:

  • 时间窗口的创建(窗口大小,窗口最小划分周期定义)
  • 当前所属时间窗口定位,完成计数,统计操作

其中窗口最小划分周期可以理解为窗口每次移动的步长,也是统计计数的基本单位,这个步长的大小决定了窗口是否能平滑移动,步长定义越小,滑动窗口移动得越平滑,最终的统计结果也越精确。

如下,定义了一个滑动窗口:

  • 窗口大小为 4s
  • 窗口步长为 1s,即一个窗口被拆分成 4 块

假设每个窗口内的请求阈值定义为 10 个,可以看到:

  • 窗口1的请求总数量为 8,没有达到阈值
  • 窗口2的请求总数量为 14,触发了阈值限制,因此其中有 4 个请求会被拒绝

基本实现

代码实现思路如下。

定义滑动窗口属性:

滑动窗口实现:

统计当前窗口的请求数:

测试用例1:

熔断阈值设置为10,可以看到后10次请求都触发了熔断。

测试用例2:

熔断阈值设置为10,窗口大小为 10s,第11次请求触发熔断,之后休眠10s,过渡到下一个新的窗口,后面9次请求正常执行。

Redis 实现

基于Redis有序集合的特性,可以很简单就实现滑动窗口:

  • 有序集合的 score 属性存储每个请求的时间戳
  • 窗口数据统计请求量时,只需要把时间窗口外的元素舍弃,集合中剩余的元素数量之和便是结果

定义滑动窗口属性:

滑动窗口实现:

测试用例1:

熔断阈值设置为10,可以看到后10次请求都触发了熔断。

测试用例2:

熔断阈值设置为10,窗口大小为 10s,第11次请求触发熔断,之后休眠10s,过渡到下一个新的窗口,后面9次请求正常执行。

测试用例3(将窗口大小调整为20s,代码与测试用例2保持一致):

窗口大小设置为20s,第11个请求之后即使休眠了10s,后面9个请求仍然触发熔断,因为这些请求还在同一个窗口内。