多個節點保存同一份資料時,單純要求「讀到最新」並不是精確的系統規格;分散式系統需要用操作的發起、生效與回應區間,明確定義讀寫者能期待什麼保證。 不同的一致性模型(consistency models)在正確性直覺與協調成本之間做出不同取捨。
本文接續時鐘與因果關係,從單一節點的順序推進到多副本狀態契約,為後續的複寫與故障切換建立衡量基礎。
查證日期:2026-11-04。線性一致性依 Herlihy 與 Wing(1990)原論文;循序一致性依 Lamport(1979);Session Guarantees 依 Terry 等人(1994)。未執行實際叢集部署或延遲注入實驗,文中數值與狀態歷程均為概念推演。
「讀到最新」為何需要精確化
在單一執行緒存取記憶體或單一資料庫時,「寫入後立刻讀取」直覺上應看見新值。但在分散式環境中,操作不是零時間的點,而是包含:
- 發起(invocation):客戶端送出請求的時間點。
- 回應(response):客戶端收到確認的時間點。
- 執行區間(execution interval):介於發起與回應之間的物理時間範圍。
若呼叫端 A 於 10:00:01 發起寫入、10:00:05 收到成功;呼叫端 B 於 10:00:03 發起讀取、10:00:04 收到結果。B 的讀取區間完全落在 A 的寫入區間內部,兩者在時間上並行重疊。此時 B 讀到舊值還是新值?若 B 讀到舊值,稍後於 10:00:06 發起讀取的 C 又該讀到什麼?
如果沒有嚴格契約,系統就無法說明何謂「正確」的行為。
線性一致性:最強的單物件即時保證
線性一致性(Linearizability),又稱強一致性或原子一致性(atomic consistency),是針對單一物件/單一暫存器定義的最高標準。它要求系統滿足兩項條件:
- 每個讀寫操作,都必須表現得如同在它的發起點與回應點之間的某個瞬間原子性生效。
- 若操作 A 的回應點在實體時間上先於操作 B 的發起點(即 A 已經完成,B 才開始),則 B 必須看見 A 的效果,或看見在 A 之後生效的其他更新。
這意味著系統對外呈現一個全域時間線,資料永遠不會「時光倒退」。參考 Herlihy & Wing(1990):Linearizability。
以文章匯出服務為例,工作狀態從 PENDING 更新為 RUNNING:
| 參與者 | 發起時間 | 操作內容 | 回應時間 | 觀測結果 | 合法性分析 |
|---|---|---|---|---|---|
| Client 1 | $t_1$ | 寫入狀態 RUNNING | $t_4$ | 成功 | 生效點介於 $[t_1, t_4]$ |
| Client 2 | $t_5$ ($> t_4$) | 讀取工作狀態 | $t_6$ | PENDING | 違反線性一致性(寫入已完成,後續讀取不可見舊值) |
| Client 3 | $t_2$ ($> t_1$) | 讀取工作狀態 | $t_3$ ($< t_4$) | PENDING | 合法(與寫入並行,生效點可在讀取之後) |
線性一致性的代價極高:為了讓所有客戶端在任意節點都能立刻看見最新生效的寫入,節點間必須在讀寫時進行即時協調,容易受網路延遲與節點故障影響。
循序一致性與因果一致性
若放寬實體時間的絕對約束,可以得到其他嚴格但代價較低的模型:
循序一致性(Sequential Consistency)
Lamport 於 1979 年提出:所有操作的執行結果,必須等同於所有操作依照某種全域交錯順序(global sequence)在單一處理器上執行,且該順序必須嚴格遵守每個個別程序原本的執行順序(program order)。
與線性一致性的關鍵差異在於:循序一致性不要求遵守實體時間的絕對先後。如果操作 A 在真實世界 $t_1$ 完成,操作 B 在 $t_2$ 執行,循序一致性允許系統將順序排成 B 在 A 之前,只要所有節點看到的順序一致、且不違背各自程序內部的順序。
因果一致性(Causal Consistency)
進一步放寬全域順序:如果操作 A 因果上先於操作 B(A → B,例如呼叫端看見 A 的結果後才發起 B),則所有節點必須以 A 在先、B 在後的順序看見它們。
對於沒有因果關聯的並行操作(concurrent operations),不同節點允許以不同的順序觀察到它們。這比循序一致性更弱,但允許在網路分割時持續提供非同步讀寫。
客戶端 Session Guarantees
在以使用者為中心的系統中,即便整個叢集無法提供全域線性一致性,通常仍需確保個別使用者體驗合理。Terry 等人(1994)提出四種客戶端會話保證(Session Guarantees):
- 讀己所寫(Read-Your-Writes):同一個客戶端更新某筆資料後,該客戶端隨後發起的讀取一定能看見自己剛才的更新(但其他客戶端可能稍有延遲)。
- 單調讀(Monotonic Reads):客戶端觀察到資料的某個版本後,隨後的讀取絕不會看見比該版本更舊的資料(避免使用者重新整理頁面時看到進度倒退)。
- 單調寫(Monotonic Writes):同一個客戶端的多筆寫入操作,系統必須按照其送出順序依序套用。
- 寫隨讀後(Writes-Follow-Reads):客戶端讀取某狀態後發起的寫入,在任何副本套用時,該讀取所依賴的狀態必然已經先套用(保留因果鏈)。
參考 Terry et al.(1994):Session Guarantees。
最終一致性與收斂
最終一致性(Eventual Consistency)是弱一致性的一種:在沒有新的更新注入的前提下,所有副本經過一段時間的通訊傳播,最終會收斂到相同的狀態。
但「最終」沒有提供時間上限保證(可以是數毫秒,也可以是數分鐘)。在收斂之前,不同的客戶端可能讀到互相衝突或陳舊的資料。單純宣稱最終一致性是不夠的,系統必須明確交代:
- 衝突發生時依據什麼規則決定最終結果(例如版本向量、特定業務合併邏輯,見後續篇章)?
- 客戶端在收斂過渡期是否具備基本的單調讀或讀己所寫保護?
易混淆概念邊界
| 概念維度 | 核心關注重點 | 代表標準與模型 | 典型防護錯誤 |
|---|---|---|---|
| 副本一致性(Replica Consistency) | 多副本系統中,單一物件在空間與時間上的讀寫順序契約 | Linearizability、Sequential、Causal、Eventual | 誤以為「讀到最新」不需要界定呼叫區間與時鐘前提 |
| 交易隔離性(Transaction Isolation) | 單一或多個節點中,包含多個物件讀寫的並行交易互不干擾 | Serializability、Repeatable Read、Read Committed | 將 Serializable(交易全序)與 Linearizable(即時單物件原子性)混為一談 |
| 資料庫一致性(ACID Consistency) | 交易前後,資料是否符合應用定義的結構完整性與業務約束 | 外鍵、唯一鍵、非負餘額約束 | 將 ACID 的 C 當成分散式節點間的同步狀態 |
建立了讀寫契約的精確定義後,下一篇複寫、確認與故障切換將探討:多節點架構採用何種複寫拓樸,才能在節點崩潰與切換時維持這些承諾。