🎯 什麼情境該想到我

當你在分散式系統裡糾結「要不要強一致、可用性 vs 一致性怎麼取捨、多節點怎麼對同一件事達成一致」時。

⚙️ 怎麼用

  1. 線性一致性(Linearizability):讓多副本「看起來像只有一份資料」,讀到的一定是最新已寫入值。強、直覺,但成本高。
  2. CAP 取捨:網路分區(P)發生時,只能在一致性(C)與可用性(A)間擇一。分區無法避免 → 你在選 CP 還是 AP。
  3. 共識(Consensus):讓一群節點對某個值達成一致(選主、鎖、原子提交)。用 Raft/Paxos 這類演算法,或直接靠 ZooKeeper/etcd。
  4. 能不要強一致就別要:多數場景用因果一致性/最終一致性即可,成本低很多。

★ CAP 常被誤解,正確的用法是這樣

CAP 不是「三選二」,是「分區發生時,C 和 A 只能選一個」。
網路分區無法避免(光纖會斷、交換器會壞、GC 會停頓),所以 P 是前提不是選項。
★ 沒有分區的時候,你可以同時擁有 C 和 A —— 這是 CAP 最常被忽略的一半。

更實用的框架是 PACELC:

if (Partition) then  C or A      ← CAP 講的
else                 L or C      ← ★ 平時:Latency 或 Consistency

★ else 那一半才是你每天在付的成本:
強一致要跨節點確認 → 即使一切正常,延遲也更高。
多數系統選 AP/EL(可用 + 低延遲),這是刻意的,不是妥協。

★ 一致性模型的光譜(越上面越強、越貴)

模型保證成本
嚴格可序列化線性一致 + 可序列化最高
線性一致(Linearizability)★ 看起來像只有一份資料,讀到的一定是最新已提交值高(要共識)
可序列化(Serializable)交易像一個個依序執行(★ 但不保證「順序和真實時間一致」)高
因果一致★ 有因果關係的操作順序一致,無關的可以亂序中——CP 難以企及時的好折衷
最終一致不再有寫入時,最終會收斂低

★ 「線性一致」和「可序列化」是不同的東西,常被混用:
線性一致是關於單一物件 + 真實時間順序(recency);
可序列化是關於多物件交易 + 某種等價順序(不保證是真實時間順序)。
兩個都要 = 嚴格可序列化(例如 Spanner)。

★ 什麼時候真的需要線性一致(很少)

需要不需要
★ 選主 / leader election社群動態、按讚數
★ 唯一性約束(帳號名、座位、庫存扣減到 0)推薦、搜尋
★ 分散式鎖/柵欄快取
跨通道的因果(付款完成 → 觸發出貨)遙測、日誌
帳務餘額「大約多少人在線」

★ 判準:這件事「錯了會怎樣」?
錯了會造成重複扣款、超賣、兩個 leader → 需要強一致。
錯了只是「數字晚幾秒更新」→ 最終一致就好,而且便宜非常多。

★★ 分散式鎖的陷阱(實務上最常出事的地方)

客戶端 A 取得鎖 → ★ GC 停頓 15 秒 → 鎖過期 → 客戶端 B 取得鎖
                                                  ↓
A 醒來,「以為」自己還持有鎖 → 兩個人同時寫 → ★ 資料毀損

★ 鎖有過期時間 + 程序可能任意暫停 = 鎖永遠不安全。
SETNX + TTL 的 Redis 鎖擋不住這個問題(Redlock 的爭議核心也在這裡)。

唯一的正解:fencing token(柵欄令牌)

取得鎖時拿到一個「單調遞增的編號」 → 每次寫入都帶上它
★ 儲存端「拒絕」編號比已見過的更小的寫入
→ A 醒來用舊 token 寫入 → 被拒絕

★ 關鍵:保護必須在「被保護的資源」那一端做,不能只靠客戶端自律。
這需要儲存端支援(或用資料庫的條件更新 WHERE version = ? 達成同樣效果,
見 工具-交易與隔離等級 的樂觀鎖)。

★ 共識演算法:要知道什麼

演算法特點
Paxos理論基礎,★ 極難正確實作
Raft★ 為「可理解性」設計:leader election + log replication + safety 三塊分開
ZABZooKeeper 用的
Viewstamped Replication與 Raft 類似

共同性質:

  • 需要多數(quorum): 個節點容忍 個故障 → ★ 所以節點數是奇數(3、5、7)
  • ★ 節點越多越慢(每次都要多數確認),不是越多越好
  • 只容忍「崩潰故障」,不容忍拜占庭故障(惡意節點)

★★ 實務結論:不要自己實作共識演算法。
用 etcd、ZooKeeper、Consul,或直接用資料庫的交易。
自己實作 Raft 是一個「看起來對、但在網路分區與時鐘異常時會靜默出錯」的經典陷阱。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

⚠️ 注意 / 什麼時候不適用

  • ★★ 不要自己實作共識(見上)。用成熟的元件。
  • ★ 不要把「強一致」當預設。它的成本是每次操作的延遲 + 分區時的不可用。
    先問「這裡錯了會怎樣」,多數答案是「沒怎樣」。
  • ★ 分散式鎖要有 fencing token,否則它只是「大部分時候有效的建議」。
  • CAP 裡的 A 是「每個非故障節點都能回應」,不是「系統大致可用」。
    實務上的可用性討論遠比 CAP 的形式定義寬鬆——不要用 CAP 當作架構決策的唯一依據。
  • 時鐘不可信。NTP 會跳、VM 會暫停、閏秒會出事。
    ★ 不要用 wall clock 判斷「誰比較新」(LWW 的根本問題,見 工具-資料複製)——
    用邏輯時鐘(Lamport、vector clock)或單調時鐘。
  • 「網路分區」包含 GC 停頓與 VM 暫停。一個 stop-the-world GC 讓節點靜默 10 秒,
    從外面看和「網路斷了」無法區分。
  • 共識系統的資料量要小。etcd/ZooKeeper 適合存「設定與協調資訊」,不是資料庫。

🔗 相關工具