简言
1. redis使用有序集合zset也能实现简单的限流,但是只能处理几十,几百的量级,因为zset需要记录每一条信息,很占据空间。要想处理更大数量级的限流,必须使用其他方法
2. 通常的限流算法有两种,漏斗算法,令牌桶算法,本篇博客要讲的redis-cell是使用令牌桶算法实现的
3. redis-cell的官方地址:https://github.com/brandur/redis-cell
4. redis-cell只有一个命令 cl.throttle,使用很简单,需要注意的是最后一个参数为正时表取出令牌,为负时表放入令牌,不填时默认为1
5. 《Redis深度历险》一书中对redis-cell的介绍是错误的,书中以为 cl.throttle 设置的是容量,其实不然,设置的是 “容量-1”,比如设置99时,容量则为100
安装(由于redis-cell是使用rust语言编写的,而本人对rust毫无研究,也不想去部署rust的环境,所以直接下载编译好的动态库so文件,不再源码编译)
1.打开地址:https://github.com/brandur/redis-cell/releases,挑选适合自己环境的压缩包,下载最新的,本人是ubuntu环境,下载linux版的即可,下载到/usr/local/redis/redis-stable目录,并解压
2. 修改要使用的redis.conf文件,添加一行 “loadmodule /usr/local/redis/redis-stable/libredis_cell.so”,保存后,重启redis即可
3. 连接进我们的redis,运行命令 module list ,可以查看目前已经启用的module
使用
如上面简言所述,redis-cell使用很简单,只有一个命令
命令格式:cl.throttle key名字 令牌桶容量-1 令牌产生个数 令牌产生时间 本次取走的令牌数 (不写时默认1,负值表放入令牌)
返回格式:0成功,1失败
令牌桶的容量
当前桶内剩余的令牌数
成功时该值为-1,失败时表还需要等待多少秒可以有足够的令牌
表预计多少秒后令牌桶会满
示例1(key:mybag,该key不存在时会新建,容量为100(也就是99+1=100), 每10秒产生1个令牌,本次取出40个)
127.0.0.1:6379> cl.throttle mybag 99 1 10 40
1) (integer) 0
2) (integer) 100
3) (integer) 60
4) (integer) -1
5) (integer) 400
0表示取出成功,100表令牌桶容量,60表桶内剩余令牌数,-1表成功即本次取令牌不需等待,400表预计还需要400秒令牌桶会满,根据我们的速度设定,每10秒产生一个令牌,确实是需要400秒
示例2(从mybag的令牌桶中再取出40个)
127.0.0.1:6379> cl.throttle mybag 99 1 10 40
1) (integer) 0
2) (integer) 100
3) (integer) 20
4) (integer) -1
5) (integer) 798
127.0.0.1:6379> cl.throttle mybag 99 1 10 40
1) (integer) 1
2) (integer) 100
3) (integer) 20
4) (integer) 196
5) (integer) 796
第一次的0表示取出成功,100表令牌桶容量,20表桶内剩余令牌数,-1表成功即本次取令牌不需等待,798表预计还需要798秒令牌桶会满
第二次的1表示取出失败,100表令牌桶容量,20表桶内剩余令牌数,196表失败,还需要等待196秒可以重试本次操作,796表预计还需要796秒令牌桶会满
示例3(往mybag的令牌桶中先放入40个,再取出40个)
127.0.0.1:6379> cl.throttle mybag 99 1 10 -40
1) (integer) 0
2) (integer) 100
3) (integer) 126
4) (integer) -1
5) (integer) -262
127.0.0.1:6379> cl.throttle mybag 99 1 10 40
1) (integer) 0
2) (integer) 100
3) (integer) 60
4) (integer) -1
5) (integer) 400
放入40个时,0表放入成功,126就没啥意义了,因为最大容量才100,当然桶内不可能有126个;-262更诡异了,桶满了就满了呗,干嘛告诉我需要负262秒呢,感觉桶满时0更准确
我们验证前面的猜想,马上再取出40个可以看到结果值0表成功,60表桶内还剩下60个令牌,即容量100减去本次的40得到,也就验证了第一次返回的126毫无意义