← Back to Blog

Cloudflare D1 冷啟動延遲分析與優化方案

Cloudflare性能

Cloudflare D1 是運行在 Workers 邊緣網絡上的 SQLite 數據庫,近期在接入 Newsletter 訂閱功能時遇到了冷啟動延遲問題,本文記錄分析過程和優化方案。

問題現象

在低流量時段(Worker 長時間未被調用後),首次數據庫查詢的 P99 延遲超過 800ms,遠高於正常的 30-80ms。

根本原因

D1 的底層基於 SQLite,Worker 運行在 Cloudflare 的隔離(Isolate)中。當 Isolate 因長時間空閒被回收後,下次請求需要重新初始化運行環境,即”冷啟動”。D1 的 HTTP API 調用還需要建立到數據中心的連接,進一步增加延遲。

冷啟動耗時組成:
  Isolate 初始化  ≈ 200-400ms
  D1 連接建立    ≈ 100-300ms
  實際查詢執行   ≈ 10-50ms
  ─────────────────────────
  合計            ≈ 310-750ms

優化方案

方案一:Cron Trigger 保活(推薦)

每 5 分鐘通過 Cron 觸發一個輕量查詢,防止 Isolate 被回收:

// wrangler.toml
[triggers]
crons = ["*/5 * * * *"]

// worker.ts
export default {
  async scheduled(event, env) {
    await env.DB.prepare('SELECT 1').first();
  }
};

代價: 每天 288 次調用,在 Workers 免費額度內。

方案二:讀路徑加緩存層

對頻繁讀取的數據(訂閱者總數、最新文章列表),用 Cache API 或 KV 緩存,減少 D1 調用頻率:

const cacheKey = new Request('https://cache/subscriber-count');
const cached = await caches.default.match(cacheKey);
if (cached) return cached;

const result = await env.DB.prepare(
  'SELECT COUNT(*) as count FROM subscribers'
).first();
// 緩存 60 秒
const response = new Response(JSON.stringify(result), {
  headers: { 'Cache-Control': 'max-age=60' }
});
await caches.default.put(cacheKey, response.clone());
return response;

方案三:[需驗證] Smart Placement

開啟 Workers Smart Placement,讓 Worker 自動運行在距離 D1 數據庫最近的節點,縮短內部延遲。在 wrangler.toml 中添加:

[placement]
mode = "smart"

結論

目前採用方案一(Cron 保活)+ 方案二(KV 緩存讀路徑),冷啟動場景從 800ms 降至 ~120ms,正常路徑維持在 40ms 以內。方案三效果[需驗證],待觀察數據後決定是否啟用。