有没有被node-mongodb-native驱动坑过的
发布于 7 年前 作者 heroWang 4181 次浏览 来自 分享

事情是这样的,我们的系统经常出现莫名其妙的卡顿现象.一个正常情况下40ms就完成的请求,有时候会出现短则几秒钟,长则几十秒的延时.经过排查,排除了mongodb慢查询,道理上讲同一个请求,同样的参数数据库查询不可能一会儿快一会儿慢.然后在mongo驱动里打日志分析,确定不是发生了数据库重连.那进一步推断只能是mongo驱动回调机制出现了问题.经过N个小时的问题排查,手段包括加连接数,加服务器,升级mongo驱动到最新版本.这其中只有加连接数奏效了.

还有一个奇怪的现象.在压力测试的时候,查询同一个接口,压到1000qps也不会出现卡顿的,然而放到生产环境后,就会有卡顿.综合这几个分析结果,我猜测是有慢查询影响了快的查询,于是进行了测试.

在测试中,我把连接数限制到2.同时启动两个查询,一块一慢,两个都是每隔一秒查询一次,这个时候能发现快的那个查询存在明显的卡顿现象,一会儿几十毫秒,一会儿就飙到几秒十几秒去了.然而单独执行快查询,时间就很平均且都是几十毫秒就执行完了.更夸张的是,如果连接数调成1,这俩查询是一起回调的,都是十几秒才完成.而如果把这两种查询任务分配独立的连接池,它们之间就没有影响了.

这样就基本得出了结论.node-mongodb-native这个驱动每个连接上的查询是会排队的,并不像熟悉nodejs的人想象的那样基于事件驱动,IO完成就回调,是坑爹的排队执行的,同一个连接前面有慢查询的话,慢查询结束之前后面的查询必须等待!!!

这也解释了为什么加连接数会有效果,因为连接数多了以后,同一个连接数上排队的查询就会少一点,那队列前面存在慢查询的几率也小了.然而连接数优化只能缓解问题,不能从根本上解决问题,当我们把每个进程的连接数从10加到50后,卡顿现象少了一半.从50加到100,没有变化.

解决办法还没有定下来,我测试了java驱动,不存在快慢查询排队现象.先把问题分享出来,看看大家有遇到过这个问题没有.实在不行,打算把数据库查询功能用java写成一个代理服务,不用node这个驱动了.

13 回复

你确定不是在等待连接释放吗?

确认有问题,可以去仓库提issue的,讨论讨论

node-mongodb-native 每个连接上的查询有排队是正常的吧,一个连接一次只能对应一个查询。这个库在初始化的时候,是可以传入连接池大小选项的。

你排查的过程中,有发现是不是mongodb连接数用满吗?如果用满了的话,就加大连接数。如果连接数没有满,那么那些卡顿的查询有什么共性吗?

JAVA也排队的吧,只是java会自己加连接池大小。 我的方法是慢查询和快查询走不同的链接,让快查询永远走快的链接,不要去跟慢的查询一起排队。

@alsotang 连接数没有满,后来加过机器和连接数,连接数肯定是够用的. 如果数据库连接排队是正常的,那怎么解释 express 查询就没有排队的情况呢.node的设计哲学就是I/O完成了callback 而不是排队执行

@jiangzhuo 真不是 我maxConnectionsPerHost我都设置成1了 那么多接口要一个一个去看哪些有慢查询还是挺难的.

@heroWang node再牛逼也得受对方协议限制啊。有些协议不是串行的。 express不排队是因为每个请求都有一个独立的http连接。。。。。。。

@alsotang 同一个tcp连接上我同时发过去两个请求,mongo应该会同时处理这俩请求吧.不懂,求教.

@heroWang 这东西就跟 http 1.1 的协议一样,虽然 tcp 是支持并发的,但一个 tcp 连接上面只能搭载一个 http 1.1 的连接,这个连接只能串行的发出请求。而 http 2.0 则可以在一个连接上实现并发请求。

@alsotang 这样的话好像除了增大连接数也没有别的办法了,但是我们试验的结果是连接数再多驱动也不会去用了.只能是把慢查询找出来使用独立的连接池.有什么好的建议吗?

@heroWang 想要找办法,首先得找出原因。。。再找找原因看吧

@alsotang 嗯. node驱动的round-robin轮询应该没有去检查一个连接前面等待队列的长度或者等待时间吧,我觉得官方那些人可以解决这个问题.

回到顶部