【问题标题】:Redis clients can update cache simultaneously causing wrong state to be savedRedis 客户端可以同时更新缓存导致错误的状态被保存
【发布时间】:2022-11-22 02:11:10
【问题描述】:

我一直在构建一个简单的应用程序,它使用 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 缓存中,首先会保存从 Player1 接收到的值,然后是来自玩家 2 的值,这意味着缓存中的新值将是:

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

尽管这是错误的,因为正确的值应该是:{ roomId: "...", score:[{ "player1": 1 }, { "player2": 1 }] },其中两个更改都存在。

目前,我还在使用发布/订阅系统来跟踪更改,以便将所做的更改反映到每个服务器和连接到服务器的每个用户。

我该怎么做才能解决这个问题?作为参考,将下图视为系统的体系结构:

【问题讨论】:

    标签: caching redis publish-subscribe messaging


    【解决方案1】:

    问题似乎是您将一组读/写操作与其他操作交错,这导致在更新密钥时使用陈旧数据。幸运的是,修复(相对)简单:只需使用 Lua scripttransaction 或更简单的单个 RedisJSON 命令,将您的读/写操作块组合到一个原子单元中。

    这是一个使用 RedisJSON 的示例。使用 JSON.SET 命令准备您的 JSON 密钥/文件,它将首先保存房间的所有分数:

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

    之后,一旦需要将项目附加到分数大批:

    > 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}]}"
    

    【讨论】:

      猜你喜欢
      • 2012-02-07
      • 2020-12-01
      • 1970-01-01
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      • 2021-03-11
      • 2015-07-22
      • 2016-12-17
      相关资源
      最近更新 更多