跳轉到

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 房間、全域計數器、速率限制

選型的思考順序:

  1. 需要 SQL / 交易 / 多表關聯? → D1
  2. 只是讀多寫少的鍵值對? → KV
  3. 要存的是大檔案(圖片、影片、備份)? → R2
  4. 需要「同一時刻全世界只有一份真相」+ 即時互動? → Durable Objects

一個具體例子(本書第五、六章會持續使用的部落格 + 留言板):

  • 文章本體與分類 → D1(關聯查詢、交易)
  • 「熱門文章」榜單、特色快取 → KV
  • 使用者上傳的封面圖 → R2
  • 即時留言室與線上人數 → Durable Objects

小結與練習#

本節建立了邊緣資料儲存的理論地基:CAP 定理告訴我們分區下 C 與 A 二選一;最終一致性有強弱之別;CRDT 用數學保證合併正確;Cloudflare 用四個產品對應這光譜的不同位置。

練習:

  1. 目錄式的短網址服務(短碼 → 長網址),寫入頻率極低、讀取量極大,你會選哪個儲存?為什麼?(提示:分區發生時,你希望它「可用」還是「拒絕」?)
  2. 一個全世界的投票應用,每個使用者投一票,票數要即時顯示。用 KV 會出什麼問題?用 D1 會出什麼問題?(提示:寫入傳播延遲 vs. 寫入衝突)
  3. 查閱文件:KV 的寫入傳播時間上限是多少?R2 的 egress 收費是多少?把答案記下來,下一節會用到。
  4. 思考題:你的個人部落格有多少資料需要「強一致」?答案往往出乎意料地少——這也是邊緣架構的設計心法:先量測一致性需求,再選儲存,而不是反過來。