Redis如何在并发下让自增key的值不超过某个固定的数?

大致代码如下:

     func(id, ip){
         int countId = jedis.hget("count", id);
         int countIP = jedis.get("count", ip);
         if(countId >= 5 || countIP>=5){
             return;
         }
         ... //一些其他操作
         
         //再次判断,怕并发时被其他线程修改过
         int countId = jedis.hget("count", id);
         int countIP = jedis.get("count", ip);
         if(countId >= 5 || countIP>=5){
             doSomething();
             jedis.hincrBy("count", id, 1);
             jedis.hincrBy("count", ip, 1);
         }
     }
     

上述代码只是表达大致意思,因为显然在并发情况下会有问题

我的设想是,譬如做一个类似CAS的,casIncrBy("count", id, 1, 5), 这个原子操作对key值增1,如果>5则失败。然后判断是否失败,失败就不doSomething(),成功就doSomething().

如何达成?

阅读 5k
3 个回答
新手上路,请多包涵

拿出来, 判断一下, 修改后发现大于5把数值改成5..

用Lua脚本。

eval "local curr = redis.call('get', KEYS[1]); if curr and tonumber(curr) >= tonumber(ARGV[2]) then return 0 else redis.call('incrby', KEYS[1], ARGV[1]); return curr + ARGV[1] end" 1 count 1 5

可以使用 @oraoto 的思路, 写个lua脚本.
如果lua脚本无法实现业务逻辑, 可以使用WATCH命令, 或者自己实现一个简单的锁, 锁住这个键.
可以参考Redis实战中《4.4 Redis事务》 和 《6.2分布式锁》

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题