请问redis incr命令可以限制特定数量吗? [英] Will redis incr command can be limitation to specific number?

查看:443
本文介绍了请问redis incr命令可以限制特定数量吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的项目中,我们想使用redis的incr命令对存储进行限制.例如,对于特定的商品 A,我们想在促销期间只出售其中的十件.所以我们打算用incr命令把0到10的存储值相加,理论上这个方案在这个场景下是没有问题的.

In our project, we want to use redis's incr command to do limitation to the storage. For example, for the specific goods A, We want to sell only ten of them during the promotion. So we planned to use incr command to add the storage value from 0 to 10. In theory, this plan is no problem with this scenario.

开始之前,我们对incr命令进行了性能测试,结果发现使用incr对货物存储进行限制可能不可靠.

Before start, we did a performance test on the incr command, the result appeared that using incr to do limitation to the goods storage may be unrealiable.

测试代码如下:

static int count = 0;

public void performanceToken() throws RedisAccessException {

    long result = redisUtil.incrRedisEx("myrrrxxxrrrediskey6");

    if (result <= 10) {
        count ++;
    }

    Struts2Utils.renderJson(result +"|"+count);
    return;
}

incrRedisEx 是 incr 命令的包装器,我们使用 jedis 作为驱动程序来驱动我们的 java 项目中的 redis.

The incrRedisEx was the wrapper of incr command and we used jedis as the driver to drive our redis in our java project.

然后我们启动了我们的tomcat,我们可以直接从我们的浏览器调用上面的界面.结果很好,没有错误,没有错误.

Then We started our tomcat and we could invoke above interface directly from our browser. The result was good, no mistake, no error.

然后我们切换到性能测试工具jmeter,它可以模拟用户调用界面的巨大压力.我们在 1 秒内创建了 1500 个请求来调用接口.但结果如下:

And then we switched to jmeter, the performance testing tool, who could simulate great pressure from users to invoke the interface. we created 1500 requests to invoke the interface in 1 seconds. But the result is below:

起初,代码运行正常,我们可以看到货物存储限制为 10.

At the first, the code worked ok and we can see that the goods storage was limited to 10.

过了一会儿,我们可以看到计数突破了限制,它增长了!!!

After a while, we can see that the count number broke the limitation, it growssss!!!

不知道为什么,redis incr 不能在用户要求很大的情况下做存储限制.任何人都可以给我一些灯吗?

Don't know why, redis incr can't do limitation to storage under great user requests. Anyone can give me some lights on it?

基于redis incr机制,执行incr命令后会返回新的值,如果是这样,为什么不能停止数字的增长,真是奇怪.

Based on redis incr mechanism, it will return new value after doing incr command , if so, why it can't stop the growth of the number, it's a strange thing, really.

对我来说,我觉得,可能同时有两个操作send到redis做incr操作,但是一个做incr命令直接返回,另一个做incr那么慢,返回的时候就是发现它增加的数字不是2,而是11,因为其他请求已经做了incr命令,好的存储已经增加到10,可能吗?但是这个解释是不正确的,因为redis是单线程模型.

For me, I think, maybe at the same time, there are two operations send to redis to do incr operation, but one does the incr command and returns directly, another one does incr so slow and when it returns, it is found that the number it increases is not 2, but 11, because other requests do the incr command already and the good storage has been increased to 10, maybe? But this explaination is not correct because redis is single thread model.

--------编辑----------------

--------EDIT----------------

我更改了代码以避免线程安全问题:

I changed my code to avoid thread safe problem:

 long result = redisUtil.incrRedisEx("axgggggggggg");

    if (result <= 10) {
        logger.error("==generate==order==result==" + result);
    }

    Struts2Utils.renderJson(result );
    return;

刚刚发现日志会写十次以上.

Just found that the log will be write more than ten times.

推荐答案

您可以使用一个小 Lua 脚本在 Redis 本身内部进行增量,以便它本质上是单线程的:

You could use a little Lua script to do the increment within Redis itself so that it is essentially single-threaded:

127.0.0.1:6379> set CappedInt 7
OK
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get
(integer) 8
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get
(integer) 9
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get
(integer) 10
127.0.0.1:6379> eval "local c=redis.call(ARGV[1],KEYS[1])+0;if c<10 then return redis.call('INCR',KEYS[1]); else return 10; end" 1 CappedInt get
(integer) 10

<小时>

您也可以将 Lua 代码放入名为 IncWithCap.lua 的文件中,而不是在脚本中键入:


Rather than typing in the script, you can also put the Lua code into a file called IncWithCap.lua like this:

local cap=10
if(redis.call(ARGV[1],KEYS[1])+0 < cap) then
   return redis.call('INCR',KEYS[1])
end
return cap

然后您可以使用以下命令将其加载到 Redis 中:

Then you can load it into Redis with:

redis-cli SCRIPT LOAD "$(cat IncWithCap.lua)"

样本输出

"6e6ad88c9a2b7dfdade9c5763467aaab2358d4e1"

然后你可以调用/执行它:

Then you can call/execute it with:

127.0.0.1:6379> evalsha 6e6ad88c9a2b7dfdade9c5763467aaab2358d4e1 1 CappedInt get

这篇关于请问redis incr命令可以限制特定数量吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆