MongoDB云数据库机器宕机引发的复制集心跳异常问题

Posted 阿里云云栖号

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB云数据库机器宕机引发的复制集心跳异常问题相关的知识,希望对你有一定的参考价值。

问题背景


是由3个节点组成的复制集,node3原来是 Primary 节点,因为硬件故障宕机,云数据库高可用模块检测到后,立即进行了主备切换,保证服务正常,node3重启之后重新加入复制集,变为 Hidden 节点,最终的状态如下表所示:


Primary Secondary Hidden
node1:port1 node2:port2 node3:port3
引发的问题

一、宕机引发的问题


node3重新加入后,服务正常,但复制集内部的通信却还有问题。


从node3的 rs.status()看整个复制集,一切正常,说明 node3到 node1、node2发送心跳请求都正常(每个节点周期性向其他节点发送心跳,通过心跳应答来更新其他节点的状态信息)。


当从 node1、node2的 rs.status()看,node3却处于宕机状态,错误如下:


 {            "_id" : 3,            "name" : "node3:port3",            "health" : 0,            "state" : 8,            "stateStr" : "(not reachable/healthy)",            "uptime" : 0,            "optime" : Timestamp(0, 0),            "optimeDate" : ISODate("1970-01-01T00:00:00Z"),            "lastHeartbeat" : ISODate("2016-07-21T12:30:17.807Z"),            "lastHeartbeatRecv" : ISODate("2016-07-21T12:30:17.544Z"),            "pingMs" : NumberLong(0),            "lastHeartbeatMessage" : "Couldn't get a connection within the time limit",            "configVersion" : -1
        }


也就是说 node1向 node3发送心跳信息是一直失败的,失败的原因是Couldn't get a connection within the time limit node1上执行 netstat,发现 node1已经建立了到 node3的连接 (注意这条连接 tcp keepalive timer 是关闭的):


tcp        0      0 node1:58347          node3:port3           ESTABLISHED off (0.00/0/0)


然而从 node3上执行 netstat,这个连接并不存在。


也就是说,这个连接是 node3宕机之前建立的连接,因为 tcp keepalive 没有打开,加上 node3异常退出,所以这条连接只是一边断开了,node1一端还一直保留着这条连接。


此时只要 node1往 node3通过这个连接发送心跳数据,就会发现对端已经关闭,但实际上没有发送任何数据,在从连接池获取连接的时候就已经出错了(Couldn't get a connection within the time limit),所以心跳并没有发出,事后确定是 MongoDB 的 bug导致,参考。

解决问题

二、解决问题


解决这个问题,最直接的方法就是把 node1、node2的 mongod 进程重启,一切就会恢复正常,但作为云服务应该尽量避免这么做,以减少对用户的影响。猜测只要上述连接只要能在 node1上关闭,node1重新建立连接就能恢复正常,于是尝试来干掉这条 tcp连接。


首先尝试了,但并不能满足需求,tcpkill 的工作方式类似于 tcpdump,要在满足条件的连接上抓到数据包才会触发 kill 连接的动作,而上述的连接上已经没有任何的数据发送了。


tcpkill 依赖 libpcap、这2个库,抓包的功能由 libpcap 实现,而kill连接(实际上是往连接上发送 reset 包)由 libnet 实现。libnet 自带的 sample 里包含了一个简单的工具,能往指定连接发包。


 # ./libnet/sample/tcp2libnet 1.1 packet shaping: TCP[raw]
usage: /tmp/libnet/sample/.libs/lt-tcp2 -s source_ip.source_port -d destination_ip.destination_port [-p payload]


利用这个小工具,向上述连接随便发送了一些数据,连接立即被关闭了,node1向 node3新建立了一条连接来发送心跳,一切恢复正常。


三、为什么关闭tcp keepalive

为什么关闭tcp keepaliv

设计上是应用层会做 keepalive,但实现上的缺陷并没有达到预期的效果,遇到类似问题的用户请升级到MongoDB-3.2最新版本。





点击“阅读原文”可查看原文。




想和这群聪明人共事吗?加入阿里云云栖社区翻译志愿者:yqeditor@list.alibaba-inc.com


投稿或入驻云栖社区,请联系:yqeditor@list.alibaba-inc.com


2016,为了实现更多技术梦想,云栖社区与你携手并行。

yunqiinsight

长按二维码,一网打尽所有深度技术文章



戳原文,更有料!

以上是关于MongoDB云数据库机器宕机引发的复制集心跳异常问题的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB一次节点宕机引发的思考(源码剖析)

MongoDB选举过程

MongoDB副本集主节点的选举过程

MongoDB 复制集

MongoDB 节点宕机引发的思考

MongoDB 复制集节点增加移除及节点属性配置