拜占庭故障與真相 (Byzantine Faults)

★★★★★Draft

FromDDIADatabase Internals

📚 From the Books

拜占庭故障與真相 (Byzantine Faults)Distributed Troubles

前面幾頁的節點雖然不可靠——會慢、會暫停、狀態會過時——但它們誠實:只要回應,就是照協議說實話。這一頁把最後一層信任也拿掉:若一個節點會說謊、傳送任意錯誤或偽造的回應,你還能不能達成一致?這就是拜占庭故障,而在這種環境下達成共識,需要付出遠高於平常的代價。

🧠 Intuition

TIP

大多數分散式系統的預設假設是節點不可靠但誠實 (unreliable but honest)——這讓演算法能以較少的參與者、較少的往返次數運作。拜占庭故障 (Byzantine fault) 打破這個假設:節點可能做出任意行為,甚至在共識中「決定一個從未被提出的值」。一旦要容忍這種行為,成本就會急遽上升,所以真正值得付這個代價的場景很少。

⚖️ Tradeoffs

何時值得付拜占庭容錯的代價
  • 值得的場景很具體:航太環境——輻射可能損壞記憶體或 CPU 暫存器,導致任意不可預測的回應,所以不直接信任子元件、要交叉驗證;多方互不信任的系統——如 Bitcoin 等區塊鏈,沒有中央權威、參與者有物質動機偽造值。
  • 一般資料中心系統不值得:所有節點由同一組織控制、可以合理信任,拜占庭容錯的成本過高。Web 應用要防惡意客戶端,但通常靠輸入驗證與授權處理,而非拜占庭協議。
  • 判斷準則是「系統各部分之間有沒有信任」:有信任 → 加密與驗證節點間通訊通常就夠;缺乏信任 → 才需要 PBFT 這類演算法。
弱形式的『說謊』:就算不上全套 BFT 也要防
  • 不必全面拜占庭容錯,也該防範弱形式的錯誤回應——這些在誠實假設下仍會偶爾發生。
  • 具體手段:網路封包可能因硬體問題損壞,TCP/UDP 的 checksum 通常能捕捉但偶有遺漏,關鍵資料要自己再校驗;應用程式輸入一律驗證NTP 客戶端查詢多台伺服器並排除離群值,避免單一壞時鐘源。
  • 精神:把「防一點點謊言」當成日常防禦性設計,與是否採用完整 BFT 是兩件事。
為什麼拜占庭共識這麼貴:N² 訊息與 3f + 1
  • 前面所有共識演算法(Paxos、Raft)都假設非拜占庭故障——節點善意執行、不偽造結果,因此能用較少參與者、較少往返達成共識。
  • 拜占庭共識則相反:大多數演算法每一步需要 N² 則訊息(N 為 quorum 大小),因為每個節點都要與其他每個節點交叉驗證
  • 節點數要求也更高:為承受 f 個被入侵的節點,至少需要 n = 3f + 1 個節點——最多 (n − 1)/3 個副本可故障。直覺是:f 個可能故障、另有 f 個可能只是無回應但未故障,演算法仍需從剩下的正確副本收集到足夠回應。
PBFT:一個實際可行的拜占庭容錯演算法
  • PBFT (Practical Byzantine Fault Tolerance) 假設節點故障彼此獨立、系統做弱同步假設(網路大致正常、故障非永久且最終會恢復),並對所有節點間通訊加密以防訊息偽造。
  • View 區分叢集配置:每個 View 有一個 Primary(主節點)、其餘為 Backup;Primary 索引為 v mod N。客戶端把操作交給 Primary,Primary 廣播給 Backup。
  • 正常情況三階段:Pre-prepare(Primary 廣播含 View ID、單調遞增識別碼、載荷與其摘要的訊息)→ Prepare(Backup 廣播不含載荷本身的 Prepare,需收到 2f 個匹配才前進)→ Commit(廣播 Commit,收集 2f + 1 個匹配才提交)。Prepare 與 Commit 兩階段就是節點間互相交叉驗證、確保只有正確節點能成功提交。
  • View 變更:副本發現 Primary 不活躍就停止回應、廣播 View 變更;新 Primary 收到 2f 個 View 變更事件後啟動新 View。客戶端等 f + 1 個副本回覆相同結果即視為完成;唯讀操作可只用一次往返、收集 2f + 1 個相同回應。

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading