🎯 什麼情境該想到我

當你想讓資料庫高可用、或用多副本分攤讀取,卻遇到「讀到舊資料」的怪象時。

⚙️ 怎麼用(先選架構,再處理延遲)

  1. 選複製架構:
    • 單主(Leader-based):寫主、讀從,最常見;簡單但主是寫入瓶頸/單點。
    • 多主:跨資料中心可寫,但要處理寫衝突。
    • 無主(Dynamo 式):靠 quorum 讀寫。
  2. 同步 vs 非同步:同步保證從庫有最新值但慢/易卡;非同步快但有延遲。
  3. 處理複製延遲的讀取異常:
    • 讀自己的寫 → 讀己所寫一致性(read-your-writes)
    • 時光倒流 → 單調讀(monotonic reads)

★ 三種複製拓撲

拓撲怎麼運作適合★ 主要問題
單主(leader-based)所有寫入走主,非同步複製給從★ 絕大多數場景主掛了要選新主;複製延遲
多主(multi-leader)多個節點都能寫多資料中心、離線編輯★ 寫入衝突,而且沒有通用解法
無主(leaderless)客戶端寫多個節點,靠 quorumDynamo、Cassandra一致性弱,要處理讀修復

★ 判準:能用單主就用單主。 多主與無主帶來的衝突解決成本,遠超過它們解決的可用性問題——
除非你真的有「跨洲寫入」或「離線優先」的需求。

★ 同步 vs 非同步(這是可用性與持久性的取捨)

全同步:主等所有從都確認   → ★ 一個從掛了,「整個系統不能寫」
全非同步:主不等            → ★ 主掛了,「未複製的寫入永久遺失」
★ 半同步:至少等一個從確認  → 實務上的預設(PG 的 synchronous_standby_names)

★★ 複製延遲的三個經典問題(面試必考,實務必踩)

① 讀自己的寫(read-your-writes)

使用者送出留言 → 寫入主庫 → 重新整理 → ★ 讀到從庫(還沒複製到)→ 「我的留言不見了」

解法:

  • 寫入後的 N 秒內,該使用者的讀都走主庫(最簡單,最常用)
  • 記下寫入時的 LSN/時間戳,讀的時候要求從庫至少追到那個位置
  • 「自己的資料」一律讀主庫

② 單調讀(monotonic reads)

第一次讀 → 從庫 A(新)→ 看到留言
第二次讀 → 從庫 B(舊)→ ★ 留言消失了(時光倒流)

解法:★ 同一個使用者永遠路由到同一個從庫(依 user_id 雜湊)。

③ 一致前綴讀(consistent prefix reads)

A: 「你午餐吃什麼?」
B: 「便當」
★ 觀察者可能先看到「便當」再看到問題 —— 因果順序被打亂

解法:有因果關係的寫入放進同一個分區,或用邏輯時鐘追蹤因果。

★ 這三個問題的共同點:它們不是「bug」,是「非同步複製的固有後果」。
你不能靠「加更多從庫」解決,只能靠路由策略或更強的一致性保證。

★ 多主的衝突解決(沒有好答案)

策略問題
LWW(last write wins)★ 會靜默丟失資料,而且「last」依賴時鐘(不可靠)
記下所有版本讓應用解複雜,但至少沒有靜默遺失
CRDT★ 數學上保證收斂,但只適用於特定資料型別(計數器、集合、文字)
避免衝突★ 最實用:讓同一筆資料永遠只在同一個 leader 寫(依 user 路由)

★ 「避免衝突」才是實務上的正解。衝突解決演算法是最後手段,不是設計目標。

★ 故障轉移(failover)的三個坑

坑說明
★ 資料遺失非同步複製下,舊主未複製的寫入在提升新主時就沒了。舊主回來後這些寫入還要被丟棄
★ 腦裂(split brain)舊主沒真的死(只是網路分區),兩個主同時接受寫入 → ★ 必須有 fencing(STONITH)機制
逾時設得太短暫時的網路抖動觸發不必要的 failover → 在高負載時引發連鎖故障

★ 自動 failover 不是免費的。很多成熟團隊選擇半自動(自動偵測 + 人工確認),
因為錯誤的 failover 比晚幾分鐘恢復更糟。

🧪 我實際套用的紀錄

  • 2026-07-15:(待填)

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

  • ★ 讀取副本不能解決寫入瓶頸。寫入永遠只有一個主——寫不夠就要分區(見 工具-資料分區)。
  • ★ 複製延遲不是「偶爾」而是「總是」。設計時就要假設從庫落後,而不是「通常應該很快」。
    → 監控 replication lag,並設告警。
  • ★ 「剛寫完就讀」的路徑要特別處理。這是使用者最容易察覺異常的場景(表單送出、下單、發文)。
  • 「最終一致」的「最終」沒有上界。從庫卡住時可能落後數小時。要有落後過多就把它移出讀取池的機制。
  • ★ 不要用 LWW 解決衝突,除非你能接受靜默的資料遺失(例如快取、遙測)。
  • 跨區域複製的延遲是光速決定的(台北↔美西約 130ms RTT),不是調參數能解決的。
  • 備份不等於複製。複製會把「刪除」也複製過去——誤刪的資料在所有副本上都沒了。 兩者都要做。

🔗 相關工具