【发布时间】:2017-12-20 04:41:38
【问题描述】:
在我们的项目中,我们想使用redis的incr命令来限制存储。例如,对于特定商品A,我们希望在促销期间只销售其中的十件。所以我们打算用incr命令将存储值从0加到10,理论上这个方案在这个场景下是没有问题的。
在开始之前,我们对incr命令进行了性能测试,结果出现使用incr来限制货物存储可能不现实。
下面的测试代码:
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 命令的包装器,我们在 java 项目中使用 jedis 作为驱动程序来驱动我们的 redis。
然后我们启动了我们的tomcat,我们可以直接从我们的浏览器调用上面的接口。结果很好,没有错误,没有错误。
然后我们切换到性能测试工具jmeter,它可以模拟用户调用接口的巨大压力。我们在 1 秒内创建了 1500 个调用接口的请求。但结果如下:
一开始,代码运行正常,我们可以看到货物存储限制为 10 个。
不知道为什么,redis incr 在很大的用户请求下无法对存储进行限制。谁能给我点灯?
基于redis的incr机制,执行incr命令后会返回新的值,如果是这样,为什么不能阻止数字的增长,真是奇怪。
对我来说,我想,可能同时有两个操作发送到redis做incr操作,但是一个做incr命令直接返回,另一个做incr那么慢,返回的时候是发现它增加的数量不是2,而是11,因为其他请求已经执行了incr命令,并且好存储已经增加到10,也许?但是这个解释是不正确的,因为redis是单线程模型。
--------编辑----
我更改了代码以避免线程安全问题:
long result = redisUtil.incrRedisEx("axgggggggggg");
if (result <= 10) {
logger.error("==generate==order==result==" + result);
}
Struts2Utils.renderJson(result );
return;
刚刚发现日志会被写十多次。
【问题讨论】:
-
performanceToken是否在多线程环境中运行? -
@for_stack 这是一个 struts 动作,我将它公开给用户。
-
performanceToken不是线程安全的。如果用户或您的测试代码在多个线程中调用此方法,count可能大于 10。 -
@for_stack 我更改了代码以避免线程安全问题。请再次建议。
-
您应该检查其他一些客户端是否减少或删除了密钥。试试
Redis Keyspace Notifications。