限流系列文章——漏斗限流
1、需求
限定用户的某个行为在指定时间 T 内,只允许发生 N 次。假设 T 为 1 秒钟,N 为 1000 次。
2、常见的错误设计
程序员设计了一个在每分钟内只允许访问 1000 次的限流方案,如下图 01:00s-02:00s 之间只允许访问 1000 次,这种设计最大的问题在于,请求可能在 01:59s-02:00s 之间被请求 1000 次,02:00s-02:01s 之间被请求了 1000 次,这种情况下 01:59s-02:01s 间隔 0.02s 之间被请求 2000 次,很显然这种设计是错误的。
3、漏斗限流
3.1 解决方案
漏斗容量有限,当流水的的速度小于灌水的速度,漏斗就会水满溢出,利用这个原理我们可以设计限流代码!漏斗的剩余的空间就代表着当前行为(请求)可以持续进行的数量,漏斗的流水速率代表系统允许行为(请求)发生的最大频率,通常安装系统的处理能力权衡后进行设值。
3.2 Java 代码实现
测试代码:
计算机运行如下的代码速度会非常的块,我通过 TimeUnit.SECONDS.sleep(2);模拟客户端过一段时间后再请求。
设置漏斗容量为 10,每毫秒允许 0.002 次请求(2 次/秒),每次请求数量为 1;
测试结果:
01-10 次请求成功,初始漏斗大小为 10,因此前 10 次请求成功
11-14 次请求失败,由于漏斗已满,并且漏斗的流速在这四次请求之间未能释放 1
15-18 次请求成功,因为 i == 15 时主线程睡眠 2 秒,2 秒时间漏斗流出 0.002*1000*2 = 4,因此这四次请求成功
19-20 次请求失败,与 11-14 次请求失败的原因一致
3.3 结合 Redis 实现
我们采用 hash 结构,将 Funnel 的属性字段,放入 hash 中,并且在代码中进行运算即可
测试代码:
测试结果:
与上面的 java 代码结构一致
4、总结
上述说了两种实现漏斗限流的方式,其实思想都是一样的,但是这两者都无法在分布式环境中使用,即便是在单机环境中也是不准确的,存在线程安全问题/原子性问题,因此我们一般使用 Redis 提供的限流模块 Redis-Cell 来限流,Redis-Cell 提供了原子的限流指令 cl.throttle,这个留到后续在详细说吧,我要睡觉去了!
版权声明: 本文为 InfoQ 作者【李子捌】的原创文章。
原文链接:【http://xie.infoq.cn/article/af6b9073aea9fe7950287eb36】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论