🎯 什麼情境該想到我
當你想讓資料庫高可用、或用多副本分攤讀取,卻遇到「讀到舊資料」的怪象時。
⚙️ 怎麼用(先選架構,再處理延遲)
- 選複製架構:
- 單主(Leader-based):寫主、讀從,最常見;簡單但主是寫入瓶頸/單點。
- 多主:跨資料中心可寫,但要處理寫衝突。
- 無主(Dynamo 式):靠 quorum 讀寫。
- 同步 vs 非同步:同步保證從庫有最新值但慢/易卡;非同步快但有延遲。
- 處理複製延遲的讀取異常:
- 讀自己的寫 → 讀己所寫一致性(read-your-writes)
- 時光倒流 → 單調讀(monotonic reads)
★ 三種複製拓撲
| 拓撲 | 怎麼運作 | 適合 | ★ 主要問題 |
|---|---|---|---|
| 單主(leader-based) | 所有寫入走主,非同步複製給從 | ★ 絕大多數場景 | 主掛了要選新主;複製延遲 |
| 多主(multi-leader) | 多個節點都能寫 | 多資料中心、離線編輯 | ★ 寫入衝突,而且沒有通用解法 |
| 無主(leaderless) | 客戶端寫多個節點,靠 quorum | Dynamo、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),不是調參數能解決的。
- 備份不等於複製。複製會把「刪除」也複製過去——誤刪的資料在所有副本上都沒了。 兩者都要做。
🔗 相關工具
- 工具-資料分區 —— 正交的另一半(複製管可用性,分區管容量)
- 工具-線性一致性與共識 —— 需要更強保證時
- 工具-故障偵測 —— failover 的前提
- 工具-交易與隔離等級 —— 單機內的一致性
- 工具-快取與資源優化 —— 快取也是一種複製,有同樣的失效問題
- 工具-反熵與Gossip傳播 —— 無主複製的修復機制
- 工具-服務容錯設計 —— failover 期間的降級
- 設計資料密集型應用