用 Hyperdrive 讓 Worker 連既有的 Postgres
你已經有一個 Postgres,Hyperdrive 讓 Workers 連它又快又穩——完全不用搬家。
我們要串什麼?
你已經有一個區域型 Postgres 在跑——可能在 Neon、Supabase、AWS RDS,或你自己的伺服器上。它只住在一個地方。但你的 Workers 卻跑在數百個城市裡。這篇教學會用 Hyperdrive 把 Worker 接到那個資料庫,讓每個請求都能重複利用已經接通的連線、並從快取讀資料,而不是每次都付完整的延遲成本。
Hyperdrive 夾在中間,同時扮演「連線池(connection pooler,把連線存起來共用的中介)」和「查詢快取(query cache,把查詢結果記起來)」。你的程式碼照樣用一般的 Postgres 驅動程式——唯一的差別是它連到的是 env.HYPERDRIVE.connectionString,而不是資料庫真正的網址。
把它想成…
資料庫門口的一排待客計程車。與其每個 Worker 都重新叫一台新車、再等它開過來(重開一條連線),Hyperdrive 直接在路邊備好幾台發動中的車,還記得熱門目的地——所以大多數乘客上車就走。
各層負責什麼?
你的 Worker
跑遍全球、保持無狀態。它對 env.HYPERDRIVE.connectionString 開一個客戶端,然後執行 SQL。
Hyperdrive
擋在資料庫前面的連線池+快取層。重複利用連線、並回傳已快取的讀取結果。
你的 Postgres
依然是唯一的真實來源。資料表結構、資料、供應商通通維持原樣。
連線字串
存放在 Hyperdrive 設定裡,而不是 Worker 程式碼裡——資料庫密碼不會被打包進程式。
為什麼不直接連資料庫?
從遠方的 Worker 直接連線,每一次都要付 TCP + TLS + 身分驗證的握手成本,而且無伺服器(serverless)的大量呼叫很快就會把資料庫的連線數上限用光。連線池讓你重複利用熱連線;快取則讓重複的讀取查詢完全省掉那趟來回。
沒有 vs 有 Hyperdrive
下面這張圖把同一份工作畫了兩次。上半部直接連線、每次請求都重建一條連線;下半部走 Hyperdrive,重複利用已接通、進到連線池的連線——常常直接從快取回答。
時間都花在哪
在一條全新的直接連線上,光是握手就可能花掉好幾趟來回,資料都還沒開始傳。Hyperdrive 把這個成本只付一次,再分攤給大量的請求共用。
動手串起來
五個步驟:建立一個指向你資料庫的 Hyperdrive 設定、把綁定加進 wrangler.toml、安裝 Postgres 驅動程式、透過 env.HYPERDRIVE.connectionString 查詢,然後部署。
建立 Hyperdrive 設定
把你既有的連線字串交給 Hyperdrive。Wrangler 會印出一組 id——複製起來下一步要用。
npx wrangler hyperdrive create my-postgres \ --connection-string="postgres://user:password@db.example.com:5432/appdb"加入 [[hyperdrive]] 綁定
把 id 貼進 wrangler.toml。一定要開 nodejs_compat 旗標,因為 Postgres 驅動程式會用到 Node 的 API。
name = "my-worker" main = "src/index.js" compatibility_date = "2024-09-23" compatibility_flags = ["nodejs_compat"] [[hyperdrive]] binding = "HYPERDRIVE" id = "<paste-the-id-from-step-1>"安裝 Postgres 驅動程式
這裡用 postgres.js;node-postgres 的 pg 套件也可以。
npm i postgres透過 Hyperdrive 查詢
連到 env.HYPERDRIVE.connectionString——絕對不是資料庫真正的網址。每個 isolate 維持一個小連線池,並在背景關閉它。
import postgres from "postgres"; export default { async fetch(request, env, ctx) { // Connect to Hyperdrive, not the database directly const sql = postgres(env.HYPERDRIVE.connectionString, { max: 5, // small pool per Worker isolate fetch_types: false // skip an extra round-trip }); try { const products = await sql`SELECT id, name, price FROM products LIMIT 10`; // Close in the background so it does not delay the response ctx.waitUntil(sql.end()); return Response.json(products); } catch (err) { console.error(err); return Response.json({ error: String(err) }, { status: 500 }); } } };部署上線
發布 Worker。查詢就會走上有連線池、有快取的快速通道了。
npx wrangler deploy
安全地讀取與寫入
// Parameterized values are sent separately, never string-concatenated
const id = 42;
const rows = await sql`SELECT id, name FROM products WHERE id = ${id}`;
// Writes (INSERT/UPDATE/DELETE) are never cached — they always hit Postgres
await sql`INSERT INTO views (product_id) VALUES (${id})`;別把真實網址寫進程式碼
資料庫密碼只存在你第一步建立的 Hyperdrive 設定裡。一律透過 env.HYPERDRIVE.connectionString 連線,這樣機密就不會跑進你的原始碼或打包檔裡。
重點概念
連線字串
包含主機、連接埠、帳號、密碼與資料庫名稱的那串 URL。Hyperdrive 把你的藏在 env.HYPERDRIVE.connectionString 後面。
連線池
一組已接通、隨時可用的連線,在請求之間共用,沒人需要重複付建立連線的成本。
查詢快取
可快取的 SELECT 結果會被記住(預設 60 秒),一模一樣的重複查詢就能跳過資料庫。
建立連線延遲
一條全新連線在能跑查詢之前,必須先完成 TCP + TLS + 驗證的握手。連線池讓這個成本只付一次。
連線數上限
每個 Postgres 都有連線數上限。爆量的無伺服器流量很容易把它用光——連線池讓用量維持平穩。
資料庫仍是來源
Hyperdrive 只負責加速存取。你真正的資料永遠存放在你自己的 Postgres 裡。
小提示與陷阱
依新鮮度調整快取
快取預設開啟、最長保留 60 秒(可調到最多 1 小時)。如果某些資料一定要即時,可以用 npx wrangler hyperdrive update <id> --caching-disabled true 關掉它。
- 沒有 compatibility_flags = ["nodejs_compat"] 和夠新的 compatibility_date,Postgres 驅動程式會載入失敗。
- 只有唯讀的 SELECT 會被快取;INSERT/UPDATE/DELETE 一定會到 Postgres。
- 用到 NOW()、RANDOM()、CURRENT_DATE 的查詢會被視為不可快取——甚至只在 SQL 註解裡提到這些函式名稱,也會讓那筆查詢不快取。
- 一律用 ctx.waitUntil(sql.end()) 收尾,清理才不會拖慢回應。
- 每個 isolate 的連線池維持小一點(例如 max: 5);Hyperdrive 反正會在背後多工共用。
- 支援 Postgres 與相容資料庫(Neon、Supabase、RDS、CockroachDB、Timescale)——也支援 MySQL。
- 想要 Cloudflare 原生的 SQL 資料庫、而不是自備?可以看看 D1。