CRDT 讓副本不用鎖也能同步
CRDT 讓分散式應用能同時接受多方寫入,之後再自動收斂成一致結果,適合離線優先、協作編輯與多區部署。

CRDT 讓分散式應用能同時接受多方寫入,之後再自動收斂成一致結果。
說真的,這東西很適合分散式系統。你不用每次寫入都先問伺服器。副本先收資料,之後再合併就好。
這篇講的是 CRDT。它是 Conflict-free Replicated Data Type 的縮寫。概念在 2011 年正式整理出來。作者是 Marc Shapiro、Nuno Preguiça、Carlos Baquero 和 Marek Zawirski。
實務上,Redis、Riak,還有 Azure Cosmos DB 都碰過這套路。講白了,它不是論文玩具,是真的進過生產環境。
| Fact | Value | Why it matters |
|---|---|---|
| Formal definition | 2011 | CRDT 變成正式研究主題 |
| Core property | Eventual convergence | 副本可短暫不同,最後仍一致 |
| Two main families | State-based and operation-based | 團隊可在簡單合併與省流量間選擇 |
| Example systems | Redis, Riak, Cosmos DB | 它已進入實際資料庫與服務 |
CRDT 為什麼重要
訂閱 AI 趨勢週報
每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。
不會寄垃圾信,隨時可取消。
分散式軟體最煩的,就是大家同時改同一份資料。兩個使用者一起編輯,兩台伺服器同時收寫入,結果就會撞車。傳統作法是加鎖、做協調、跑共識。能解,但延遲會上來,服務也更脆。

CRDT 的想法比較直白。先讓每個副本本地接受更新。之後再用固定規則合併。只要資料型別設計對了,副本就算先分歧,最後也會收斂到同一份結果。
這對離線優先 app 很有用。像協作編輯、聊天、筆記同步、手機離線回寫,都很吃這套。你不想因為網路慢,就卡住每一次輸入。
- 每個副本都能先本地寫入。
- 不需要每次都做跨節點協調。
- 合併規則寫在資料型別裡。
- 副本最後會收斂成一致狀態。
兩大類型,兩種取捨
CRDT 大致分成兩種。第一種是 state-based CRDT,也叫 CvRDT。第二種是 operation-based CRDT,也叫 CmRDT。兩者都追求 strong eventual consistency,但資料傳輸方式不同。
state-based CRDT 會把整個狀態送出去。接收端再用 merge function 合併。這個 merge 必須滿足 commutative、associative、idempotent。翻成白話就是,順序亂掉、重複送一次,都不能把結果弄壞。
operation-based CRDT 則是送操作,不送整包狀態。這樣通常比較省頻寬。代價是傳輸層要更可靠。操作要避免重複,還要維持 causal order。網路層沒做好,資料就會亂。
“The merge function should compute the join for any pair of replica states, and should form a semilattice with the initial state as the neutral element.”
這句話很硬,但意思很單純。合併函式要能把兩個副本狀態接起來,而且不怕晚到、重送、亂序。這就是 CRDT 的核心約束。沒有這條,整套設計就會翻車。
- state-based CRDT 比較好設計。
- 它常搭配 gossip 傳播。
- operation-based CRDT 比較省流量。
- 它更吃訊息系統品質。
- 兩者都要保證最後收斂。
幾個經典例子最好懂
先看 G-Counter。它是只增不減的計數器。每個節點只改自己的槽位。合併時取每個槽位的最大值。最後再把整個陣列加總。這樣就不怕兩邊同時加 1。

再看 PN-Counter。它把增和減拆成兩個 G-Counter。對外看起來可以加減,內部其實還是單向遞增。這種設計很 CRDT。外表像一般資料結構,底層卻很克制。
集合類型也很經典。G-Set 只能新增。2P-Set 加上 tombstone,刪除後就不能再回來。LWW-Element-Set 用時間戳決勝負。OR-Set 則更細膩,能保留更多並行意圖。
- G-Counter:分散式累加。
- PN-Counter:可加可減,但內部仍單向成長。
- G-Set:只允許新增。
- 2P-Set:刪除有墓碑。
- LWW-Element-Set:靠 timestamp 決定勝負。
- OR-Set:更適合多人協作。
跟傳統一致性方案比,差在哪
先講結論。CRDT 不是拿來取代所有一致性方案。它比較像一把專用工具。適合的地方很好用,不適合的地方就會很卡。你如果硬拿去做複雜交易,通常只會把自己搞累。
跟鎖、兩階段提交、共識協定比,CRDT 最大的好處是少協調。少協調代表延遲低,跨區也比較不怕。代價是資料型別要先設計好,不能隨便亂塞任意邏輯。
從系統角度看,CRDT 很適合 counters、flags、sets、協作註記。這些資料有個共通點。它們常常只需要「最後能對上」,不一定要每一步都同步到完全一致。
- CRDT 適合離線優先與多區部署。
- 鎖和共識適合強一致交易。
- CRDT 對資料模型有要求。
- 不是每種狀態都能輕鬆改成 CRDT。
- 設計好時,延遲和阻塞會少很多。
產業脈絡其實很現實
CRDT 最早是為了協作編輯和行動裝置。這很合理。手機常常斷線。多人又會同時改同一份文件。你不可能每打一個字,就等遠端確認。那體驗會爛到爆。
後來,聊天系統、媒體分發、遊戲狀態、地理分散資料庫也開始碰它。SoundCloud 就是常被拿來提的例子之一。它提醒大家,CRDT 不只是學術名詞。它真的能處理分散式寫入的髒活。
如果你在做多區服務,CRDT 會出現在幾個地方。像是計數、通知已讀、線上狀態、協作標記。這些欄位看起來小,卻常常是系統最容易吵架的地方。把它們改成可收斂資料型別,通常比硬上全域鎖更實際。
你也可以先看另一篇 eventual consistency vs. strong consistency。先搞懂一致性光譜,再回來看 CRDT,會比較有感。
講白了,CRDT 解的是一個很工程的問題。不是要你相信某種理論。是要你少踩同步地雷。
下一步怎麼看待 CRDT
CRDT 很強,但不是萬能。它最適合的是單調成長、可合併、可收斂的狀態。像任意刪除、複雜交易、嚴格排序,這些就沒那麼順。
如果你是開發者,我會建議先挑一個功能來看。像是計數器、草稿同步、協作註解,或線上狀態。問自己一句話:這個狀態能不能改成 monotonic?如果可以,你就有機會少掉很多 coordination 成本。
我自己的判斷很直接。CRDT 不是拿來炫技的。它是拿來救分散式系統的手感。當你的產品開始跨區、離線、多人同寫時,這套東西就會變得很值錢。下一步最實際的做法,就是把一個功能畫成狀態圖,看看能不能先從 CRDT 化開始。