Redis не обновляется, когда много запросов одновременно - PullRequest
2 голосов
/ 07 июня 2019

У меня есть приложение Node.js, и я пытаюсь использовать кэш Redis для подсчета количества сделанных запросов.Это просто подтверждение концепции, чтобы увидеть, является ли Redis подходящим инструментом для меня, но я немного разочарован результатом, и мне интересно, действительно ли Redis работает очень плохо или есть ли в моем коде изъян *.1001 *

У меня есть следующий код:

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.счетчик обновляется, как и ожидалось.

Но когда я запускаю тест в JMeter, где я делаю 150 запросов одновременно, я получаю счет около 20-30 после последнего запроса вместо ожидаемых 150.

Так что мойвопрос - это ожидаемое поведение, или это ошибка в моем коде?и в обоих случаях - как это исправить?

Ответы [ 2 ]

2 голосов
/ 07 июня 2019

Возможно, это связано с настройкой вашего сервера Redis.

Вы можете запустить MONITOR из redis cli на вашем хост-компьютере.

Обычно вы подключаетесь через cli, например:

https://redis.io/topics/rediscli

redis-cli -h <your server ip> -p <your server port> -a <if you have a server password enabled>

$ redis-cli -h host -p port -a password

Порт по умолчанию: 6379

Это покажет все взаимодействия с сервером Redis, но не запускайте его, так как он всегда работает, но имеет снижение производительности, но отлично подходит для устранения неполадок.

https://redis.io/commands/monitor

 $ redis> monitor
 1339518083.107412 [0 127.0.0.1:60866] "keys" "*"
 1339518087.877697 [0 127.0.0.1:60866] "dbsize"
 1339518090.420270 [0 127.0.0.1:60866] "set" "x" "6"
 1339518096.506257 [0 127.0.0.1:60866]

Это должно дать вам представление о проблеме.

Вы также можете запустить команду INFO из redis cli, чтобы просмотреть статистику сервера и информацию, такую ​​как использование памяти.

https://redis.io/commands/info

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>

Также используйте команду INCRBY из вашего Redis-клиента в вашем коде, в противном случае потребуется увеличить значение счетчика перед его установкой, что не соответствует асинхронному шаблону.

https://redis.io/commands/incrby

Я думаю, что ваша проблема в том, что это асинхронно, верно?

Таким образом, отсчеты не синхронизируются, когда они публикуются, так как некоторые могут ожидаться раньше, чем другие.

В любом случае, вы можете попробовать опубликовать их синхронно, чтобы увидеть, если это имеет значениетогда вы знаете, что это проблема, и для этой цели было бы лучше использовать команды Redis INCR.

0 голосов
/ 08 июня 2019

Звучит как проблема атомарности.

// 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)

следующий оператор будет увеличиваться и устанавливать счетчик в 21, а следующая строка попытается сохранить его в redis.

Это стандартное условие гонки, лучше объясненное https://en.wikipedia.org/wiki/Race_condition#Example

Вы должны будете внедрить lock либо в своем коде, либо использовать тот, который предоставлен redis для решения этой проблемы.

Блокировка, по существу, ставит в очередь каждый запрос, чтобы увеличивать один за другим, избегая перезаписи значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...