Vercel function 預設跑在美東:把它搬到新加坡配對 Neon 後,部署速度從 523ms 降到 93ms
直接回答
Vercel function 預設跑在美東 iad1,如果 DB 在亞太 region,每次 SSR 跨太平洋查 DB 多吃 250ms 純網路延遲。改 vercel.json 加 regions 配對 DB region,加上首頁 60 秒 edge cache 雙刀流,實測首頁 SSR warm 從 523ms 降到 93ms,5.6 倍速。任何 Vercel + serverless DB 部署都該跑這個 SOP。
最近兩個用 Vercel + Neon 的專案都被嫌慢。一個是個人工作日誌站,一個是顧問案的客戶網站。打開首頁明顯感覺到「載入中」那半秒。
業主問我:「這個怎麼這麼慢?」
完整評估跑下來,發現是一個多數人不會注意的預設值問題。
—
第一個診斷:X-Vercel-Id 顯示 function 跑美東
我先用 curl 看 response header:
curl -I https://my-site.vercel.app/api/xxx
回傳裡有一行:
X-Vercel-Id: hkg1::iad1::xxx
這個 header 的格式是 edge-node::function-region::request-id。
hkg1 是香港邊緣節點(CDN),這個正常,因為訪客從台灣連最近的就是香港 edge。
問題出在 iad1。iad1 是華盛頓 DC,這是 Vercel function 真正執行的地方。所有新建的 Vercel project 預設都跑 iad1,因為 Vercel 公司在美國。
但我的 Neon DB 在新加坡。每次 SSR 跑 DB 查詢的路徑是:
訪客(台灣)→ 香港 edge → 美東 function → 跨太平洋查新加坡 DB → 跨回美東 → 香港 edge → 訪客
光是「美東 function ↔ 新加坡 DB」這一段就吃 250ms 純網路延遲,每次 query 都要付一次。
—
第一刀:function 搬到新加坡
vercel.json 加一行:
{
"regions": ["sin1"]
}
部署後再 curl X-Vercel-Id:
X-Vercel-Id: hkg1::sin1::xxx
function 搬到新加坡跟 DB 同一個 region,DB query 從 250ms 跨海降到 5-20ms 同 region 內。
實測效果:
第一個專案的 API TTFB warm 580ms 降到 200-400ms。 第二個專案首頁 SSR warm 523ms 降到 200-300ms。
但兩個都還沒到我預期的 100ms 以下。
—
卡點:cold start 還是慢
實測發現 cold start(function 第一次被叫起來)還是 600-1000ms。
兩個來源: Vercel function 本身 cold start 200-500ms(拉 image + Node 初始化) Neon Pool 是 WebSocket based,cold 要建 WS 連線多 200-500ms
第一項沒辦法改(hobby plan 限制)。第二項可以解。
第二個專案的 driver 一開始就是 neon() HTTP-based,沒這問題。第一個專案還在用舊的 Pool,要改:
// 改前
import { Pool } from '@neondatabase/serverless'
const pool = new Pool({ connectionString: url })
const { rows } = await pool.query('SELECT...', [id])
// 改後
import { neon } from '@neondatabase/serverless'
const sql = neon(url)
const rows = await sql.query('SELECT...', [id])
API route 全部換完後 cold start 額外省 200-300ms,warm 大致相同(HTTP 沒比 WS 慢)。
—
第二刀:首頁加 60 秒 edge cache
雖然 region 配對 + driver 換掉,warm 還是 200-300ms。原因是每次訪客都要打 function + DB,再快也有 baseline。
真正的 game changer 是 edge cache。
首頁的 site_settings 數據多數時候不變動。我加:
Astro.response.headers.set('Cache-Control', 'public, s-maxage=60, stale-while-revalidate=30');
這個 header 告訴 Vercel edge:「60 秒內所有訪客直接從 edge 回應,不用打 function 也不用打 DB」。
實測:cache 命中時首頁 TTFB 93ms。
副作用:業主在後台改 site_settings 後,前台要等最多 60 秒才反映。對「不太常變動」的頁面這 trade-off 可接受,對需要即時反映的頁面(後台、結帳)千萬不要加 cache。
—
雙刀流的最終數字
優化前 vs 優化後:
第一個專案 API:580ms → 200-400ms warm 第二個專案首頁:523ms → 93ms(cache 命中時)
5.6 倍速。訪客體感從「等載入」變「即時」。
—
對照表:Neon region 對應 Vercel region
ap-southeast-1(新加坡)→ sin1 ap-northeast-1(東京)→ hnd1 ap-east-1(香港)→ hkg1 us-east-1 → iad1(Vercel 預設) us-west-2 → pdx1 eu-central-1 → fra1
Supabase / PlanetScale 同樣邏輯,把 DB region 跟 Vercel region 配上就對。
—
學到什麼
Vercel function 跑美東是「給美國公司用」的預設值,不是給亞洲用戶的最佳值。多數人開發時不會注意這件事,因為本機跑很快、Vercel 預覽頁也快,等 production 流量起來才發現慢。
部署完成不是收尾,部署完成後立刻 curl X-Vercel-Id 驗 region 配對才是真收尾。每個 Vercel + serverless DB 專案都該跑這個 SOP,不分大小。