5.1 邊緣資料儲存的取捨#
本節目標#
- 理解 CAP 定理在邊緣運算環境的具體意涵
- 認識邊緣多副本系統面臨的一致性挑戰
- 區分 weak eventual consistency 與 strong eventual consistency
- 一句話理解 CRDT 的核心思想
- 能依工作負載特性選擇 D1 / KV / R2 / Durable Objects
從資料中心到邊緣:一致性問題被放大了#
傳統架構中,資料庫通常部署在單一資料中心(或主從複製的少數節點),應用伺服器「連過去」查詢。網站的所有請求都繞到同一個地方,一致性天然較容易維持——因為只有一個(或少數幾個)權威節點。
Cloudflare 的邊緣架構則不同:你的程式碼跑在全球三百多個城市的節點上,離使用者最近的那一個。當資料也要「放在邊緣」時,問題就來了:
- 多副本:同一份資料在台北、東京、法蘭克福各有的一份拷貝
- 網路分區是常態:跨洲的光纖會斷、路由會抖動
- 沒有區域網路的低延遲優勢:任兩個邊緣節點之間都是廣域網路延遲(數十到數百毫秒)
在資料中心裡,讓所有節點「達成共識」可能只要幾毫秒;在邊緣,同樣的共識可能要 100ms 以上,甚至根本連不上。於是「一致性」變成一個必須明確選擇的取捨,而不是免費的午餐。
CAP 定理:三選二的陷阱#
CAP 定理(Eric Brewer, 2000;Gilbert & Lynch, 2002 證明)指出,分布式系統在以下三個性質中,最多只能同時保證兩個:
| 性質 | 意義 | 邊緣環境下的解讀 |
|---|---|---|
| Consistency | 所有節點在同一時刻看到相同的資料(線性一致性) | 台北寫入的資料,東京立刻讀到 |
| Availability | 每個請求都能得到(非錯誤的)回應 | 就算部分節點失聯,服務仍然可用 |
| Partition tolerance | 網路分區發生時系統仍能運作 | 洲際光纖斷線不會導致整個系統停擺 |
常見誤解是「三選二」好像可以放棄 P。但 P 不是可選項——分區一定會發生,放棄 P 等於假設網路永遠可靠,這在邊緣環境是不成立的。所以真正的選擇是:
- CP:分區發生時拒絕服務,保證資料一致(如傳統的分布式 SQL 資料庫、ZooKeeper)
- AP:分區發生時繼續服務,接受資料暫時不一致並最終收斂(如 DNS、Cassandra、Cloudflare KV)
Cloudflare 的產品線正是刻意覆蓋這個光譜的兩端:KV/R2 偏 AP,Durable Objects 偏 CP,D1 則用「單一寫入者」的方式折衷。
一致性的光譜:weak vs strong eventual consistency#
先定義 Eventual Consistency(最終一致性):只要停止寫入並等待足夠時間,所有副本最終會收斂到相同的值。
但「最終收斂」有兩種截然不同的保證強度:
| 等級 | 名稱 | 保證 | 典型風險 |
|---|---|---|---|
| Weak EC | 弱最終一致 | 「最後」收斂,但收斂到哪個值沒有保證(last-write-wins,依時鐘與傳輸順序而定) | 兩個節點各寫一次,收斂後可能只剩後寫的那筆;讀回的順序在不同節點可能不同 |
| Strong EC | 強最終一致 | 所有副本以相同的順序與結果收斂,不遺失任何並行更新(CRDT 達成) | 收斂結果是數學上定義好的合併(如計數器相加、集合聯集) |
關鍵差異在「並行寫入」怎麼處理。假設兩個使用者幾乎同時對同一個鍵寫入:
- Weak EC(KV):內部在某個時刻選出一個「贏家」(last-write-wins),另一筆直接消失。適合快取、組態、feature flag——本來就是「後者為準」的語意。
- Strong EC(CRDT):兩筆更新都能以確定性的方式合併,例如計數器
3和5並行更新後收斂為8,而不是隨機挑一個。
CRDT:一句話版#
CRDT(Conflict-free Replicated Data Type,無衝突複製資料型別)是一種資料結構,其合併運算滿足交換律、結合律與冪等性,因此副本之間無論以什麼順序、重複同步幾次,結果都必然相同。
常見的 CRDT 型別:G-Counter / PN-Counter(計數器)、G-Set / OR-Set(集合)、LWW-Register(暫存器)、以及序列型別(如協作文件用的 RGA)。Durable Objects 的房型房間計數器、Linear/Figma 式的協作編輯,背後都有 CRDT 或等僟思想的影子。
注意:CRDT 解決的是「合併的正確性」,但不保證即時一致——它仍是最終一致,只是收斂過程沒有衝突。
Cloudflare 四種儲存的對比與選型#
| 產品 | 資料模型 | 一致性特性 | 延遲特性 | 最佳用途 |
|---|---|---|---|---|
| D1(SQLite) | 關聯式(SQL) | 單一主寫入者=強一致讀寫(同 session) | 首次讀有複製延遲;寫入需繞到主節點 | 部落格文章、使用者帳號、需要 JOIN 與交易的中型應用 |
| KV | 鍵值(最大 25MB/值) | 最終一致(寫入後最長 60 秒全球生效) | 讀取極快(就近邊緣);寫入傳播較慢 | 組態、feature flag、快取、重新導向對應表 |
| R2 | 物件儲存(S3 API) | 強一致(讀寫皆強) | 寫入稍慢;讀取可搭配 CDN 快取 | 圖片、影片、備份、大檔案下載(zero egress 費用) |
| Durable Objects | 有狀態的 JS 物件 | 線性一致性(單一實例) | 讀寫皆極快(物件有個固定家,就近常駐) | 即時協作、WebSocket 房間、全域計數器、速率限制 |
選型的思考順序:
- 需要 SQL / 交易 / 多表關聯? → D1
- 只是讀多寫少的鍵值對? → KV
- 要存的是大檔案(圖片、影片、備份)? → R2
- 需要「同一時刻全世界只有一份真相」+ 即時互動? → Durable Objects
一個具體例子(本書第五、六章會持續使用的部落格 + 留言板):
- 文章本體與分類 → D1(關聯查詢、交易)
- 「熱門文章」榜單、特色快取 → KV
- 使用者上傳的封面圖 → R2
- 即時留言室與線上人數 → Durable Objects
小結與練習#
本節建立了邊緣資料儲存的理論地基:CAP 定理告訴我們分區下 C 與 A 二選一;最終一致性有強弱之別;CRDT 用數學保證合併正確;Cloudflare 用四個產品對應這光譜的不同位置。
練習:
- 目錄式的短網址服務(短碼 → 長網址),寫入頻率極低、讀取量極大,你會選哪個儲存?為什麼?(提示:分區發生時,你希望它「可用」還是「拒絕」?)
- 一個全世界的投票應用,每個使用者投一票,票數要即時顯示。用 KV 會出什麼問題?用 D1 會出什麼問題?(提示:寫入傳播延遲 vs. 寫入衝突)
- 查閱文件:KV 的寫入傳播時間上限是多少?R2 的 egress 收費是多少?把答案記下來,下一節會用到。
- 思考題:你的個人部落格有多少資料需要「強一致」?答案往往出乎意料地少——這也是邊緣架構的設計心法:先量測一致性需求,再選儲存,而不是反過來。