mongodb 同步延迟 读不到数据

由于负载过大,使得mongodb 的主从库存在同步延迟,导致有的时候读取不到最新的数据。

本来是准备在存储时再加一层redis缓存层,从缓存层读取,但是该数据库有两个应用在使用,我们无法控制另一个应用,故只能从mongodb上读取。

由于需要分库来缓解主库的读写压力,故不能设置为全从主库读取。

是否可以通过写一个特殊方法,使得该方法是直接从主库读取数据,而其他正常方法则仍旧从分库读取?如果可以的话,需要加什么参数才能实现?

阅读 6.6k
3 个回答

由于负载过大,使得mongodb 的主从库存在同步延迟,导致有的时候读取不到最新的数据。

一致性(Consistency),可用性(Availability),分区容忍性(Partition tolerance)三者只能取其二,这是著名的CAP理论陈述的内容。分布式系统大部分都是取了A和P放弃C并转而保证最终一致性(Eventual Consistency),所以无论负载如何,延迟是一定存在的,只是时间长短问题。那么假设负载小,你就能保证马上能从从库上读到?那只能代表复制的速度正好比程序从写到读所花的时间要短而已,换名话说这是运气。如果把代码构建在运气之上,这是道送命题。
你应该从逻辑上保证,程序写完开始读的时候,从库上一定已经复制到了刚才写入的数据。当然不是靠sleep。在程序中sleep的话,又一道送命题。正确的做法是{w: "majority"},即写的时候阻塞到写到大多数结点写完才算完成。有了这点还是不够的,因为你要读的从结点并不能保证一定在“大多数”之内。为了保证读结点在“大多数”之内(假设是3结点复制集的情况下),是不是可以用{w: 3}呢?又一道送命题。很显然如果有一个结点当了你的所有写都会失败。正确的选择是{readConcern: "majority"}——多数结点有的才算有。
成功避开了所有送命题之后得到了解决方案{w: "majority"} + {readConcern: "majority"},你会发现现在做什么事情都要集群的大多数承认,也就是说一个请求要压在大多数结点之上,有违你分散压力的初衷(而且恐怕压力更大了)。没有办法,天下没有免费的午餐,并且复制集的主要目的本来也不是冲着分散压力来的。想避免这样的情况最简单的办法就是不要从从结点读啊,从主结点读不就没有延迟的问题了?控制的办法是readPreference=primary(readPreference)。所以,对时效性要求高的数据从primary读,否则才从secondary读。
可能你还想问如果大部分请求都要求时效性怎么办?压力可能还是集中在primary上。那就应该是分片的时候了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题