一、序言在一些对高并发要求有限定的系统或者功能里,比如说秒杀活动,或者一些网站返回确当前用户过多,请稍后考试测验。这些都是通过对同一时候要求数量进行了限定,一样平常用为难刁难后台系统的保护,防止系统由于过大的流量冲击而崩溃。对付系统崩溃带来的后果,显然还是谢绝一部分要求更能被掩护者所接管。而在各种限流中,除了系统自身设计的带锁机制的计数器外,利用Redis实现显然是一种既高效安全又便捷方便的办法。二、incr命令Redis Incr 命令将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再实行 INCR 操作。如果值包含缺点的类型,或字符串类型的值不能表示为数字,那么返回一个缺点。本操作的值限定在 64 位(bit)有符号数字表示之内。示例:127.0.0.1:6379> set num 10OK127.0.0.1:6379> incr num(integer) 11127.0.0.1:6379> get num # 数字值在 Redis 中以字符串的形式保存"11"把稳: 由于redis并没有一个明确的类型来表示整型数据,以是这个操作是一个字符串操作。实行这个操作的时候,key对应存储的字符串被解析为10进制的64位有符号整型数据。事实上,Redis 内部采取整数形式(Integer representation)来存储对应的整数值,以是对该类字符串值实际上是用整数保存,也就不存在存储整数的字符串表示(String representation)所带来的额外花费。三、利用场景1.计数器利用思路是:每次有干系操作的时候,就向Redis做事器发送一个incr命令。例如这样一个场景:我们有一个web运用,我们想记录每个用户每天访问这个网站的次数。web运用只须要通过拼接用户id和代表当前韶光的字符串作为key,每次用户访问这个页面的时候对这个key实行一下incr命令。这个场景可以有很多种扩展方法:通过结合利用INCR和EXPIRE命令,可以实现一个只记录用户在指定间隔韶光内的访问次数的计数器客户端可以通过GETSET命令获取当前计数器的值并且重置为0通过类似于DECR或者INCRBY等原子递增/递减的命令,可以根据用户的操作来增加或者减少某些值 比如在线游戏,须要对用户的游戏分数进行实时掌握,分数可能增加也可能减少。2.限速器限速器是一种可以限定某些操作实行速率的分外场景。传统的例子便是限定某个公共api的要求数目。假设我们要办理如下问题:限定某个api每秒每个ip的要求次数不超过10次。我们可以通过incr命令来实现两种方法办理这个问题。四、流量掌握之java实现这里我们将在java中利用redis-incr的特性来构建一个1分钟内只许可 要求100次的掌握代码,key代表在redis内存放的被掌握的键值。public static boolean flowControl(String key){ //最大许可100 int max = 100; long total = 1L; try { if (jedisInstance.get(key) == null) { //jedisInstance是Jedis连接实例,可以使单链接也可以利用链接池获取,实现办法请参考之前的blog内容 //如果redis目前没有这个key,创建并授予0,有效韶光为60s jedisInstance.setex(key, 60, "0"); } else { //获取加1后的值 total = jedisInstance.incr(redisKey).longValue(); //Redis TTL命令以秒为单位返回key的剩余过期韶光。当key不存在时,返回-2。当key存在但没有设置剩余生存韶光时,返回-1。否则,以秒为单位,返回key的剩余生存韶光。 if (jedisInstance.ttl(redisKey).longValue() == -1L) { //为给定key设置生存韶光,当key过期时(生存韶光为0),它会被自动删除。 jedisInstance.expire(redisKey, 60); } } } catch (Exception e) { logger.error("流量掌握组件:实行计数操作失落败,无法实行计数"); } long keytotaltransations = max; //判断是否已超过最大值,超过则返回false if (total > keytotaltransations) { return false; } return true; }
