最近的一直进行的工作包括提升 mongo 的性能,在我接手的这段时间里,在 newrelic 上的平均响应时长是 200-300ms,遇到任务堵塞还会暴涨到 600ms 左右一小段时间。

第一次

尝试是升级 mongoose@4.4.9,效果是很明显的,响应时长立马降下来了,平均响应时长 100ms 左右。但,我们观察到 mongo 的连接数直接升了一倍,app 进程在阶段性重启,大约是 20 分钟一次,因为我们用 pm2 的时候,设置了最大内存,一旦超过就自动重启,于是我们放弃了。

期间给 mongo-core 改了一个问题,如果使用 readReference=secondaryPreferred 的话,如果监听的是 open 事件的话,立马开始读数据库则所有的请求都会到 master 上面去。看了代码之后,我尝试监听 fullsetup 事件(顺便吐槽下,这代码,真烂。。。),但请求只会到 master 以及一个 secondary 上面去。

于是我改代码,我把’all’事件给暴露出来了,于是当监听 all 事件的话,就能均匀分布到所有的节点上门去了。当然了,这种情况只会在这种特殊情况下出现,具体测试可以看这里:https://github.com/xizhibei/node-mongodb-test-utils

同时呢,还有另一个问题,就是连接数爆的问题,这真是它的 bug,我那天刚给它改了,等我想提交的时候,作者自己改了,因为这问题不止我一个人发现。目前最新的 mongoose@4.4.12 已经没有这个问题了。其实响应时长降低的原因就在于几乎是每一个请求就会被分配一个连接,所以连接数非常多,响应快,但是代价是内存泄露以及连接数爆棚。

第二次

调整连接参数,就是之前提到过的 #2 ,调整了连接池以及 keepAlive 的数值。

第三次

尝试升级到 mongoose@3.8.39,顺利,响应时长有小幅度的下降。但是当时又出现了一个问题,其中一个数据库的连接数很高,TCP TIME_WAIT 是 Established 的两倍,然后会几个小时就暴增一次,于是 nodejs 进程出现大量 fail connect 错误,整体响应时长也暴增。

另外,3.8.394.4.12 的对比效果不明显,反而是 3.8.39 的效果稍好一些

第四次

经过了第三次,我突然想到,数据库本身是不是有问题,我看了下数据库版本,3.0.3,然后去官网一查,我去,果然有问题!其中刚好就是这个版本,有一个复制集中任务阻塞的 bug,在 3.0.4 中修复了 https://docs.mongodb.org/manual/release-notes/3.0/

于是安排运维升级,升级到最新的 3.2 版本,运维说不行,没法直接升级,于是用 export 与 restore,但是之后无法加入集群,具体原因不清楚,以后再查,先升级要紧,于是改 3.0.11,顺利升级。

戏剧般的效果出来了,响应时长瞬间将至 40ms 左右,升级的那台数据库的 CPU 与查询数瞬间暴涨,但是任务数却没怎么升高,连接数正常,其他数据库的查询几乎没有了,也就是说,这一台数据库就几乎抗住了所有的查询。后来陆续升级了,目前一切正常。

这结果,我梦里都能笑出来,目前性能提升 10 倍左右,平均响应时长 30ms,newrelic 的 apdex 指数文档在 0.98,之前是 0.7-0.9。

两点教训

一、很多性能问题还是得靠升级解决;
二、性能问题要从基础开始排查;

后记

我深知基础设施的改进能带来多大的改变,量变产生质变,你能比竞争对手快 10 倍就意味着你领先非常多了,对于我们来说,性能决定了我们能承载多少用户,能活多久。对于团队发展到一定程度之后的技术债务,尽早还清,所以也希望能分清团队里重要与紧急的任务。


原链接: https://github.com/xizhibei/blog/issues/5

知识共享许可协议

本文采用 署名 - 非商业性使用 - 相同方式共享(BY-NC-SA) 进行许可。