Redis深度历险阅读笔记(5)

前言

我胡汉三写完毕业论文回来啦!这次读到了限流!

简单限流

策略

只允许用户在一定时间段内操作N次

思路

使用ZSet维持一个滑动窗口,用户每操作依次,记录依次,以时间为value,key随意(只要保证唯一即可),用户操作前计算滑动窗口内有几个key,如果小于N,则允许用户操作,否则不允许。

代码

基础的代码我写在了:https://github.com/Carey6918/RedisGo/blob/master/simple_rate_limiter.go

漏斗限流

策略

只允许用户在最大频率内进行操作,操作超过最大频率会被阻塞,超过阻塞容量会丢弃。

类似漏斗,漏嘴=流量最大频率,漏斗容量=阻塞容量。

代码

基础的代码我写在了:https://github.com/Carey6918/RedisGo/blob/master/funnel_rate_limiter.go

Redis-Cell

以上的代码有一个明显的问题,就是对redis的存取&内存中的计算必须是原子性的,所以必须加锁,这导致了性能瓶颈。

Redis 4.0 提供了限流Redis模块,也用了漏斗算法,并提供了原子的限流指令。

> cl.throttle key 15 30 60 # 最大容量:15,最大频率:30op/60s
1) (integer) 0   # 0 表示允许,1表示拒绝
2) (integer) 15  # 漏斗容量
3) (integer) 14  # 漏斗剩余空间 
4) (integer) -1  # 如果拒绝了,需要多长时间后再试(漏斗有空间了,单位秒)
5) (integer) 2   # 多长时间后,漏斗完全空出来(单位秒)

注:这里我看网上很多文章说redis-cell使用的是令牌桶算法,但是我看了一下github上的描述,它实现的是GCRA算法,我认为它的一些描述(max_burst、The remaining limit of the key)等属于漏斗算法。

令牌桶限流

策略

令牌桶和漏斗的区别在于,漏斗确定了最大消耗速度,而令牌桶确定了令牌生成速度,桶中的令牌以一定速率增长,当全部被消耗光时,就需要等待下一块令牌的生成,

代码

基础的代码我写在了:https://github.com/Carey6918/RedisGo/blob/master/token_rate_limiter.go

但是观察发现,漏斗和令牌桶的实现几乎一模一样,不同的是令牌桶只需要关心自身是否拿到令牌,而漏斗需要延迟一段时间等待漏斗中的其他水漏出(这里可以用FIFO队列进行注水和漏水(消费))

内心比较犹豫,不知道自己的理解对不对,如果不对,欢迎指正。

Reference

自己动手写令牌桶、漏桶、计数等限流实现

后记

原文的漏斗代码有点奇怪,也不知道是不是我写了一个月论文写傻了…和吴老师胡言乱语了一通,最终不知道是我忽悠了谁,又是谁忽悠了我……

以我的理解,漏斗和令牌就是上述这样了,不过应该还有更好的实现,我造的轮子太渣…嗯..下次再造一个好一点的轮子_(:зゝ∠)_

Table of Contents