HomeBlogProjects

MongoDB 读写分离踩坑

sorcererxw

发现问题与排查

这两天开发了一个后端更新用户个人信息的接口 POST /profile, 最初的设计是前端提交请求之后,后端更新信息之后,并从数据库里面读取最新的数据,返回给客户端。就是一个写+读的操作,非常简单,很快就开发完了,并通过了单元测试,上线到测试环境。

不过很快测试同学就告诉我每次更新完返回的数据都不是最新的,返回了上一次的旧数据。不应该啊,明明已经通过了单元测试。

于是开始排查,一开始是怀疑代码里面的 Promise 被异步调用了,本地单元测试执行速度过快而没有发现问题。但很快这个问题就被排除了,很明显,如果异步调用了,在 event loop 模式下根本不可能存在正确的情况。

然后开始将目光放到了项目当中使用的 ODM 上,我使用的 MongoDB ODMMongoose, 因为原生的 Mongoose 应该是对不同事件进行 callback 来执行相关逻辑的,但是切换到现在的 async/await 模式,担心 await 的结果不是真实的调用结果。或者说,怀疑 Mongoose 将数据操作发送到 MongoDB 服务器将认为请求成功,那么调用方应该是无法实时获得新的数据的。查了一圈 StackOverflow,翻了一遍文档,发现 Mongoose 的更新操作确实是同步的,一定是 MongoDB 确实写入了数据才返回结果。

最后,将目光瞄向了数据库连接配置上,最后在注意到了 MongoDB 的 url 上有一个参数 readPreference=secondaryPreferred。这下我才恍然大悟过来,原来这中间的延迟出现在 MongoDB 主从复制。这样,同样也能解释为什么本地单元测试就能通过,而线上环境就会出现问题:因为本地连接的并不是数据库集群,所有读写都存在于主库当中,这样就不会存在时延。

解决方案

既然找到问题,那么就得考虑如何解决这个问题