Skip to content
Anonymous

Cloudflare D1 資料庫實作:在邊緣區域的高性能資料同步與管理

深入探討 DueWise 如何利用 Cloudflare D1 (SQLite on Edge) 實現全球資料極速同步,並分享 SQL 結構設計與性能優化心得。

#D1 #Cloudflare #SQL #Database #Edge Computing

Cloudflare D1 資料庫實作:在邊緣區域的高性能資料同步與管理

在分散式系統中,最難處理的通常不是計算邏輯,而是「狀態」。對於 DueWise 這樣一個需要全球存取的效期管理工具,如何讓身處紐約的用戶與身處台北的用戶都能享有極低的讀寫延遲?我們的答案是 Cloudflare D1

D1 是 Cloudflare 基於 SQLite 構建的無伺服器 (Serverless) 關聯式資料庫。它強大的地方在於它直接嵌入在全球分佈的 Worker 中。這篇文章將分享我們在 DueWise 中使用 D1 的實戰經驗。

為什麼選擇 D1 而不是傳統 RDS 或 MongoDB?

  1. 零延遲存取: D1 運行在邊緣,與計算(Worker)同一個節點。
  2. SQLite 的簡潔性: 對於清單類的數據結構,關聯式資料庫的 SQL 查詢語法遠比 NoSQL 穩定且靈活。
  3. 無感擴展 (Serverless): 我們不需要配置主機規格、不用管理分片 (Shards),Cloudflare 幫我們處理了一切。

DueWise 的資料表結構設計

在 DueWise 中,我們設計了一個核心資料表 items,透過 owner (用戶 Email) 進行索引優化。

CREATE TABLE items (
    id TEXT PRIMARY KEY,
    owner TEXT NOT NULL,
    name TEXT NOT NULL,
    category TEXT,
    expiry_date TEXT NOT NULL, -- 以 YYYY-MM-DD 儲存,方便排序
    start_date TEXT,
    note TEXT,
    is_recurring INTEGER DEFAULT 0,
    recurring_interval INTEGER,
    recurring_unit TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_owner ON items(owner);
CREATE INDEX idx_expiry ON items(expiry_date);

優化要點:

  • 索引優化: 我們為 owner 建立了索引,確保每個用戶加載「我的清單」時都能在 10ms 內完成掃描。
  • 類型選擇: 雖然 SQLite 沒有專用的日期類型,但我們堅持使用 TEXT (YYYY-MM-DD),這讓我們在 SQL 語法中可以直接進行大小比較,例如 SELECT * FROM items WHERE expiry_date < date('now')

技術實戰:Astro 內的 D1 呼叫

在 Astro 組件中,我們可以透過 Astro.locals 取得 Cloudflare 環境變數提供的 D1 實例:

const db = (Astro.locals as any).runtime?.env?.DB;
const userEmail = session.user.email;

const { results } = await db.prepare(
  'SELECT * FROM items WHERE owner = ? ORDER BY expiry_date ASC'
).bind(userEmail).all();

這種整合方式非常乾淨,沒有連接字串(Connection Strings)的困擾,也沒有連接池(Connection Pooling)爆炸的問題,因為這本質上是 HTTP 型態的請求。

修復「過時數據」:D1 的最終一致性

在使用 D1 時需要注意,雖然讀寫很快,但在極少數分散式場景下,可能會遇到「最終一致性」的細微差異。為了確保 DueWise 的用戶體驗,我們在前端實作了 Optimistic UI (樂觀更新)

當用戶點擊「刪除物品」時,Zustand Store 會立刻從本地列表中移除該項,同時發送後端請求。即使 D1 正在處理全球同步,用戶看到的介面依然是流暢、無延遲的。

如何處理離線模式與資料庫同步?

這也是 D1 展現價值的地方。由於 D1 與 IndexedDB 的結構高度相似(都是關聯式概念),我們開發了一組 Sync Logic:

  1. 離線操作: 數據寫入瀏覽器的 IndexedDB。
  2. 偵測連線: PWA 利用導航狀態偵測網路。
  3. 批次上傳: 將本地的新增/修改透過 D1 批次 API 一次性寫入雲端。

D1 Batch API 範例:

const statements = syncPayload.map(item => 
  db.prepare("INSERT INTO items (id, ...) VALUES (?, ...)").bind(item.id, ...)
);
await db.batch(statements);

使用 batch 不僅節省了網路往返時間,還能保證操作的原子性 (Atomicity)。

結論

Cloudflare D1 徹底改變了我們看待資料庫的方式。它不再是一個沉重、需要遠程連接的「龐然大物」,而是一個輕巧且無處不在的「局部變數」。對於追求極速與全球化佈署的 PWA 應用程式,D1 無疑是當前最強大的後盾。

下一篇文章,我們將探討驗證的核心:「Auth.js (Auth-Astro) 認證架構:如何在邊緣端實現安全的 OAuth 整合」。