Node.js Redis没有';当一次有多个请求时,无法更新
我有一个Node.js应用程序,我正在尝试使用Redis缓存来记录请求的数量。这只是一个概念证明,看看Redis是否是适合我的工具,但我对结果有点失望,我想知道Redis的性能是否真的很差,或者我的代码中是否有缺陷 我有以下代码:Node.js Redis没有';当一次有多个请求时,无法更新,node.js,redis,Node.js,Redis,我有一个Node.js应用程序,我正在尝试使用Redis缓存来记录请求的数量。这只是一个概念证明,看看Redis是否是适合我的工具,但我对结果有点失望,我想知道Redis的性能是否真的很差,或者我的代码中是否有缺陷 我有以下代码: const express = require('express') const Redis = require('ioredis') const client = new Redis(6379, 'redis'); client.on('connect', fu
const express = require('express')
const Redis = require('ioredis')
const client = new Redis(6379, 'redis');
client.on('connect', function() {
console.log('Redis client connected');
});
client.on('error', function (err) {
console.log('Something went wrong ' + err);
});
const getRedisCount = async (question_id) => {
const count = await client.get('votes_' + question_id);
if(count) {
return count;
}
await setRedisCount(question_id, 0)
return 0;
}
const setRedisCount = async (question_id, count) => {
await client.set('votes_' + question_id, count)
}
const app = express();
app.use(express.json());
// post a vote
app.post('/vote', async (req, res) => {
let count = await getRedisCount(req.body.question_id)
count++
await setRedisCount(req.body.question_id, count)
res.status(200).send({ status: 200, data: count });
})
app.listen(5000, () => {
console.log('Vote service listening on port 5000')
})
现在,当我在Postman中执行一个post请求时,所有这些都如预期的那样工作。计数器将按预期更新
但是当我在JMeter中运行一个测试,一次执行150个请求时,在最后一个请求之后,我得到的计数是20-30,而不是预期的150
所以我的问题是-这是预期的行为,还是我的代码中的错误?在这两种情况下-如何修复它?这可能与您的redis服务器配置有关 您可以在主机上从redis cli运行监视器 通常通过cli进行连接,例如: 这应该给你一个问题的指示 您还可以从redis cli运行INFO命令,查看服务器统计信息和内存使用情况等信息
redis>INFO
#服务器
redis_版本999.999.999
redis_git_sha1:3c968ff0
redis\u git\u dirty:0
redis_build_id:51089de051945df4
redis_模式:独立
操作系统:Linux 4.8.0-1-amd64 x86_64
拱形位:64
多路复用api:epoll
atomicvar_api:原子内置
gcc_版本:6.3.0
进程id:8394
另外,在代码中使用redis客户端的INCRBY命令,否则需要在设置它之前增加您的计数值,这与异步模式不一致
我想你的问题是因为这是异步的,对吗
因此,当它们被发布时,计数是不同步的,因为一些计数可能会在其他计数之前等待
无论采用哪种方式,您都希望尝试同步发布它们,看看这是否会产生影响,然后您就知道这是问题所在,最好使用redis INCR命令来实现这一目的 听起来像是原子性问题
// post a vote
app.post('/vote', async (req, res) => {
let count = await getRedisCount(req.body.question_id)
count++
await setRedisCount(req.body.question_id, count)
res.status(200).send({ status: 200, data: count });
})
假设计数是20,那么您的150个请求中的许多请求将读取20作为其值
let count = await getRedisCount(req.body.question_id)
下一条语句将递增并将count设置为21,下一行将尝试将其保存到redis
这是一个标准的比赛条件,更好的解释
您必须在代码中实现锁
,或者使用redis提供的锁来解决此问题
锁基本上会将每个请求排队,一个接一个地递增,以避免覆盖值。不确定这是否可行,但可能会使用
GETSET
?我正在尝试这一点,因为我有同样的问题
谢谢!monitor命令告诉我,例如,在一行中执行了4次该命令:“set”“voates_1”“2”,这让我觉得这更像是一个代码问题-它不应该在一行中设置4次数字2,它应该将其设置为2、3、4、5等。因此,当前它没有在负载平衡器中运行,只有一个Vote服务实例,因此,它绝对不应该多次设置相同的数字。嗯,好的,如果你提交投票时查看浏览器调试工具,它是否每次单击只将其发布到web服务器一次?我没有使用我的浏览器。我用Postman做了一次投票,ApacheJMeter一次做了150次,我发现它错过了这一部分。谢谢。你的代码中肯定有一个缺陷。读/增量/写入算法不是原子算法,这意味着具有不同计数器值的不同读写可以以任何方式交错,并可能导致计数丢失-这正是您所经历的。我对node.js不太熟悉,所以我无法给出正确的答案,但您想使用的是redis增量操作:。您对这里的性能影响有何看法?
redis> INFO
# Server
redis_version 999.999.999
redis_git_sha1:3c968ff0
redis_git_dirty:0
redis_build_id:51089de051945df4
redis_mode:standalone
os:Linux 4.8.0-1-amd64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:6.3.0
process_id:8394
</snip>
// post a vote
app.post('/vote', async (req, res) => {
let count = await getRedisCount(req.body.question_id)
count++
await setRedisCount(req.body.question_id, count)
res.status(200).send({ status: 200, data: count });
})
let count = await getRedisCount(req.body.question_id)