手記:一次網(wǎng)卡丟包引發(fā)分布式數(shù)據(jù)庫 Paxos 租約漂移排障實(shí)錄)
這是一次將全鏈路排障推向極限物理硬件層、跨越軟件算法與物理光纖信號(hào)邊界的驚悚排錯(cuò)實(shí)錄。事故發(fā)生在一個(gè)看似平靜的周二上午。我們內(nèi)部核心分布式關(guān)系型數(shù)據(jù)庫集群基于 Multi-Paxos / Raft 變種構(gòu)建的強(qiáng)一致分布式存算分離數(shù)據(jù)庫突然在監(jiān)控看板上暴露出一種令人極其抓狂的“周期性微痙攣”每隔大約 40 秒到 1 分鐘數(shù)據(jù)庫核心集群的寫入 TPS 就會(huì)出現(xiàn)一次垂直的“歸零懸崖”長(zhǎng)達(dá) 3 到 5 秒無法寫入任何數(shù)據(jù)與此同時(shí)前臺(tái)核心交易網(wǎng)關(guān)的 P999 延遲呈現(xiàn)出令人膽寒的周期性尖刺部分只讀微服務(wù)更是偶爾拋出SnapshotIsolationException甚至極低概率讀到了幾毫秒前的舊版本數(shù)據(jù)在排查監(jiān)控大盤時(shí)所有節(jié)點(diǎn)的 CPU 利用率不到 30%磁盤 I/O util 只有 15%內(nèi)存沒有任何溢出跡象操作系統(tǒng)內(nèi)核dmesg也沒有任何明顯的硬件報(bào)警。這種“不致命、不宕機(jī)但每隔一分鐘就神經(jīng)質(zhì)抽搐一次”的陰間故障往往比直接宕機(jī)更具破壞性。在這長(zhǎng)達(dá) 4 個(gè)小時(shí)的排障拉鋸戰(zhàn)中我們層層穿透應(yīng)用代碼、數(shù)據(jù)庫狀態(tài)機(jī)、內(nèi)核網(wǎng)絡(luò)棧最終在萬兆光纖交換機(jī)的一枚微小物理光模塊上找到了推倒整副多米諾骨牌的隱秘元兇。一、迷局為什么 Leader 會(huì)像幽靈一樣反復(fù)易主我們首先調(diào)取了分布式數(shù)據(jù)庫核心存儲(chǔ)引擎Storage Engine的日志發(fā)現(xiàn)了極其反常的密集事件流10:14:02.120 [WARN] Paxos Leader Lease keepalive timeout on Node-1! 10:14:02.135 [INFO] Node-1 stepping down from Paxos Leader... 10:14:03.200 [INFO] Node-2 elected as new Paxos Leader for Range 104! 10:14:45.310 [WARN] Paxos Leader Lease keepalive timeout on Node-2! 10:14:45.320 [INFO] Node-2 stepping down... 10:14:46.400 [INFO] Node-1 elected as new Paxos Leader for Range 104!經(jīng)典的租約漂移Lease Drift分布式共識(shí)系統(tǒng)之所以能夠提供低延遲的就地只讀Local Read依賴于 Leader 持有的絕對(duì)時(shí)間租約Paxos Lease。只要租約未到期Leader 就可以向客戶端直接提供強(qiáng)一致性讀無需每次讀取都走昂貴的 Paxos 全網(wǎng)法定人數(shù)確認(rèn)Quorum。然而日志清晰地顯示Leader 節(jié)點(diǎn)在以每分鐘一次的荒謬頻率不斷因?yàn)樽饧s續(xù)約失敗而被迫下臺(tái)Step Down緊接著觸發(fā)全網(wǎng)重新選舉在選舉的 1 3 秒真空期內(nèi)所有的寫事務(wù)全部被阻塞掛起讀事務(wù)由于無法確認(rèn)最新租約而陷入一致性校驗(yàn)異常。二、多米諾骨牌的連鎖推演為什么在內(nèi)網(wǎng)千兆/萬兆極速局域網(wǎng)內(nèi)心跳續(xù)約會(huì)頻繁超時(shí)【骨牌 1物理交換機(jī)端口光模塊微小老化】 萬兆單模光纖接口產(chǎn)生微弱光衰物理鏈路發(fā)生極其隱蔽的 0.05% 偶發(fā)丟包 │ ▼ 【骨牌 2TCP 擁塞控制與超時(shí)重傳 (RTO)】 心跳探針 RPC 連續(xù)命中重傳退避報(bào)文往返延遲從 0.5ms 陡增至 2.5 秒 │ ▼ 【骨牌 3臨界死穴Lease 續(xù)約超時(shí)邊界塌陷】 系統(tǒng)配置的 Lease Timeout 2.0s由于心跳超期觸發(fā)安全降級(jí)機(jī)制 │ ▼ 【骨牌 4Leader 頻繁主動(dòng)下臺(tái)與全網(wǎng)重新選舉】 分片 Ranges 反復(fù)經(jīng)歷 Leader 切換租約在物理節(jié)點(diǎn)間發(fā)生惡性漂移 │ ▼ 【致命終局前臺(tái)寫操作周期性歸零卡頓只讀請(qǐng)求遭遇舊租約數(shù)據(jù)撕裂】第一塊骨牌極其陰險(xiǎn)的 0.05% 物理微丟包我們最初執(zhí)行了簡(jiǎn)單的網(wǎng)絡(luò)探測(cè)ping -c 100 10.0.4.12結(jié)果顯示0% packet loss, rtt avg 0.21ms看起來網(wǎng)絡(luò)健康至極。這也是讓無數(shù)運(yùn)維工程師陷入盲區(qū)的第一道陷阱。直到我們把探測(cè)包數(shù)量放大到 50,000 個(gè)并使用mtr結(jié)合ethtool -S eth0逐個(gè)檢查網(wǎng)卡統(tǒng)計(jì)指標(biāo)時(shí)一行驚心動(dòng)魄的數(shù)據(jù)終于暴露出來rx_crc_errors: 14205 rx_missed_errors: 8902網(wǎng)卡層居然存在大量的 CRC 校驗(yàn)錯(cuò)誤丟包平均下來丟包率大概只有0.05%。在普通 Web 業(yè)務(wù)看來這種微小丟包甚至可以通過上層重試無感抹平但在納秒與微秒必爭(zhēng)的底層共識(shí)協(xié)議棧中這 0.05% 卻是一顆劇毒的暗雷第二塊與第三塊骨牌TCP RTO 退避與 2 秒生死時(shí)速分布式數(shù)據(jù)庫節(jié)點(diǎn)間的心跳?;畈捎?gRPC / TCP 長(zhǎng)連接通信在通常情況下Paxos 心跳 RPC 每隔 500ms 發(fā)送一次延遲穩(wěn)定在 0.3ms然而當(dāng)某一次心跳的 TCP 報(bào)文不幸命中了網(wǎng)卡的 CRC 物理損壞接收端靜默丟棄該包此時(shí)Linux 內(nèi)核的 TCP 棧必須等待超時(shí)重傳RTO。根據(jù) Linux 默認(rèn)實(shí)現(xiàn)初始 RTO 約為 200ms更加致命的巧合是如果連續(xù)兩個(gè)心跳探針或確認(rèn)包發(fā)生了丟包碰撞TCP 的指數(shù)退避Exponential Backoff會(huì)將 RTO 瞬間推升至1.5 秒 2.5 秒此時(shí)系統(tǒng)的 Paxos Lease 配置參數(shù)赫然寫著lease_timeout 2000ms數(shù)學(xué)臨界點(diǎn)被無情刺穿心跳重傳耗時(shí)突破了 2 秒Leader 的本地單調(diào)時(shí)鐘判定當(dāng)前租約已經(jīng)徹底失效為了防御分布式腦裂Leader 必須無條件立刻自殺下臺(tái)第四塊骨牌租約漂移帶來的前臺(tái)地震節(jié)點(diǎn) 1 下臺(tái)分片 Range 104 失去 Leader節(jié)點(diǎn) 2 發(fā)起選舉耗時(shí) 800ms 成功當(dāng)選新 Leader僅僅過了 40 秒節(jié)點(diǎn) 2 與節(jié)點(diǎn) 3 之間的網(wǎng)絡(luò)鏈路再次遭遇 CRC 物理丟包TCP 重傳超時(shí)再次上演節(jié)點(diǎn) 2 同樣被逼下臺(tái)節(jié)點(diǎn) 1 再次被選回伴隨著 Leader 像乒乓球一樣在兩臺(tái)機(jī)器間來回彈跳數(shù)據(jù)庫內(nèi)部的 Raft/Paxos 日志提交隊(duì)列頻繁被強(qiáng)制刷新截?cái)嗲芭_(tái)寫請(qǐng)求每分鐘必卡死一次形成了我們最初看到的魔幻景象。三、現(xiàn)場(chǎng)極限排障與物理拔除在精準(zhǔn)定位到是萬兆物理網(wǎng)卡鏈路的 CRC 錯(cuò)誤后我們協(xié)同機(jī)房值班駐場(chǎng)工程師火速展開了物理搶修1. 軟件層緊急抗震調(diào)優(yōu)爭(zhēng)取排查時(shí)間在尚未更換物理硬件的過渡期立即在分布式數(shù)據(jù)庫全局動(dòng)態(tài)參數(shù)中對(duì)租約心跳容忍度進(jìn)行安全平移-- 將心跳發(fā)送頻率從 500ms 加密至 200ms (高頻探針抗單次偶發(fā)丟包) SET GLOBAL paxos_heartbeat_interval_ms 200; -- 適度放寬租約超時(shí)門檻從 2.0s 至 4.0s SET GLOBAL paxos_lease_timeout_ms 4000;這一微調(diào)使得系統(tǒng)即便遭遇單次 TCP 重傳退避依然有充足的余量在 4 秒租約耗盡前完成重試恢復(fù)集群的每分鐘周期性抽搐卡頓在 1 分鐘內(nèi)立即停止2. 物理層拔除老化光模塊機(jī)房駐場(chǎng)工程師攜帶光功率計(jì)登門檢查發(fā)現(xiàn)連接 Node-1 與核心交換機(jī)的多模光纖跳線接頭存在微量粉塵污染且交換機(jī)端的光模塊接收光功率衰減至-18.5 dBm正常應(yīng)在-3 到 -9 dBm之間導(dǎo)致信號(hào)眼圖畸變產(chǎn)生誤碼。立即熱插拔更換了全新的萬兆單模光模塊清潔光纖接頭并重新熔接跳線網(wǎng)卡rx_crc_errors增長(zhǎng)計(jì)數(shù)在瞬間永久停止物理丟包率徹底歸零。四、骨牌反思給分布式架構(gòu)師的硬核法則這次排障經(jīng)歷深深烙印在我的技術(shù)思維模型中促使我們確立了三條底層運(yùn)維治理規(guī)范【共識(shí)系統(tǒng)與底層硬件三道絕對(duì)契約】 ┌─────────────────────────────────────────────────────────────┐ │ 1. 租約時(shí)限必須滿足“至少容忍連續(xù)三次 TCP RTO 重傳” │ │ - LeaseTimeout HeartbeatInterval * 4 Max_RTO │ │ - 嚴(yán)禁將 Lease 設(shè)置在臨界單次超時(shí)的危險(xiǎn)邊緣 │ └──────────────────────────────┬──────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 2. 基礎(chǔ)設(shè)施層建立“誤碼丟包零容忍巡檢” │ │ - 將 ethtool 物理網(wǎng)卡 CRC、丟包指標(biāo)納入 P1 級(jí)秒級(jí)監(jiān)控大盤 │ │ - 任何千分之一級(jí)別的微丟包必須被判定為高危物理故障報(bào)警 │ └──────────────────────────────┬──────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 3. 租約漂移預(yù)警 (Lease Drift Alerting) │ │ - 統(tǒng)計(jì)單分片 10 分鐘內(nèi)發(fā)生 Leader 切換的頻次 │ │ - 頻次 2 次立即觸發(fā)架構(gòu)防御工單防止暗病長(zhǎng)期侵蝕 │ └─────────────────────────────────────────────────────────────┘越是高階精妙的分布式共識(shí)算法其對(duì)底層物理世界的微小瑕疵就越加敏感。在現(xiàn)代云原生與海量并發(fā)面前一名出色的架構(gòu)師不僅要懂得軟件層面的算法推演更要時(shí)刻對(duì)底層的光電物理世界保持敏銳的嗅覺與敬畏。