加入收藏 | 设为首页 | 会员中心 | 我要投稿 威海站长网 (https://www.0631zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

MongoDB一次节点宕机引发的思考

发布时间:2019-11-05 07:23:48 所属栏目:MySql教程 来源:java架构coid
导读:简介 最近一个 MongoDB 集群环境中的某节点异常下电了,导致业务出现了中断,随即又恢复了正常。 通过ELK 告警也监测到了业务报错日志。 运维部对于节点下电的原因进行了排查,发现仅仅是资源分配上的一个失误导致。 在解决了问题之后,大家也对这次中断的

代码如下:

  1. HeartbeatResponseAction TopologyCoordinatorImpl::processHeartbeatResponse(...) { 
  2.   
  3.  ... 
  4.  const Milliseconds alreadyElapsed = now - hbStats.getLastHeartbeatStartDate(); 
  5.  Date_t nextHeartbeatStartDate; 
  6.  // 计算下一次 心跳启动时间 
  7.  // numFailuresSinceLastStart 对应连续失败的次数(2次以内) 
  8.  if (hbStats.getNumFailuresSinceLastStart() <= kMaxHeartbeatRetries && 
  9.  alreadyElapsed < _rsConfig.getHeartbeatTimeoutPeriod()) { 
  10.  // 心跳失败,不等待,直接重试心跳 
  11.  nextHeartbeatStartDate = now; 
  12.  } else { 
  13.  // 心跳成功,等待一定间隔后再次发送(一般是2s) 
  14.  nextHeartbeatStartDate = now + heartbeatInterval; 
  15.  } 
  16.  ... 
  17.  // 决定下一步的动作,可能发生 tack over(本备节点优先级更高,且数据与主节点一样新时) 
  18.  HeartbeatResponseAction nextAction; 
  19.  if (_rsConfig.getProtocolVersion() == 0) { 
  20.  ... 
  21.  } else { 
  22.  nextAction = _updatePrimaryFromHBDataV1(memberIndex, originalState, now, myLastOpApplied); 
  23.  } 
  24.  nextAction.setNextHeartbeatStartDate(nextHeartbeatStartDate); 
  25.  return nextAction; 

electionTimeout 定时器

至此,我们已经知道了心跳实现的一些细节,默认情况下副本集节点会每2s向其他节点发出心跳(默认的超时时间是10s)。

如果心跳成功,将会持续以2s的频率继续发送心跳,在心跳失败的情况下,则会立即重试心跳(以更短的超时时间),一直到心跳恢复成功或者超过10s的周期。

那么,心跳失败是如何触发主备切换的呢,electionTimeout 又是如何发挥作用?

在前面的过程中,与electionTimeout参数相关两个方法如下,它们也分别对应了单独的定时器:

ReplicationCoordinatorImpl::_scheduleNextLivenessUpdate_inlock 发起保活状态检查定时器

ReplicationCoordinatorImpl::_cancelAndRescheduleElectionTimeout_inlock 重新发起选举超时定时器

第一个是 _scheduleNextLivenessUpdate_inlock这个函数,它的作用在于保活状态检测,如下:

  1. void ReplicationCoordinatorImpl::_scheduleNextLivenessUpdate_inlock() { 
  2.  //仅仅支持3.2+ 
  3.  if (!isV1ElectionProtocol()) { 
  4.  return; 
  5.  } 
  6.   
  7.  // earliestDate 取所有节点中更新时间最早的(以尽可能早的发现问题) 
  8.  // electionTimeoutPeriod 默认为 10s 
  9.  auto nextTimeout = earliestDate + _rsConfig.getElectionTimeoutPeriod(); 
  10.   
  11.  // 设置超时回调函数为 _handleLivenessTimeout 
  12.  auto cbh = _scheduleWorkAt(nextTimeout, 
  13.  stdx::bind(&ReplicationCoordinatorImpl::_handleLivenessTimeout, 
  14.  this, 
  15.  stdx::placeholders::_1)); 

因此,在大约10s后,如果没有什么意外,_handleLivenessTimeout将会被触发,如下:

  1. void ReplicationCoordinatorImpl::_handleLivenessTimeout(...) { 
  2.  ... 
  3.  for (auto&& slaveInfo : _slaveInfo) { 
  4.  ... 
  5.  //lastUpdate 不够新(小于electionTimeout) 
  6.  if (now - slaveInfo.lastUpdate >= _rsConfig.getElectionTimeoutPeriod()) { 
  7.  ... 
  8.  //在保活周期后仍然未更新节点,置为down状态 
  9.  slaveInfo.down = true; 
  10.  //如果当前节点是主,且检测到某个备节点为down的状态,进入memberdown流程 
  11.  if (_memberState.primary()) { 
  12.   
  13.  //调用_topCoord的setMemberAsDown方法,记录某个备节点不可达,并获得下一步的指示 
  14.  //当大多数节点不可见时,这里会获得让自身降备的指示 
  15.  HeartbeatResponseAction action = 
  16.  _topCoord->setMemberAsDown(now, memberIndex, _getMyLastDurableOpTime_inlock()); 
  17.  //执行指示 
  18.  _handleHeartbeatResponseAction(action, 
  19.  makeStatusWith<ReplSetHeartbeatResponse>(), 
  20.  true); 
  21.  } 
  22.  } 
  23.  } 
  24.  //继续调度下一个周期 
  25.  _scheduleNextLivenessUpdate_inlock(); 

可以看到,这个定时器主要是用于实现主节点对其他节点的保活探测逻辑:

当主节点发现大多数节点不可达时(不满足大多数原则),将会让自己执行降备

(编辑:威海站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读