01

總覽與定位

從「資料有多份」走向「讀者能看到什麼保證」;這是複寫系統真正困難的地方。

基礎複寫回答的是「資料怎麼被複製到多個節點」;進階複寫一致性要回答的是:在網路延遲、節點故障、併發寫入與 Failover 之下,Client 到底能相信自己讀到什麼?

這個問題不能只用「同步」或「異步」二分。實務上你會同時調整複寫拓撲、Quorum 參數、讀取路由、版本追蹤、衝突解決與 Session Guarantee,最後得到一組符合產品需求的保證。

correctness
讀到哪個版本
Linearizable、Read-your-writes、Monotonic Reads 都是在定義這件事。
availability
故障時能否服務
Quorum 越嚴格,越容易在節點故障或跨區延遲時拒絕請求。
operations
如何收斂差異
Read Repair、Hinted Handoff、Anti-entropy 決定長尾不一致多久被修正。
座標這篇承接 Replication Basics

複寫基礎篇已介紹 Single-Leader / Multi-Leader / Leaderless、同步與異步、以及 Replication Lag 異常。這篇會把焦點放在「如何明確宣告並實作一致性保證」,尤其是 Dynamo-style 與跨區資料庫常見的設計取捨。

一句話答法進階複寫一致性不是追求永遠強一致,而是明確選擇讀寫保證、Quorum 條件與衝突收斂策略,讓產品在 Latency、Availability 與 Correctness 之間做可解釋的取捨。

02

一致性保證光譜

面試與架構設計最常混淆的點:Linearizability、Serializability、Eventual Consistency 不是同一個維度。

討論複寫一致性時,第一步是把名詞放在正確座標上。Linearizability 關心「單一物件的即時可見性」;Serializability 關心「多筆交易的隔離順序」;Eventual Consistency 則只承諾沒有新寫入後,副本最後會收斂。

保證 核心語意 常見實作 代價
Linearizability 寫入成功後,所有後續讀取都必須看到該寫入或更新版本。 Leader 強路由、Consensus、同步 Quorum。 跨區 Latency 高;Partition 時偏向拒絕服務。
Sequential Consistency 所有 Client 看到同一個順序,但不要求符合真實時間。 單序列日誌、單主複寫。 需要集中排序點,吞吐受限於排序瓶頸。
Session Guarantees 至少對同一個使用者維持合理體驗,如 Read-your-writes。 Sticky Routing、Session Token、Leader fallback。 需要追蹤 session 進度;負載均衡彈性下降。
Eventual Consistency 若停止寫入,所有副本最後會趨向相同狀態。 Async Replication、Anti-entropy、CRDT。 短時間可讀到舊值或衝突值,應用層要能處理。

四種保證大致由強到弱排列。該看「代價」欄:越往上,代價越集中在跨區延遲與分區時的可用性;越往下,處理舊值與衝突的責任就越往應用層推。

陷阱不要把 Serializability 當成「最新讀」

Serializability 是交易隔離等級,保證多個交易的結果等價於某個序列執行;Linearizability 才是在描述操作完成後的即時可見性。資料庫可以 Serializable 但不是 Linearizable,尤其在多副本、異步讀取與快照讀場景中。

一句話答法Linearizability 管「最新值可見性」,Serializability 管「交易隔離順序」,Eventual Consistency 管「最終收斂」;設計時要先說清楚你承諾的是哪一種保證。

03

Session Guarantees:用戶體驗的一致性底線

很多產品不需要全域強一致,但幾乎都需要「同一個使用者不要被系統背叛」。

在社群、電商、SaaS 後台與內容平台中,對所有使用者提供 Linearizability 可能太昂貴;但如果使用者剛更新個人資料,刷新頁面卻看不到,體驗會直接崩壞。Session Guarantees 是在最終一致架構上加的一組局部保證。

Read-your-writes
RYW

同一個使用者寫入成功後,自己的後續讀取必須看到該寫入。常用做法是寫入後短時間強制讀 Leader,或把最新版本 token 帶回 Client。

Monotonic Reads
no time travel

同一使用者看過版本 8,就不能下一次讀到版本 6。可透過 Sticky Routing、最小版本要求或 session token 達成。

Monotonic Writes
ordered writes

同一使用者的寫入必須依序套用,避免「先改密碼、再改信箱」被副本反序接收。常見策略是每個 session 綁定單一寫入序列點。

Writes-follow-reads
causal write

使用者基於某次讀取做出的後續寫入,不能被套用到還沒看過該讀取版本的副本上,否則會破壞因果關係。

四條保證各自獨立、可以分開採用:上兩條(RYW、Monotonic Reads)管「讀到什麼」,下兩條(Monotonic Writes、Writes-follow-reads)管「寫入的順序與因果」。該看的是每一列右側的實作手段——它們幾乎都收斂到 Sticky Routing 與版本 token 這兩招,這正是緊接著的 Session Token 模式要展開的東西。

Session Token 的實務模式

每次讀寫回應都帶上副本進度,例如 {region: "ap", log: 1842} 或 per-shard vector。Client 後續請求帶回 token,Gateway 只把請求路由到進度至少達到該 token 的副本;若沒有副本符合,就等待、回 Leader 或回應可重試。

關鍵Session Guarantee 是產品語意,不只是資料庫功能

例如「訂單付款成功後,使用者自己的訂單頁必須立刻看到已付款」是 Read-your-writes;但「所有客服後台立即看到已付款」可能是另一個 SLA。把保證寫到 user journey 上,才知道哪些讀取要付出強一致成本。

一句話答法Session Guarantees 用較低成本保護單一使用者的因果體驗;常見做法是 Sticky Routing、Leader fallback 與版本 token,而不是把所有讀取都升級成全域強一致。

04

Quorum 讀寫:用交集換取可調一致性

Leaderless 複寫的核心公式:只要讀寫集合有交集,就有機會讀到最新版本。

在 Dynamo-style 系統中,一筆資料通常有 N 個副本。寫入成功需要 W 個副本確認,讀取則向 R 個副本查詢。若滿足:

W + R > N

理論上讀集合與寫集合必定有交集,讀取方就能遇到至少一個最新版本;再透過版本比較選出最新值,並把舊副本補上。

設定 語意 適合場景 風險
N=3, W=1, R=1 最快但沒有交集保證。 可容忍舊值的計數、推薦、快取資料。 Stale Read 常見,衝突收斂依賴背景修復。
N=3, W=2, R=2 典型 Majority Quorum。 一般 metadata、購物車、低額風險狀態。 節點故障時可用性下降;尾延遲受慢副本影響。
N=5, W=3, R=3 跨多 AZ 的強交集設定。 跨區重要狀態、需要較高讀寫信心的資料。 跨區 RTT 會放大 P99 latency。
N=5, W=1, R=5 寫入快、讀取嚴格。 寫多讀少,且讀取時願意付成本校驗。 任何副本慢都拖累讀取。

只有第一列 W+R=2 不大於 N=3、沒有交集保證,其餘三列都滿足 W+R>N。同樣有交集時,W 與 R 的分配決定成本落在寫入還是讀取——最後一列把成本全押在讀取端。

陷阱公式成立不等於免費 Linearizability

W + R > N 只保證讀寫集合有交集;若網路分區、 sloppy quorum、時鐘版本錯誤、或讀取沒有比較版本並修復舊副本,仍可能讀到舊值。Quorum 是工具,不是魔法。

一句話答法Quorum 用 W + R > N 讓讀寫集合相交,並透過版本比較找出新值;提高 R/W 能提升一致性信心,但會犧牲 latency 與故障時可用性。

05

互動演示:Quorum 與 Read Repair 實驗室

切換不同 R/W 設定,觀察 Stale Read、交集保證與 Read Repair 如何影響副本狀態。

下方模擬器使用 5 個副本。你可以選擇「快速最終一致」、「平衡 Majority」、「讀取嚴格」或「故障壓力」四種模式,依序執行寫入、讀取與 Read Repair,觀察哪些節點拿到新版本、讀取是否有機會遇到新值。

互動 · Quorum consistency lab 選模式後依序執行寫入、讀取、修復
等待操作:先按「寫入 v2」,再按「讀取」。
目前所有副本都停在 v1。不同模式會改變寫入確認數 W、讀取數 R,以及讀取是否足以碰到最新版本。
v1 舊副本 v2 最新副本 本次讀取集合 故障 / 不可達

觀察重點:低 W/R 帶來低延遲但容易讀到舊值;Majority 需要更多 ACK,卻能透過交集與 Read Repair 快速收斂。

一句話答法Quorum 的互動心法是「寫入碰到多少副本、讀取查多少副本、兩者是否交集」;Read Repair 則是在讀到新舊版本混雜時,把落後副本順手補齊。

06

Version Vector 與衝突解決

當系統允許多點寫入,就必須知道兩個版本是「先後」還是「併發」。

在 Multi-Leader 或 Leaderless 架構中,兩個 Client 可能在不同區域同時修改同一筆資料。若只用單一 timestamp,會把併發修改粗暴壓成「最後寫入者勝」(LWW),看似簡單,實際上可能遺失使用者更新。

Version Vector 的直覺:每個副本都維護自己的計數器;每次寫入時增加自己的 counter,並把整個 vector 附在資料版本上。
區域 A 修改購物車
{A:2, B:1}
區域 B 同時修改購物車
{A:1, B:2}
兩者互不支配
concurrent conflict

如何判斷版本關係

  • A dominates B:A 的每個 counter 都大於或等於 B,且至少一個更大;代表 A 已包含 B 的歷史。
  • B dominates A:反過來,B 是較新的線性後繼版本。
  • Concurrent:兩者各有某個 counter 比對方大;代表併發寫入,不能安全自動覆蓋。

衝突解決策略

策略 適合資料 優點 風險
Last-Write-Wins 狀態覆蓋型欄位,如暱稱、最後登入時間。 簡單、儲存成本低。 時鐘漂移與併發寫入會造成資料遺失。
Application Merge 購物車、文件協作、設定集合。 保留業務語意,能做精準合併。 需要應用層處理 siblings 與冪等合併。
CRDT Counter、Set、Presence、協作狀態。 數學上可交換、可結合、可冪等,天然收斂。 資料模型受限制,刪除與壓縮需要設計。

由上往下,保留的業務語意越多,實作成本也越高。該看「風險」欄:LWW 的風險是資料遺失,另外兩種的風險是設計成本,這正是下方陷阱要提醒的取捨。

陷阱LWW 是資料遺失策略,不是衝突解決萬靈丹

如果兩個裝置同時把購物車加入不同商品,LWW 會直接丟掉其中一邊。除非產品語意允許覆蓋,否則應優先使用 Application Merge 或 CRDT。

一句話答法Version Vector 用每個副本的 counter 判斷版本先後與併發;遇到併發版本時,系統必須用業務合併、CRDT 或明確的 LWW 策略收斂,而不能假裝衝突不存在。

07

面試考點與架構決策

把一致性需求翻譯成可落地的讀寫路由、Quorum 與衝突策略。

回答框架:先問資料語意,再選保證

面試官問「如何設計跨區資料庫的一致性」時,不要一開始就背 CAP。先把資料分級:哪些資料必須強一致、哪些只需要 Session Guarantee、哪些可接受最終一致。接著為每一類資料選讀寫路由與修復策略。

資料類型 建議保證 設計手段 取捨說法
付款狀態 / 庫存扣減 Linearizable 或 Consensus-backed。 單寫入 Leader、Raft/Paxos、Fencing Token。 願意犧牲跨區寫入延遲,換取不超賣、不重複扣款。
個人 Profile / 訂單頁 Read-your-writes + Monotonic Reads。 Session Token、Leader fallback、Sticky Routing。 保護使用者自己的體驗,不要求所有人即時看到。
Feed、按讚數、推薦特徵 Eventual Consistency。 Async Replication、Anti-entropy、CRDT Counter。 允許短暫舊值,換取高吞吐與低延遲。
協作文件 / 購物車 Causal Consistency + Merge。 Version Vector、Application Merge、CRDT Set。 避免併發更新互相覆蓋,成本是資料模型與合併邏輯變複雜。

每一列都是一次「資料語意 → 建議保證 → 設計手段」的翻譯。該看「設計手段」欄:同一個系統裡,四類資料各走不同的讀寫路由,而不是全系統只選一種一致性。

考點如何處理跨區低延遲與一致性的衝突?

標準答法是「資料分級 + 多模式讀寫」。關鍵狀態集中到 Consensus 或單 Leader;使用者體驗靠 Session Token;大量非關鍵讀寫採 Eventual Consistency;背景用 Read Repair / Anti-entropy 收斂。這比宣稱整個系統都強一致更可信。

風險一致性策略一定會影響下游

若上游資料可能短暫舊值,下游快取、搜尋索引、通知系統與分析 pipeline 都必須知道它們收到的是 eventually consistent event,而不是絕對最新狀態。否則會在 audit、客服後台或風控判斷中放大不一致。

一句話答法進階複寫一致性的面試核心是資料分級:關鍵資料用強一致,使用者路徑用 Session Guarantees,高吞吐資料用最終一致與背景修復,併發寫入則用版本向量與業務合併收斂。