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

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

Моя проблема заключается в том, что когда пользователь выполняет задачу, его оценка обновляется, что означает, что он обновит запись в Redis, заменив предыдущее значение новым (в моем случае он заменит весь объект комнаты новым, даже если комната не изменилась, а изменился только счет игрока внутри комнаты).

Дело в том, что если несколько пользователей выполнят задачу одновременно, они будут одновременно отправлять новую запись в redis, и только последний получит обновление.

Например:

В кеше Redis это начальное значение: { roomId: "...", score:[{ "player1": 0 }, { "player2": 0 }] }

Игрок 1 выполняет задание и отправляет:

{ roomId: "...", score:[{ "player1": 1 }, { "player2": 0 }] }

При этом Игрок 2 выполняет задание и отправляет:

{ roomId: "...", score:[{ "player1": 0 }, { "player2": 1 }] }

В кеше Redis сначала будет сохранено значение, полученное, скажем, от игрока 1, а затем значение от игрока 2, что означает, что новое значение в кеше будет:

{ roomId: "...", score:[{ "player1": 0 }, { "player2": 1 }] }

Хотя это неправильно, потому что правильное значение будет: { roomId: "...", score:[{ "player1": 1 }, { "player2": 1 }] } где присутствуют оба изменения.

На данный момент я также использую систему pub/sub для отслеживания изменений, чтобы они отражались на каждом сервере и каждом пользователе, подключенном к серверу.

Что я могу сделать, чтобы исправить это? Для справки рассмотрим следующее изображение как архитектуру системы:

Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
0
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема заключается в том, что вы чередуете один набор операций чтения/записи с другими, что приводит к использованию устаревших данных при обновлении ключей. К счастью, это (относительно) легко исправить: просто объедините блок операций чтения/записи в единую атомарную единицу, используя Lua-скрипт , транзакцию или, что еще проще, с помощью одного RedisJSON. команда.

Вот пример использования RedisJSON. Сначала подготовьте ключ/документ JSON, в котором будут храниться все оценки для комнаты, используя команду JSON.SET:

> JSON.SET room:foo $ '{ "roomId": "foo", "score": [] }'
OK

После этого используйте команду JSON.ARRAPPEND, если вам нужно добавить элемент в массив оценок:

> JSON.ARRAPPEND room:foo $.score '{ "player1": 123 }'
1
...
> JSON.ARRAPPEND room:foo $.score '{ "player2": 456 }'
2

Получить весь документ JSON так же просто, как запустить:

> JSON.GET room:foo
"{\"roomId\":\"foo\",\"score\":[{\"player1\":123},{\"player2\":456}]}"

Другие вопросы по теме