机器宕机引发的复制集心跳异常问题

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介:

问题背景

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导致,参考SERVER-24058.

解决问题

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

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

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

 # ./libnet/sample/tcp2
libnet 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

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

相关文章
|
3月前
|
存储 分布式计算 运维
ChunkServer 故障恢复机制
【8月更文第30天】在分布式文件系统中,如Google的GFS(Google File System)或Hadoop的HDFS(Hadoop Distributed File System),数据被划分为多个块(chunks),并分散存储在多个ChunkServer上。这种分布式的存储方式提高了系统的可扩展性和容错能力。然而,由于硬件故障和网络中断不可避免,ChunkServer需要具备强大的故障恢复机制来确保数据的一致性和可用性。本文将深入探讨ChunkServer在遇到硬件故障或网络中断时如何自动恢复数据的一致性,并通过伪代码示例来说明这些机制的工作原理。
56 0
|
3月前
|
存储 缓存 Kubernetes
在K8S中,集群节点宕机,可能由哪些原因造成?
在K8S中,集群节点宕机,可能由哪些原因造成?
|
运维 监控 NoSQL
记一次redis主从切换导致的数据丢失与陷入只读状态故障
背景 最近一组业务redis数据不断增长需要扩容内存,而扩容内存则需要重启云主机,在按计划扩容升级执行主从切换时意外发生了数据丢失与master进入只读状态的故障,这里记录分享一下。 业务redis高可用架构 该组业务redis使用的是一主一从,通过sentinel集群实现故障时的自动主从切换,这套架构已经平稳运行数年,经历住了多次实战的考验。 高可用架构大体如下图所示: 简单说一下sentinel实现高可用的原理: 集群的多个(2n+1,N>1)哨兵会定期轮询redis的所有master/slave节点,如果sentinel集群中超过一半的哨兵判定redis某个节点已主观下线,就会将
|
监控
一个 datanode 宕机,恢复流程
一个 datanode 宕机,恢复流程
326 0
|
NoSQL Redis 开发者
集群-主从下线与主从切换|学习笔记
快速学习集群-主从下线与主从切换
|
SQL 关系型数据库 MySQL
《叶问》38期,MGR整个集群挂掉后,如何才能自动选主,不用手动干预
《叶问》38期,MGR整个集群挂掉后,如何才能自动选主,不用手动干预
393 0
LXJ
|
监控 关系型数据库 MySQL
同时监控多台mysql主从
能够监控多个mysql主从监控
LXJ
137 0
|
搜索推荐 网络安全 数据库
服务器宕机原因
服务器宕机原因 阿里云服务器经常CPU跑满,服务器宕机彻底解决方法 要解决这个问题首先先要知道问题出在哪里下面给大家介绍一下CPU跑满的一个案例 解决方法在文章最下方 CPU跑满的问题出现过很多次,最多的时候一天跑满四五次,整个网站在这样的环境下运营如何使得,发工单处理过几次,都是让重启服务器好的。
2974 0
|
索引 安全 搜索推荐
服务器宕机可能的原因以及服务器宕机解决办法
服务器宕机可能的原因以及服务器宕机解决办法 服务器宕机是指服务器因为某些原因而导致服务器无法运转,造成网络无法正常使用。 对于网站来说,服务器宕机所造成影响很大,它不但造成访客无妨对网站进行访问,甚至还可能影响到网站在搜索引擎上的收录和排名, 因而在租用服务器时,建议站长选择想美国服务器这种出现宕机概率比较低的服务器。
4280 0