單機軟體要嘛全對、要嘛整台當掉——行為是確定性的。一旦跨網路,就冒出第三種狀態:部分失敗 (partial failure)——有些節點好、有些壞,而且非確定性:同樣操作有時成、有時敗,你甚至不知道它到底成沒成。這一頁講的所有麻煩,都是這個第三種狀態的後果。
🧠 Intuition
TIP
資料中心與網際網路都是非同步封包網路 (asynchronous packet network):送一個封包出去,網路不保證它何時到、甚至是否會到。於是有一個問題你永遠無法從外部區分:對方是掛了,還是只是慢?——本頁一半的難題都出自這一句。
- 本書假設 shared-nothing 架構:機器之間唯一的溝通方式就是網路。
- 送一個請求、等一個回應,中間可能出錯的環節有一整排:請求遺失、請求在對方過載時排隊、對方當機、對方暫時卡住稍後恢復(如長 GC 暫停)、對方處理完但回應遺失或延遲。
- 你唯一能確定的是「還沒收到回應」——無法判斷是請求沒送到、對方掛了、還是回應在路上丟了。
⚖️ Tradeoffs
偵測故障:明確訊號不可靠,最後只能等逾時
- 有時有明確回饋:OS 還活著但程式崩了,會回 TCP 的 RST / FIN;路由器判定 IP 不可達會回 ICMP Destination Unreachable。
- 但不能依賴它們:即使 TCP 確認封包已送達,應用程式也可能在處理前就崩潰。
- 結果:多數時候只能等逾時 (timeout) 到了,才宣告一個節點死亡。
逾時的兩難:無界延遲讓公式失效
- 設太長:故障偵測慢,使用者苦等。設太短:容易誤判,把只是變慢的節點宣告死亡(假性故障)。
- 誤判的代價:把它的工作移給別人 → 增加他人負載 → 系統本就吃緊時觸發級聯失敗 (cascading failure),極端下所有節點互相判對方死。
- 理想公式是
2d + r(網路最大延遲 d + 節點最大處理時間 r),但現實網路是無界延遲 (unbounded delay)、多數伺服器也不保證最大處理時間——公式的前提根本不成立。
延遲從哪來:排隊 (queueing) 與同步 vs 非同步網路
- 延遲變異主要來自排隊:多節點同時送到同一目標,交換器要排隊、滿了就丟包;目標 CPU 忙就在 OS 排隊;VM 被暫停數十毫秒期間收不了封包;TCP 流量控制又在發送端加一層排隊。多租戶雲上還有吵雜鄰居 (noisy neighbor)。
- 對比傳統電話網:它建電路 (circuit)、預留固定頻寬,延遲有上界 (bounded delay)——這是同步網路。
- 資料中心選封包交換 (packet switching) 是因為流量是突發性的,動態共享頻寬能把利用率與成本壓下來,代價就是排隊與無界延遲。延遲不可預測不是自然定律,而是成本/效益的取捨。
- 務實做法:持續量測回應時間與抖動 (jitter)、自動調整逾時——這正是 Phi Accrual 故障偵測器(見下)的做法。
故障偵測器:從二元判死到 φ 疑似度
- 完整性 (completeness) vs 準確性 (accuracy) 是根本取捨:偵測更快通常更不準、更準通常更慢——非同步系統裡兩者無法兼得。
- Heartbeat / Ping:週期性互報存活;每個節點對其他節點維護「存活 / 死亡 / 可疑 (suspected)」三態,久未回應先標可疑而非直接判死;但確認訊息一延遲就可能誤報 (false positive)。
- φ-accrual 故障偵測器:不吐 boolean,而給一個連續的疑似度 φ——用最近心跳到達時間的滑動視窗動態估計「此刻它故障的可能性」。被 Cassandra、Akka 採用。
- SWIM / 間接偵測:P1 ping 不到 P2 時,委託幾個隨機節點代 ping P2(outsourced heartbeat),綜合直接與間接可達性,降低單點誤判。
- Gossip 式偵測:心跳計數器在節點間擴散、聚合多方觀點,能抓到「沒有任何人連得上」的節點,比單點判斷可靠。
🔑 Takeaways
- 網路的核心麻煩是部分失敗 + 非確定性:你永遠無法從外部區分「節點掛了」與「節點只是慢」。
- 沒有可靠的明確訊號,最後只能等逾時;而逾時在無界延遲下必然是「偵測快」與「少誤判」之間的取捨,
2d + r那種公式的前提不成立。 - 延遲主要來自排隊;選封包交換而非電路交換,是拿延遲保證換利用率——所以必須假設壅塞與無界延遲會發生。
- 完美的故障偵測不可得,工程解法是把「判死」換成「懷疑的程度」:φ-accrual 給連續疑似度、SWIM/gossip 用多方觀點壓低誤判。
No notes yet — jot your takeaways or Q&A here.