跳至正文

实际业务开发中使用Mongo DB Replication 写入后立即读取数据不一致

我在开发实际服务时使用 MongoDB 时遇到了问题。问题是,如果写入后立即读取相同的数据,则数据未得到确认。当时我对题材不太了解,所以花了很多时间,也吃了不少苦头。我写了这个问题的情况和原因。

问题情况

  • 当时公司主要在很多服务中使用**MongoDB。
  • 在创建新服务和准备全球发布时发现的问题。 经过阶段测试,服务投入生产时出现异常行为
    • 服务器请求的查询间歇性失败(客户端调用的服务器查询内部写入mongodb,然后再次读取数据)
    • 正常操作时,必须重新读取写入的数据并执行下一步操作,但如果失败,则客户端会遇到错误。
    • 查询按照以下流程进行:
      • 客户来电
      • 向服务器请求AWS服务并等待结果
      • AWS服务完成后将结果写入mongodb
      • 写入后,再次从mongodb中读取数据,执行以下操作
    • 在服务器上查看AWS服务查询时,AWS服务运行正常。
    • 当我直接进入mongodb查看服务器的写入部分时,数据确实存在。也就是说,确认了写入操作没有问题。
    • 服务器查询读取部分失败,但db中有写入数据。由于具体原因尚不清楚,因此难以纠正的情况。
  • 在现有测试环境检查未发现异常
    • 测试环境为staging。产品中出现了测试时根本没有出现的现象。

解决

  • 起初并没有被认为是环境的差异,而是认为是代码的bug,检查了逻辑。即使检查了好几遍,也没有发现什么大问题。
  • 一直检查没找到解决办法,就请教了解较多的同事,一起检查
    • 这是一个连我的同事都不熟悉的问题,所以需要一些时间来解决。
  • 当时我了解了一点分布式DB,能够推导出问题。
    • 比较阶段和生产之间的差异以发现问题。比较差异时,差异如下:
    • 在阶段中,MongoDB 在单个节点上运行,没有复制。
    • 在生产中,MongoDB 有两个复制辅助节点。
  • 在生产环境中,配置了副本集以确保可用性。
    • 在复制中,生产MongoDB写入数据,然后将数据传播到辅助节点。
    • 由于没有单独设置,如果从 db 写入并立即读取,则读取操作会在数据传播到辅助数据库之前执行。辅助将现有数据作为响应值传递
      • 传播时间被确认约为 2 至 4 秒。
    • 后来检查mongodb compass中的数据时,传播时间已经过去,读取时写入的数据正确可见。
  • 当时出现的解决上述问题的方法如下。
    • 等待客户端轮询,直到数据库状态发生变化。这似乎是最简单的方法。
    • 等待服务器轮询,直到数据库状态发生变化。从客户端的角度来看,现有的查询无需更改即可使用。
    • 确保向mongodb查询的传播完成并设置为可读,例如查询或集合
  • 我尝试了上述方法中的第二种方法。 不是在写入后立即进行读操作,而是在写入和读取之间添加了一个小的延迟
    • 添加延迟后检查是否正常运行
  • 通过这次,我对CAP理论有了更多的了解。
    • 在分布式结构的情况下,具有一致性、可用性、分区容错性三个特征。
    • 要满足一致性和可用性其中之一,就必须放弃另一个。
      • 满足一致性时:无论访问哪个分布式节点,数据值都必须相同。如果一致性被破坏,则请求查询时可以传递不同的数据。
      • 当可用性满足时:即使一个或多个分布式节点无法同步,也能提供正常处理请求的能力。
    • 由于当前数据库结构满足可用性而导致一致性被破坏的情况。

组织

  • 如果在db中设置了复制,当写入和读取时间不同时要小心
  • 亲眼看到、感受到CAP理论是一次很好的体验。
  • 有时间就研究一下我正在开发的服务吧。您不可能知道所有事情,但是您知道的越多,对故障排除就越有帮助。
  • 请注意,舞台和制作之间的环境可能会有所不同。也就是说,如果测试环境和实际运行环境有差异,可能会出现问题,最好提前考虑一下。
    • 为了减少调试时间,最好保持生产和阶段环境几乎相似或相同。
    • 时间也是一种成本。许多事情,例如劳动力成本和服务开放延迟,都可能会被延迟或导致额外成本。我认为只要成本与服务器成本相比不是太大,舞台和制作设置相同就可以了。