简体   繁体   English

Redis 客户端可以同时更新缓存导致错误的 state 被保存

[英]Redis clients can update cache simultaneously causing wrong state to be saved

I have been building a simple application that uses Redis as cache to store data regarding a game where each user has a score and after a user completes a task the score is updated for the user.我一直在构建一个简单的应用程序,它使用 Redis 作为缓存来存储有关游戏的数据,其中每个用户都有分数,并且在用户完成任务后会为用户更新分数。

My problem is when a user completes a task his score is updated which means that it will update the record in redis by replacing the previous value with the new one (in my case it will replace the entire room object with the new one even though the room has not changed but only the score of the player inside the room has changed).我的问题是,当用户完成一项任务时,他的分数会更新,这意味着它将通过用新值替换以前的值来更新 redis 中的记录(在我的情况下,它将用新值替换整个房间 object,即使房间没有改变,只有房间内玩家的分数发生了变化)。

The thing is if multiple users complete a task at the same time they will send each at the same time the new record to redis and only the last one will receive the update.问题是,如果多个用户同时完成一项任务,他们将同时向每个用户发送新记录到 redis,只有最后一个用户会收到更新。

For example:例如:

In the redis cache this is the starting value: { roomId: "...", score:[{ "player1": 0 }, { "player2": 0 }] }在 redis 缓存中,这是起始值: { roomId: "...", score:[{ "player1": 0 }, { "player2": 0 }] }

Player 1 completes a task and sends:玩家 1 完成任务并发送:

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

At the same time Player 2 completes a task and sends:同时玩家 2 完成一个任务并发送:

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

In the redis cache first it will be saved the value received from Player1 let's say and then the value from player 2 which means that the new value in the cache will be:在 redis 缓存中,首先会保存从 Player1 收到的值,然后是来自玩家 2 的值,这意味着缓存中的新值将是:

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

Even though this is wrong because the correct value would be: { roomId: "...", score:[{ "player1": 1 }, { "player2": 1 }] } where both changes are present.尽管这是错误的,因为正确的值应该是: { roomId: "...", score:[{ "player1": 1 }, { "player2": 1 }] }其中两个更改都存在。

At the moment I am also using a pub/sub system to keep track of changes so that does are reflected to every server and each user connected to the server.目前,我还在使用发布/订阅系统来跟踪更改,以便将所做的更改反映到每个服务器和连接到服务器的每个用户。

What can I do to fix this?我该怎么做才能解决这个问题? For reference consider the following image as the architecture of the system:作为参考,将下图视为系统的体系结构:

在此处输入图像描述

The issue appears to be that you are interleaving one read/write set of operation with others, which leads to using stale data while updating keys.问题似乎是您将一组读/写操作与其他操作交错,这导致在更新密钥时使用陈旧数据。 Fortunately, the fix is (relatively) easy: just combine your read/write chunk of operations into a single atomic unit, using either a Lua script , a transaction or, even easier, through a single RedisJSON command.幸运的是,修复(相对)简单:只需使用Lua 脚本事务或更简单的方法,通过单个RedisJSON命令,将您的读/写操作块合并到一个原子单元中。

Here is an example using RedisJSON.这是一个使用 RedisJSON 的示例。 Prepare your JSON key/document which will hold all the scores for the room first, using the JSON.SET command:使用JSON.SET命令准备您的 JSON 钥匙/文件,它将首先保存房间的所有分数:

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

After that, use the JSON.ARRAPPEND command once you need to append an item to the score array:之后,一旦需要将 append 项添加到分数数组中,请使用JSON.ARRAPPEND命令:

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

Getting back the whole JSON document is as easy as running:取回整个 JSON 文档就像运行一样简单:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM