【问题标题】:How to prevent data inconsistencies with chat application in MongoDB?如何防止MongoDB中的聊天应用程序数据不一致?
【发布时间】:2020-04-28 06:21:17
【问题描述】:

我有一个使用 node.js 和 socket.io 的聊天应用程序,它将用户信息存储在 Redis 和 MongoDB 中。当用户第一次连接到套接字服务器时,会为他们生成一个用户 ID,并且这个 ID(连同他们的用户名)存储在套接字对象中。完整的用户信息(包括头像图片​​、电子邮件等)存储在 MongoDB 中,其中一部分也缓存在 Redis 中。当客户端与套接字服务器断开连接时,该事件由以下事件处理程序处理:

const handleDisconnect = async () => {
  const {userId, username} = socket;
  if (userId && username) {
    try {
      delete socket.userId;
      delete socket.username;

      await redisClient.del(`user:${userId}`);

      await User.findByIdAndDelete(userId);
    } catch (err) {
      console.log(err);
    }
  }
};

现在,由于从 Redis 和 Mongo 中删除用户的命令是异步的,因此至少在理论上它们可能会抛出。例如,如果从 Redis 中删除的命令抛出,那么下面的命令将不会运行,用户也不会从 MongoDB 中删除。

即使一开始就将用户添加到这些数据库中,同样的事情也可能发生,因为理论上数据库命令总是会执行失败并使事情处于不一致的状态。

有处理这些情况的标准方法吗?

我是否应该实施更好的异常处理,以便捕获所有可能的错误,并不断重试数据库命令,直到它们成功?

或者我应该实施某种垃圾收集,定期遍历数据库并清理未成功删除的文档?

【问题讨论】:

  • 分别捕获它们,以便您可以重试和/或继续其他操作?

标签: javascript node.js mongodb redis socket.io


【解决方案1】:

我是否应该实现更好的异常处理,以便捕获所有可能的错误

如果您的 try-catch 块中的每个命令都可能失败,并且您通常希望执行所有这些命令,我​​当然会在 each 命令周围添加一个 try-catch 块,而不是所有命令在一起。

您可以考虑的一种方法是在 redis 中存储一个值,该值指示其余数据是否(完全)在那里,例如用户 ID/用户名。向redis写入数据时,最后设置这个值。清理时,先删除。从redis读取时,检查这个值是否存在,然后继续读取其他数据。这样,您可以在 redis 中保存部分数据,但您的应用程序不会尝试使用它。

对于任何缓存,缓存都有可能过期。您还可以考虑哪些操作需要最新数据(例如身份验证),哪些不需要(例如显示新消息的数量)。后者通常可以容忍一些陈旧。具体程度取决于应用程序。

【讨论】:

    猜你喜欢
    • 2016-12-20
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-03
    • 2019-05-29
    • 1970-01-01
    相关资源
    最近更新 更多