你被限流过吗

我还记得14年抢红米的时候,下面这个图是我最烦的一个图

抢了两个星期,才终于买到了我的第一台小米手机:红米1s。小米商城加入了一个排队的机制,于是我们可以感知到自己被限流了,但大部分服务,比如最近各大电商的抢茅台活动,并没有让我们感知到限流,不管你是手速不够还是被限流,都会给你返回“很遗憾,已经被抢光了”类似的提示。不过确实也没必要让用户感知到这个机制(你看,程序员又想做产品经理的主了),毕竟结果都是一样的。

对于这种火爆的活动,为了保证服务的稳定性,都需要对特定的接口进行限流,用Redis中的zset实现一个限流器该怎么做呢?

如何实现一个限流器

限流器需要实现的功能:在指定时间内,允许一定量的请求通过

如图所示,横坐标代表了时间,坐标轴上有一个窗口顺着时间的方向,向前移动。窗口最前面的那条线表示的就是“现在”,每进入一个请求,就会在时间轴对应的当下时间处打上一个点。比如我们要实现一个1分钟最多100000次访问的限流器。那么窗口的大小就是1分钟,窗口一直向前移动,我们要保证被窗口框住的请求永远不超过100000个。

使用Redis的zset可以很方便的实现这个功能。主要用到以下几个命令:zremrangeByScore,zcard,zadd。每当一个请求进入,我们就向zset中添加一个member,score值是当前时间的毫秒数。member叫什么不重要,只要保证他不重复就行了。当判断一个请求能否通过的时候,就检测score的值处于“当前时间”和“1分钟之前”之间的member数量,如果超过了限定值,则被限流,否则加入到zset中,给该请求“放行”。为了保证原子性,我们可以选择使用lua脚本来编写逻辑代码。

--KEYS[1]:该次限流对应的key
--ARGV[1]:一分钟之前的时间戳
--ARGV[2]:此时此刻的时间戳
--ARGV[3]:允许通过的最大数量
--ARGV[4]:member名称(随机生成)
redis.call('zremrangeByScore', KEYS[1], 0, ARGV[1])
local res = redis.call('zcard', KEYS[1])
if (res == nil) or (res < tonumber(ARGV[3])) thenredis.call('zadd', KEYS[1], ARGV[2], ARGV[4])return 0
else return 1 end

写一个demo,并发校验,可以看到输出(为了方便测试,我设定的是一分钟最多进入10个请求):

[pool-1-thread-72] INFO blog20210109.Limiter - 进入
[pool-1-thread-16] INFO blog20210109.Limiter - 进入
[pool-1-thread-42] INFO blog20210109.Limiter - 进入
[pool-1-thread-22] INFO blog20210109.Limiter - 进入
[pool-1-thread-91] INFO blog20210109.Limiter - 进入
[pool-1-thread-10] INFO blog20210109.Limiter - 进入
[pool-1-thread-33] INFO blog20210109.Limiter - 进入
[pool-1-thread-83] INFO blog20210109.Limiter - 进入
[pool-1-thread-62] INFO blog20210109.Limiter - 进入
[pool-1-thread-35] INFO blog20210109.Limiter - 进入
[main] INFO blog20210109.Limiter - 一分钟内进入的请求数有:10

彩蛋

最开始我的脚本是这样写的:

redis.call('zremrangeByScore', KEYS[1], 0, ARGV[1])
local res = redis.call('zrangeByScore', KEYS[1], ARGV[1], ARGV[2])
if (res == nil) or (table.getn(res) < tonumber(ARGV[3])) thenredis.call('zadd', KEYS[1], ARGV[2], ARGV[4])return 0
else return 1 end

测验的时候,总是限流失败。本来只允许进入10个,但每次总是会进入15个左右,你看出哪里的问题了吗?
获取完整代码请公众号(Vegout)回复:R01

用Redis中的zset实现一个限流器相关推荐

  1. Redis中的zset 存储结构(实现)原理

    同时满足以下条件时使用ziplist 编码: 元素数量小于128 个 所有member 的长度都小于64 字节 在ziplist 的内部,按照score 排序递增来存储.插入的时候要移动之后的数据. ...

  2. 使用redis中的zset进行金牌、银牌、铜牌的排序操作

    通过使用redis中的zset进行金牌.银牌.铜牌的排序操作 简介: 1. Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员. 2.不同的是每个元素都会关联一个doub ...

  3. Redis中对ZSet类型的操作命令

    写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- ------------ ...

  4. zset获取指定score_7、Redis中对ZSet类型的操作命令

    写在前面的话:读书破万卷,编码如有神 -------------------------------------------------------------------- ------------ ...

  5. Redis中的zset原理以及用Java实现跳跃表

    准备工作 先在Redis官网下载最新的稳定版本6.2.按照官网给出的安装指南到Linux服务器上安装. zadd调用过程 redis/src/server.c 文件中定义了所有命令运行要调用的方法.z ...

  6. Redis中的zset 有序集合

    存储类型 sorted set,有序的set,每个元素有个score. score 相同时,按照key 的ASCII 码排序. 数据结构对比: 数据结构 是否允许重复元素 是否有序 有序实现方式 列表 ...

  7. redis中的zset

    1.组成结构 跳跃表结构 2.接口API zslCreate:初始化zskipList的层数为1,长度为0,尾指针为NULL,创建zskiplistNode哨兵结点,结点层数为32,每层的前向指针为N ...

  8. 【承】Redis 原理篇——关于 Redis 中的事务

    前言 关于 Redis 的"起承转合",我前面已经用五个篇章的长度作了一个 Redis 基础篇--"起"篇的详细阐述,相信大家无论之前有没有接触过 Redis, ...

  9. redis 中 set 和 hset 有什么不同,什么时候使用 hset 什么时候使用set?

    转载:https://blog.csdn.net/wab719591157/article/details/73379844 redis 中存数据时,到底什么时候用  hset 相比于 set 存数据 ...

最新文章

  1. 中科院院士指出“万物互联”只是开始,“万物控制”是物联网下一个挑战
  2. UESTC_秋实大哥下棋 2015 UESTC Training for Data StructuresProblem I
  3. UITextField属性
  4. C++ explicit关键字应用方法详解
  5. 如何反编译APK文件
  6. 无意中发现的MSDN软件下载网站
  7. [201511118]发生系统错误86.txt
  8. Android_自适应布局
  9. python设计选择题代码_《Python程序的设计》试题库完整
  10. matlab 螺纹,关于螺纹边缘提取及参数测量
  11. 恒指期货高手背后的辛酸付出谁又能懂
  12. 天龙八部服务器端 修改缥缈峰副本,天龙八部手游缥缈峰副本怎么过 缥缈峰副本过关攻略...
  13. H5 网络版坦克大战
  14. 英特尔、高通等多家科技巨头禁止员工与华为交流!
  15. Java验证中文汉字、英文字母、标点符号一个字符占多少字节
  16. Android中铃声的使用
  17. 心电图心电轴怎么计算_心电轴度数计算表
  18. vba文字型的值转换成数值类型
  19. HTML5绘制国际象棋,如何用纯CSS实现一副国际象棋
  20. element dialog 设置背景色

热门文章

  1. BusyCal for Mac(任务日历工具)
  2. IBM 开源J9 JVM
  3. 爱剪辑 服务器维护,爱剪辑联网检测失败怎么办-修复爱剪辑联网检测失败的方法 - 河东软件园...
  4. 书单|如何摆脱“穷人思维”的陷阱?
  5. 实战1-数据项目分析流程
  6. AndroidStudio初体验
  7. matlab 轴系校中,轴系校中简介.ppt
  8. 去哪儿网数据同步平台技术演进与实践
  9. Java 设计模式总结及六大设计原则
  10. 三个数差的平方公式推导过程_平方差公式证明推导过程及运用详解(数学简便计算方法之一)...