自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考

運(yùn)維 數(shù)據(jù)庫運(yùn)維 MongoDB
最近一個 MongoDB 集群環(huán)境中的某節(jié)點異常下電了,導(dǎo)致業(yè)務(wù)出現(xiàn)了中斷,隨即又恢復(fù)了正常。

[[281208]]

簡介

最近一個 MongoDB 集群環(huán)境中的某節(jié)點異常下電了,導(dǎo)致業(yè)務(wù)出現(xiàn)了中斷,隨即又恢復(fù)了正常。

通過ELK 告警也監(jiān)測到了業(yè)務(wù)報錯日志。

運(yùn)維部對于節(jié)點下電的原因進(jìn)行了排查,發(fā)現(xiàn)僅僅是資源分配上的一個失誤導(dǎo)致。 在解決了問題之后,大家也對這次中斷的也提出了一些問題:

"當(dāng)前的 MongoDB集群 采用了分片副本集的架構(gòu),其中主節(jié)點發(fā)生故障會產(chǎn)生多大的影響?"

"MongoDB 副本集不是能自動倒換嗎,這個是不是秒級的?"

帶著這些問題,下面針對副本集的自動Failover機(jī)制做一些分析。

日志分析

首先可以確認(rèn)的是,這次掉電的是一個副本集上的主節(jié)點,在掉電的時候,主備關(guān)系發(fā)生了切換。

從另外的兩個備節(jié)點找到了對應(yīng)的日志:

備節(jié)點1的日志

  1. 2019-05-06T16:51:11.766+0800 I REPL [ReplicationExecutor] Starting an election, since we've seen no PRIMARY in the past 10000ms 
  2. 2019-05-06T16:51:11.766+0800 I REPL [ReplicationExecutor] conducting a dry run election to see if we could be elected 
  3. 2019-05-06T16:51:11.766+0800 I ASIO [NetworkInterfaceASIO-Replication-0] Connecting to 172.30.129.78:30071 
  4. 2019-05-06T16:51:11.767+0800 I REPL [ReplicationExecutor] VoteRequester(term 3 dry run) received a yes vote from 172.30.129.7:30071; response message: { term: 3, voteGranted: true, reason: "", ok: 1.0 } 
  5. 2019-05-06T16:51:11.767+0800 I REPL [ReplicationExecutor] dry election run succeeded, running for election 
  6. 2019-05-06T16:51:11.768+0800 I ASIO [NetworkInterfaceASIO-Replication-0] Connecting to 172.30.129.78:30071 
  7. 2019-05-06T16:51:11.771+0800 I REPL [ReplicationExecutor] VoteRequester(term 4) received a yes vote from 172.30.129.7:30071; response message: { term: 4, voteGranted: true, reason: "", ok: 1.0 } 
  8. 2019-05-06T16:51:11.771+0800 I REPL [ReplicationExecutor] election succeeded, assuming primary role in term 4 
  9. 2019-05-06T16:51:11.771+0800 I REPL [ReplicationExecutor] transition to PRIMARY 
  10. 2019-05-06T16:51:11.771+0800 I REPL [ReplicationExecutor] Entering primary catch-up mode. 
  11. 2019-05-06T16:51:11.771+0800 I ASIO [NetworkInterfaceASIO-Replication-0] Ending connection to host 172.30.129.78:30071 due to bad connection status; 2 connections to that host remain open 
  12. 2019-05-06T16:51:11.771+0800 I ASIO [NetworkInterfaceASIO-Replication-0] Connecting to 172.30.129.78:30071 
  13. 2019-05-06T16:51:13.350+0800 I REPL [ReplicationExecutor] Error in heartbeat request to 172.30.129.78:30071; ExceededTimeLimit: Couldn't get a connection within the time limit 

備節(jié)點2的日志

  1. 2019-05-06T16:51:12.816+0800 I ASIO [NetworkInterfaceASIO-Replication-0] Ending connection to host 172.30.129.78:30071 due to bad connection status; 0 connections to that host remain open 
  2. 2019-05-06T16:51:12.816+0800 I REPL [ReplicationExecutor] Error in heartbeat request to 172.30.129.78:30071; ExceededTimeLimit: Operation timed out, request was RemoteCommand 72553 -- target:172.30.129.78:30071 db:admin expDate:2019-05-06T16:51:12.816+0800 cmd:{ replSetHeartbeat: "shard0", configVersion: 96911, from: "172.30.129.7:30071", fromId: 1, term: 3 } 
  3. 2019-05-06T16:51:12.821+0800 I REPL [ReplicationExecutor] Member 172.30.129.160:30071 is now in state PRIMARY 

可以看到,備節(jié)點1在 16:51:11 時主動發(fā)起了選舉,并成為了新的主節(jié)點,隨即備節(jié)點2在 16:51:12 獲知了最新的主節(jié)點信息,因此可以確認(rèn)此時主備切換已經(jīng)完成。

同時在日志中出現(xiàn)的,還有對于原主節(jié)點(172.30.129.78:30071)大量心跳失敗的信息。

那么,備節(jié)點具體是怎么感知到主節(jié)點已經(jīng) Down 掉的,主備節(jié)點之間的心跳是如何運(yùn)作的,這對數(shù)據(jù)的同步復(fù)制又有什么影響?

下面,我們挖掘一下 ** 副本集的 自動故障轉(zhuǎn)移(Failover)** 機(jī)制

副本集 如何實現(xiàn) Failover

如下是一個PSS(一主兩備)架構(gòu)的副本集,主節(jié)點除了與兩個備節(jié)點執(zhí)行數(shù)據(jù)復(fù)制之外,三個節(jié)點之間還會通過心跳感知彼此的存活。

 

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考(源碼剖析)

 

一旦主節(jié)點發(fā)生故障以后,備節(jié)點將在某個周期內(nèi)檢測到主節(jié)點處于不可達(dá)的狀態(tài),此后將由其中一個備節(jié)點事先發(fā)起選舉并最終成為新的主節(jié)點。 這個檢測周期 由electionTimeoutMillis 參數(shù)確定,默認(rèn)是10s。

 

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考(源碼剖析)

 

接下來,我們通過一些源碼看看該機(jī)制是如何實現(xiàn)的:

<<來自 MongoDB 3.4源碼>>

db/repl/replication_coordinator_impl_heartbeat.cpp

相關(guān)方法

  • ReplicationCoordinatorImpl::_startHeartbeats_inlock 啟動各成員的心跳
  • ReplicationCoordinatorImpl::_scheduleHeartbeatToTarget 調(diào)度任務(wù)-(計劃)向成員發(fā)起心跳
  • ReplicationCoordinatorImpl::_doMemberHeartbeat 執(zhí)行向成員發(fā)起心跳
  • ReplicationCoordinatorImpl::_handleHeartbeatResponse 處理心跳響應(yīng)
  • ReplicationCoordinatorImpl::_scheduleNextLivenessUpdate_inlock 調(diào)度保活狀態(tài)檢查定時器
  • ReplicationCoordinatorImpl::_cancelAndRescheduleElectionTimeout_inlock 取消并重新調(diào)度選舉超時定時器
  • ReplicationCoordinatorImpl::_startElectSelfIfEligibleV1 發(fā)起主動選舉

db/repl/topology_coordinator_impl.cpp

相關(guān)方法

  • TopologyCoordinatorImpl::prepareHeartbeatRequestV1 構(gòu)造心跳請求數(shù)據(jù)
  • TopologyCoordinatorImpl::processHeartbeatResponse 處理心跳響應(yīng)并構(gòu)造下一步Action實例

下面這個圖,描述了各個方法之間的調(diào)用關(guān)系

 

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考(源碼剖析)

 

圖-主要關(guān)系

心跳的實現(xiàn)

首先,在副本集組建完成之后,節(jié)點會通過ReplicationCoordinatorImpl::_startHeartbeats_inlock方法開始向其他成員發(fā)送心跳:

  1. void ReplicationCoordinatorImpl::_startHeartbeats_inlock() { 
  2.  const Date_t now = _replExecutor.now(); 
  3.  _seedList.clear(); 
  4.  //獲取副本集成員 
  5.  for (int i = 0; i < _rsConfig.getNumMembers(); ++i) { 
  6.  if (i == _selfIndex) { 
  7.  continue
  8.  } 
  9.  //向其他成員發(fā)送心跳 
  10.  _scheduleHeartbeatToTarget(_rsConfig.getMemberAt(i).getHostAndPort(), i, now); 
  11.  } 
  12.  //僅僅是刷新本地的心跳狀態(tài)數(shù)據(jù) 
  13.  _topCoord->restartHeartbeats(); 
  14.  //使用V1的選舉協(xié)議(3.2之后) 
  15.  if (isV1ElectionProtocol()) { 
  16.  for (auto&& slaveInfo : _slaveInfo) { 
  17.  slaveInfo.lastUpdate = _replExecutor.now(); 
  18.  slaveInfo.down = false
  19.  } 
  20.  //調(diào)度?;顮顟B(tài)檢查定時器 
  21.  _scheduleNextLivenessUpdate_inlock(); 
  22.  } 

在獲得當(dāng)前副本集的節(jié)點信息后,調(diào)用_scheduleHeartbeatToTarget方法對其他成員發(fā)送心跳,

這里_scheduleHeartbeatToTarget 的實現(xiàn)比較簡單,其真正發(fā)起心跳是由 _doMemberHeartbeat 實現(xiàn)的,如下:

  1. void ReplicationCoordinatorImpl::_scheduleHeartbeatToTarget(const HostAndPort& target, 
  2.  int targetIndex, 
  3.  Date_t when) { 
  4.  //執(zhí)行調(diào)度,在某個時間點調(diào)用_doMemberHeartbeat 
  5.  _trackHeartbeatHandle( 
  6.  _replExecutor.scheduleWorkAt(when
  7.  stdx::bind(&ReplicationCoordinatorImpl::_doMemberHeartbeat, 
  8.  this, 
  9.  stdx::placeholders::_1, 
  10.  target, 
  11.  targetIndex))); 

ReplicationCoordinatorImpl::_doMemberHeartbeat 方法的實現(xiàn)如下:

  1. void ReplicationCoordinatorImpl::_doMemberHeartbeat(ReplicationExecutor::CallbackArgs cbData, 
  2.  const HostAndPort& target, 
  3.  int targetIndex) { 
  4.  LockGuard topoLock(_topoMutex); 
  5.  //取消callback 跟蹤 
  6.  _untrackHeartbeatHandle(cbData.myHandle); 
  7.  if (cbData.status == ErrorCodes::CallbackCanceled) { 
  8.  return
  9.  } 
  10.  const Date_t now = _replExecutor.now(); 
  11.  BSONObj heartbeatObj; 
  12.  Milliseconds timeout(0); 
  13.  //3.2 以后的版本 
  14.  if (isV1ElectionProtocol()) { 
  15.  const std::pair<ReplSetHeartbeatArgsV1, Milliseconds> hbRequest = 
  16.  _topCoord->prepareHeartbeatRequestV1(now, _settings.ourSetName(), target); 
  17.  //構(gòu)造請求,設(shè)置一個timeout 
  18.  heartbeatObj = hbRequest.first.toBSON(); 
  19.  timeout = hbRequest.second
  20.  } else { 
  21.  ... 
  22.  } 
  23.  //構(gòu)造遠(yuǎn)程命令 
  24.  const RemoteCommandRequest request( 
  25.  target, "admin", heartbeatObj, BSON(rpc::kReplSetMetadataFieldName << 1), nullptr, timeout); 
  26.  //設(shè)置遠(yuǎn)程命令回調(diào),指向_handleHeartbeatResponse方法 
  27.  const ReplicationExecutor::RemoteCommandCallbackFn callback = 
  28.  stdx::bind(&ReplicationCoordinatorImpl::_handleHeartbeatResponse, 
  29.  this, 
  30.  stdx::placeholders::_1, 
  31.  targetIndex); 
  32.  _trackHeartbeatHandle(_replExecutor.scheduleRemoteCommand(request, callback)); 

上面的代碼中存在的一些細(xì)節(jié):

  • 心跳的超時時間,在_topCoord.prepareHeartbeatRequestV1方法中就已經(jīng)設(shè)定好了
  • 具體的算法就是:
  1. **hbTimeout=_rsConfig.getHeartbeatTimeoutPeriodMillis() - alreadyElapsed** 

其中heartbeatTimeoutPeriodMillis是可配置的參數(shù),默認(rèn)是10s, 那么alreadyElapsed是指此前連續(xù)心跳失敗(最多2次)累計的消耗時間,在心跳成功響應(yīng)或者超過10s后alreadyElapsed會置為0。因此可以判斷,隨著心跳失敗次數(shù)的增加,超時時間會越來越短(心跳更加密集)

心跳執(zhí)行的回調(diào),指向自身的_handleHeartbeatResponse方法,該函數(shù)實現(xiàn)了心跳響應(yīng)成功、失敗(或是超時)之后的流程處理。

ReplicationCoordinatorImpl::_handleHeartbeatResponse方法的代碼片段:

  1. void ReplicationCoordinatorImpl::_handleHeartbeatResponse( 
  2.  const ReplicationExecutor::RemoteCommandCallbackArgs& cbData, int targetIndex) { 
  3.  LockGuard topoLock(_topoMutex); 
  4.  // remove handle from queued heartbeats 
  5.  _untrackHeartbeatHandle(cbData.myHandle); 
  6.  ... 
  7.  //響應(yīng)成功后 
  8.  if (responseStatus.isOK()) { 
  9.  networkTime = cbData.response.elapsedMillis.value_or(Milliseconds{0}); 
  10.  const auto& hbResponse = hbStatusResponse.getValue(); 
  11.  // 只要primary 心跳響應(yīng)成功,就會重新調(diào)度 electionTimeout定時器 
  12.  if (hbResponse.hasState() && hbResponse.getState().primary() && 
  13.  hbResponse.getTerm() == _topCoord->getTerm()) { 
  14.  //取消并重新調(diào)度 electionTimeout定時器 
  15.  cancelAndRescheduleElectionTimeout(); 
  16.  } 
  17.  } 
  18.  ... 
  19.  //調(diào)用topCoord的processHeartbeatResponse方法處理心跳響應(yīng)狀態(tài),并返回下一步執(zhí)行的Action 
  20.  HeartbeatResponseAction action = _topCoord->processHeartbeatResponse( 
  21.  now, networkTime, target, hbStatusResponse, lastApplied); 
  22.  ... 
  23.  //調(diào)度下一次心跳,時間間隔采用action提供的信息 
  24.  _scheduleHeartbeatToTarget( 
  25.  target, targetIndex, std::max(now, action.getNextHeartbeatStartDate())); 
  26.  //根據(jù)Action 執(zhí)行處理 
  27.  _handleHeartbeatResponseAction(action, hbStatusResponse, false); 

這里省略了許多細(xì)節(jié),但仍然可以看到,在響應(yīng)心跳時會包含這些事情的處理:

對于主節(jié)點的成功響應(yīng),會重新調(diào)度 electionTimeout定時器(取消之前的調(diào)度并重新發(fā)起)

通過_topCoord對象的processHeartbeatResponse方法解析處理心跳響應(yīng),并返回下一步的Action指示

根據(jù)Action 指示中的下一次心跳時間設(shè)置下一次心跳定時任務(wù)

處理Action指示的動作

那么,心跳響應(yīng)之后會等待多久繼續(xù)下一次心跳呢? 在 TopologyCoordinatorImpl::processHeartbeatResponse方法中,實現(xiàn)邏輯為:

如果心跳響應(yīng)成功,會等待heartbeatInterval,該值是一個可配參數(shù),默認(rèn)為2s;

如果心跳響應(yīng)失敗,則會直接發(fā)送心跳(不等待)。

代碼如下:

  1. HeartbeatResponseAction TopologyCoordinatorImpl::processHeartbeatResponse(...) { 
  2.   
  3.  ... 
  4.  const Milliseconds alreadyElapsed = now - hbStats.getLastHeartbeatStartDate(); 
  5.  Date_t nextHeartbeatStartDate; 
  6.  // 計算下一次 心跳啟動時間 
  7.  // numFailuresSinceLastStart 對應(yīng)連續(xù)失敗的次數(shù)(2次以內(nèi)) 
  8.  if (hbStats.getNumFailuresSinceLastStart() <= kMaxHeartbeatRetries && 
  9.  alreadyElapsed < _rsConfig.getHeartbeatTimeoutPeriod()) { 
  10.  // 心跳失敗,不等待,直接重試心跳 
  11.  nextHeartbeatStartDate = now; 
  12.  } else { 
  13.  // 心跳成功,等待一定間隔后再次發(fā)送(一般是2s) 
  14.  nextHeartbeatStartDate = now + heartbeatInterval; 
  15.  } 
  16.  ... 
  17.  // 決定下一步的動作,可能發(fā)生 tack over(本備節(jié)點優(yōu)先級更高,且數(shù)據(jù)與主節(jié)點一樣新時) 
  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 定時器

至此,我們已經(jīng)知道了心跳實現(xiàn)的一些細(xì)節(jié),默認(rèn)情況下副本集節(jié)點會每2s向其他節(jié)點發(fā)出心跳(默認(rèn)的超時時間是10s)。

如果心跳成功,將會持續(xù)以2s的頻率繼續(xù)發(fā)送心跳,在心跳失敗的情況下,則會立即重試心跳(以更短的超時時間),一直到心跳恢復(fù)成功或者超過10s的周期。

那么,心跳失敗是如何觸發(fā)主備切換的呢,electionTimeout 又是如何發(fā)揮作用?

在前面的過程中,與electionTimeout參數(shù)相關(guān)兩個方法如下,它們也分別對應(yīng)了單獨的定時器:

ReplicationCoordinatorImpl::_scheduleNextLivenessUpdate_inlock 發(fā)起保活狀態(tài)檢查定時器

ReplicationCoordinatorImpl::_cancelAndRescheduleElectionTimeout_inlock 重新發(fā)起選舉超時定時器

第一個是 _scheduleNextLivenessUpdate_inlock這個函數(shù),它的作用在于?;顮顟B(tài)檢測,如下:

  1. void ReplicationCoordinatorImpl::_scheduleNextLivenessUpdate_inlock() { 
  2.  //僅僅支持3.2+ 
  3.  if (!isV1ElectionProtocol()) { 
  4.  return
  5.  } 
  6.   
  7.  // earliestDate 取所有節(jié)點中更新時間最早的(以盡可能早的發(fā)現(xiàn)問題) 
  8.  // electionTimeoutPeriod 默認(rèn)為 10s 
  9.  auto nextTimeout = earliestDate + _rsConfig.getElectionTimeoutPeriod(); 
  10.   
  11.  // 設(shè)置超時回調(diào)函數(shù)為 _handleLivenessTimeout 
  12.  auto cbh = _scheduleWorkAt(nextTimeout, 
  13.  stdx::bind(&ReplicationCoordinatorImpl::_handleLivenessTimeout, 
  14.  this, 
  15.  stdx::placeholders::_1)); 

因此,在大約10s后,如果沒有什么意外,_handleLivenessTimeout將會被觸發(fā),如下:

  1. void ReplicationCoordinatorImpl::_handleLivenessTimeout(...) { 
  2.  ... 
  3.  for (auto&& slaveInfo : _slaveInfo) { 
  4.  ... 
  5.  //lastUpdate 不夠新(小于electionTimeout) 
  6.  if (now - slaveInfo.lastUpdate >= _rsConfig.getElectionTimeoutPeriod()) { 
  7.  ... 
  8.  //在?;钪芷诤笕匀晃锤鹿?jié)點,置為down狀態(tài) 
  9.  slaveInfo.down = true
  10.  //如果當(dāng)前節(jié)點是主,且檢測到某個備節(jié)點為down的狀態(tài),進(jìn)入memberdown流程 
  11.  if (_memberState.primary()) { 
  12.   
  13.  //調(diào)用_topCoord的setMemberAsDown方法,記錄某個備節(jié)點不可達(dá),并獲得下一步的指示 
  14.  //當(dāng)大多數(shù)節(jié)點不可見時,這里會獲得讓自身降備的指示 
  15.  HeartbeatResponseAction action = 
  16.  _topCoord->setMemberAsDown(now, memberIndex, _getMyLastDurableOpTime_inlock()); 
  17.  //執(zhí)行指示 
  18.  _handleHeartbeatResponseAction(action
  19.  makeStatusWith<ReplSetHeartbeatResponse>(), 
  20.  true); 
  21.  } 
  22.  } 
  23.  } 
  24.  //繼續(xù)調(diào)度下一個周期 
  25.  _scheduleNextLivenessUpdate_inlock(); 

可以看到,這個定時器主要是用于實現(xiàn)主節(jié)點對其他節(jié)點的?;钐綔y邏輯:

當(dāng)主節(jié)點發(fā)現(xiàn)大多數(shù)節(jié)點不可達(dá)時(不滿足大多數(shù)原則),將會讓自己執(zhí)行降備

因此,在一個三節(jié)點的副本集中,其中兩個備節(jié)點掛掉后,主節(jié)點會自動降備。 這樣的設(shè)計主要是為了避免產(chǎn)生意外的數(shù)據(jù)不一致情況產(chǎn)生。

 

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考(源碼剖析)

 

圖- 主自動降備

第二個是_cancelAndRescheduleElectionTimeout_inlock函數(shù),這里則是實現(xiàn)自動Failover的關(guān)鍵了,

它的邏輯中包含了一個選舉定時器,代碼如下:

  1. void ReplicationCoordinatorImpl::_cancelAndRescheduleElectionTimeout_inlock() { 
  2.  //如果上一個定時器已經(jīng)啟用了,則直接取消 
  3.  if (_handleElectionTimeoutCbh.isValid()) { 
  4.  LOG(4) << "Canceling election timeout callback at " << _handleElectionTimeoutWhen; 
  5.  _replExecutor.cancel(_handleElectionTimeoutCbh); 
  6.  _handleElectionTimeoutCbh = CallbackHandle(); 
  7.  _handleElectionTimeoutWhen = Date_t(); 
  8.  } 
  9.  //僅支持3.2后的V1版本 
  10.  if (!isV1ElectionProtocol()) { 
  11.  return
  12.  } 
  13.  //僅備節(jié)點可執(zhí)行 
  14.  if (!_memberState.secondary()) { 
  15.  return
  16.  } 
  17.  ... 
  18.  //是否可以選舉 
  19.  if (!_rsConfig.getMemberAt(_selfIndex).isElectable()) { 
  20.  return
  21.  } 
  22.  //檢測周期,由 electionTimeout + randomOffset 
  23.  //randomOffset是隨機(jī)偏移量,默認(rèn)為 0~0.15*ElectionTimeoutPeriod = 0~1.5s 
  24.  Milliseconds randomOffset = _getRandomizedElectionOffset(); 
  25.  auto now = _replExecutor.now(); 
  26.  auto when = now + _rsConfig.getElectionTimeoutPeriod() + randomOffset; 
  27.   
  28.  LOG(4) << "Scheduling election timeout callback at " << when
  29.  _handleElectionTimeoutWhen = when
  30.  //觸發(fā)調(diào)度,時間為 now + ElectionTimeoutPeriod + randomOffset 
  31.  _handleElectionTimeoutCbh = 
  32.  _scheduleWorkAt(when
  33.  stdx::bind(&ReplicationCoordinatorImpl::_startElectSelfIfEligibleV1, 
  34.  this, 
  35.  StartElectionV1Reason::kElectionTimeout)); 

上面代碼展示了這個選舉定時器的邏輯,在每一個檢測周期中,定時器都會嘗試執(zhí)行超時回調(diào),

而回調(diào)函數(shù)指向的是_startElectSelfIfEligibleV1,這里面就實現(xiàn)了主動發(fā)起選舉的功能,

如果心跳響應(yīng)成功,通過cancelAndRescheduleElectionTimeout調(diào)用將直接取消當(dāng)次的超時回調(diào)(即不會發(fā)起選舉)

如果心跳響應(yīng)遲遲不能成功,那么定時器將被觸發(fā),進(jìn)而導(dǎo)致備節(jié)點發(fā)起選舉并成為新的主節(jié)點!

同時,這個回調(diào)方法(產(chǎn)生選舉)被觸發(fā)必須要滿足以下條件:

  1. 當(dāng)前是備節(jié)點
  2. 當(dāng)前節(jié)點具備選舉權(quán)限
  3. 在檢測周期內(nèi)仍然沒有與主節(jié)點心跳成功

這其中的檢測周期略大于electionTimeout(10s),加入一個隨機(jī)偏移量后大約是10-11.5s內(nèi),猜測這樣的設(shè)計是為了錯開多個備節(jié)點主動選舉的時間,提升成功率。

最后,將整個自動選舉切換的邏輯梳理后,如下圖所示:

 

MongoDB一次節(jié)點宕機(jī)引發(fā)的思考(源碼剖析)

 

圖-超時自動選舉

業(yè)務(wù)影響評估

副本集發(fā)生主備切換的情況下,不會影響現(xiàn)有的讀操作,只會影響寫操作。 如果使用3.6及以上版本的驅(qū)動,可以通過開啟retryWrite來降低影響。

但是如果主節(jié)點是屬于強(qiáng)制掉電,那么整個 Failover 過程將會變長,很可能需要在Election定時器超時后才被副本集感知并恢復(fù),這個時間窗口會在12s以內(nèi)。

此外還需要考慮客戶端或mongos對于副本集角色的監(jiān)視和感知行為。但總之在問題恢復(fù)之前,對于原主節(jié)點的任何讀寫都會發(fā)生超時。

因此,對于極為重要的業(yè)務(wù),建議最好在業(yè)務(wù)層面做一些防護(hù)策略,比如設(shè)計重試機(jī)制。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2018-12-27 09:09:35

2019-01-16 09:20:42

架構(gòu)設(shè)計JVM FullGC宕機(jī)事故

2022-11-29 21:26:26

跨域配置

2015-07-17 10:05:03

面試思考

2013-03-05 10:05:52

2021-11-01 17:29:02

Windows系統(tǒng)Fork

2017-08-24 17:37:18

DNS緩存分析

2019-10-09 11:42:10

分布式取錢異步流程

2023-07-13 09:12:37

CNCF項目云原生

2018-09-12 09:07:43

服務(wù)器數(shù)據(jù)RAID5

2024-05-13 08:37:17

炫技H5UI

2019-06-25 14:44:11

分布式事務(wù)數(shù)據(jù)庫

2022-12-26 10:42:00

康普中國

2021-11-22 08:33:27

微信聊天離婚

2021-03-17 00:17:16

命令應(yīng)急響應(yīng)

2018-07-16 22:29:29

代碼迭代質(zhì)量

2020-01-06 09:43:14

賠償TSB遷移

2022-09-03 18:29:49

開發(fā)技術(shù)

2012-07-05 09:54:04

Amazon宕機(jī)

2022-06-14 08:00:28

切換包管理器版本
點贊
收藏

51CTO技術(shù)棧公眾號