sell整合實戰
alt_route

我該用哪種儲存?KV / D1 / R2 / Durable Objects / Hyperdrive 選型

五種儲存、一個 Worker。問自己幾個問題,答案自然浮現。

5種儲存選項
$0R2 流量費
~60sKV 全球同步
SQLD1 是關聯式
insights

我們在選什麼?

Cloudflare 提供五種差很多的資料儲存方式,它們全都掛在你的 Worker 後面。選錯會讓一切變難;選對則讓程式碼又短又快。這份指南把「該用哪個」變成幾個是/否的問題。

先把所有角色擺上同一個舞台:Worker 是大腦,每種儲存各演一個角色。KV 是快取、D1 是 SQL 資料表、R2 是檔案櫃、Durable Objects 是「唯一真相來源」、Hyperdrive 是通往你既有資料庫的快速通道。

schema一個 Worker 後面的五種儲存

快取

SQL

檔案

狀態

加速

瀏覽器

Worker

Workers KV

D1

R2

Durable Objects

Hyperdrive

Postgres / MySQL

kitchen

把它想成…

一間廚房。KV 是調味料架(隨手拿、偶爾補貨)、D1 是食譜本(有結構、可查找)、R2 是大型冷凍庫(又大又笨重的東西)、Durable Objects 是主廚(手上握著唯一一份正式點單)、Hyperdrive 則是通往你「現有供應商」的送貨捷徑。

account_tree

決策樹

從最上面開始,照著答案往下走,每條分支都會落在一個產品上。之後你當然可以混搭多種儲存,但對「單一一筆資料」來說,這棵樹會給你一個明確的預設答案。

schema四個問題選出儲存

你要存什麼資料?

大型檔案 / 二進位物件?

需要關聯式 SQL 查詢?

已有 Postgres / MySQL?

強一致性 + 協調?

Workers KV

D1

R2

Durable Objects

Hyperdrive

info

順序有意義

先問「是不是大檔案」(R2 最好認),再問「需不需要關聯式」(D1 或 Hyperdrive),接著問「要不要強一致性」(Durable Objects)。如果都不是,那通常就是一筆「讀多寫少」的小資料,答案幾乎都是 KV。

target

五個選項一次看懂

每個儲存一張卡片,附上「什麼時候該用它」的一句話原則。

key

Workers KV — 何時用…

小資料、讀遠多於寫,而且約 60 秒的全球同步可以接受:快取、功能開關、設定、登入工作階段。

table

D1 — 何時用…

需要關聯式資料表與 SQL(JOIN、WHERE、ORDER BY),而且想要一個 Cloudflare 原生、不用自己養伺服器的資料庫。

inventory_2

R2 — 何時用…

要存大型檔案——圖片、影片、PDF、備份——而且想要零「egress(對外下載流量)」費用。

hub

Durable Objects — 何時用…

某一份狀態必須強一致且需要協調:計數器、聊天室、遊戲狀態、鎖、即時協作。

rocket_launch

Hyperdrive — 何時用…

你已經有 Postgres / MySQL 資料庫,只想讓它從 Workers 連起來變快——不用搬遷、不用改寫。

construction

每個 binding 在程式碼裡長怎樣

「binding(綁定)」是你在 wrangler.jsonc 宣告的一個名字,它會以 env.某某 的形式出現在 Worker 裡。下面是每種儲存最小的真實片段——注意它們的存取方式差很多。

  1. KV — 讀取 / 寫入一個值

    用 key 查找;值是字串(或串流)。可選的 TTL 會讓 key 自動過期。

    js
    // wrangler.jsonc -> { "kv_namespaces": [{ "binding": "KV", "id": "..." }] }
    const cached = await env.KV.get("user:42");
    await env.KV.put("user:42", JSON.stringify(user), { expirationTtl: 3600 });
  2. D1 — 預備式 SQL 查詢

    用 ? 佔位符寫 SQL,用 bind() 填值,再用 .all() 取回資料列。

    js
    // wrangler.jsonc -> { "d1_databases": [{ "binding": "DB", "database_name": "app" }] }
    const { results } = await env.DB
      .prepare("SELECT * FROM orders WHERE city = ?")
      .bind("Taipei")
      .all();
  3. R2 — 存入 / 取出一個物件

    用 put() 以 key 存檔,再用 get() 取回一個物件,它的 .body 是串流。

    js
    // wrangler.jsonc -> { "r2_buckets": [{ "binding": "BUCKET", "bucket_name": "files" }] }
    await env.BUCKET.put("invoice.pdf", request.body);
    const object = await env.BUCKET.get("invoice.pdf");
    return new Response(object.body);
  4. Durable Objects — 呼叫 stub

    getByName() 會回傳「那個名字唯一的一個實例」;直接用 RPC 呼叫它的方法。所有呼叫者都打到同一個物件。

    js
    // wrangler.jsonc -> durable_objects: { "name": "ROOM", "class_name": "Room" }
    const stub = env.ROOM.getByName("room-42");
    const count = await stub.increment(); // strongly consistent
  5. Hyperdrive — 連線字串

    讀取 env.HYPERDRIVE.connectionString,用一般的 pg 客戶端連線;連線池與快取都自動幫你處理。

    js
    // wrangler.jsonc -> { "hyperdrive": [{ "binding": "HYPERDRIVE", "id": "..." }] }
    import { Client } from "pg";
    
    const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });
    await client.connect();
    const { rows } = await client.query("SELECT * FROM products LIMIT 10");
school

選型背後的關鍵字

大多數的選擇其實是被三個概念決定的:一致性、關聯式 vs 鍵值、以及物件儲存。搞懂它們,那棵決策樹就一目了然。

schedule

最終一致性

寫入後,其他地區可能要約 60 秒才看得到新值——它們會「最終」追上。KV 就是這樣:拿來做快取很棒,拿來存銀行餘額就錯了。

verified

強一致性

每個讀取者永遠、立刻看到最新的寫入。Durable Object 能做到,因為「剛好只有一個實例」擁有這份資料、並依序處理請求。

table_rows

關聯式 (SQL)

資料放在有欄位與關聯的「資料表」裡,用 SQL 查詢——JOIN 串接資料表、WHERE 過濾、ORDER BY 排序。D1(以及透過 Hyperdrive 連的自家資料庫)都是關聯式。

data_object

鍵值

沒有資料表、沒有 SQL——只有一個名字(key)指向一個值。又快又簡單,但你只能用「精確的 key」查找。KV 就是純粹的鍵值儲存。

inventory_2

物件儲存

專為大型、內容不透明的檔案(「物件」)打造,例如圖片與影片,用一個 key 來定址。R2 就是物件儲存,而且下載這些檔案不收 egress 流量費。

hub

協調

當很多使用者同時動到「同一個共享的東西」——同一個計數器、同一個聊天室——必須有人把它們排隊,更新才不會打架。那個「唯一擁有者」正是 Durable Objects 提供的。

schema一致性光譜

較弱一致性

Workers KV

D1

Durable Objects

較強一致性

tips_and_updates

速查表、混搭與陷阱

什麼時候用哪個…

  • 用 KV:小資料讀遠多於寫,且約 60 秒的全球同步可接受(快取、設定、工作階段)。
  • 用 D1:需要關聯式資料表與 SQL 查詢(JOIN/WHERE/ORDER BY),且想要 Cloudflare 原生資料庫。
  • 用 R2:要存大型檔案——圖片、影片、PDF、備份——而且想要零 egress 流量費。
  • 用 Durable Objects:某一份共享狀態必須強一致且需要協調(計數器、聊天室、鎖)。
  • 用 Hyperdrive:你已在別處跑 Postgres/MySQL,只想讓它從 Workers 連起來變快——不用搬遷。
extension

其實可以混搭

真實的應用通常會混用:把上傳的檔案放 R2、它的中繼資料放 D1、把熱門查找快取在 KV,再用一個 Durable Object 守住「絕對不能重複計數」的那個計數器。

warning

常見選錯

別把大型檔案塞進 KV(單筆上限 25 MiB,本來就不是給二進位物件用的),也別用 KV 存「全球每處都得即時最新」的資料。別只為了放靜態資料就動用 Durable Objects——那種用一張資料表就好。如果你根本沒有既有資料庫,就別選 Hyperdrive,直接從 D1 開始。

  • KV:讀多寫少、最終一致、只有鍵值、單筆最多 25 MiB。
  • D1:以 SQLite 為基礎的關聯式 SQL、有讀取副本,是應用資料的好預設。
  • R2:相容 S3 的物件儲存、無 egress 流量費,最適合媒體與備份。
  • Durable Objects:一個名字對應一個實例、強一致、內建自己的 SQLite。
  • Hyperdrive:在你既有 Postgres/MySQL 前面加上連線池與快取——它不是一個新資料庫。