跳到內容

成本工程:算得出你的帳單

查證日期
驗證環境wrangler@4.118.0·compatibility_date: 2026-07-24
對應範例examples/ch42-cost

⚠️ 價格會變。 本章所有數字都標了單位與來源頁,目的是讓你自己重算,不是背下來。範例的成本模型把費率集中在一個 PRICES 物件裡,改那裡就好。


42.1 先講一件比價格表更重要的事

Section titled “42.1 先講一件比價格表更重要的事”

你不需要猜。

D1 每一次查詢都會回報 meta.rows_read,而那個數字就是帳單上的那一行。KV、R2、Queues 的計費單位也都能在本機數出來。

範例的 /cost/d1 建了一張 5,000 列的表,然後把同樣四個查詢在「沒有 index」與「有 index」兩種情況下各跑一次:

查詢回傳列數沒有 index 的 rows_read有 index 的 rows_read
WHERE slug = ?15,0002
WHERE tenant_id = ?1005,000101
SELECT COUNT(*)15,0005,000(index 不幫忙)
ORDER BY clicks DESC LIMIT 101010,00010

三件事值得停下來看:

  1. WHERE slug = ? 差 2,500 倍。 一個 index。
  2. 🔴 ORDER BY … LIMIT 10 在沒有 index 時讀了 10,000 列 —— 是整張表的兩倍。 排序要先掃過整張表,再走一次 sorter。「我只取前十筆,應該很便宜」是完全錯的直覺。
  3. COUNT(*) 有沒有 index 都是 5,000。 全表計數就是全表掃描,加 index 不會變便宜。要便宜就得自己維護計數(第 15 章那個 DO,或一張 summary 表)。

官方文件也是這樣寫的:

“Rows read measure how many rows a query reads (scans), regardless of the size of each row. For example, if you have a table with 5000 rows and run a SELECT * FROM table as a full table scan, this would count as 5,000 rows read.”

“A query that filters on an unindexed column may return fewer rows to your Worker, but is still required to read (scan) more rows to determine which subset to return.”

同一個範例量到的:

寫入rows_written
UPDATE links SET clicks = clicks + 1 WHERE id = ?clicks 有 index)2
UPDATE links SET url = ? WHERE id = ?url 沒有 index)1

官方原文:

“Indexes will add an additional written row when writes include the indexed column, as there are two rows written: one to the table itself, and one to the index.”

所以 index 不是免費的。 三個 index 全部涵蓋熱寫入欄位的話,每次寫入變成四筆。加上 rows written 比 rows read 貴 1000 倍($1.00/M vs $0.001/M),這個取捨要算。


單位是重點,價格會過時。

產品計費單位FreePaid 含量超出
Workers 請求每次 invocation100,000/天10M/月$0.30/M
Workers CPUCPU ms(不是牆鐘時間)每次 10 ms 上限30M CPU ms/月$0.02/M
KV 讀每個 key(bulk 也一樣)100,000/天10M/月$0.50/M
KV 寫 / 刪 / list每個 key / 每次 list1,000/天1M/月$5.00/M
KV 儲存GB-月1 GB1 GB$0.50/GB
D1 rows read掃過的列數5M/天25B/月$0.001/M
D1 rows written列(含 index 那一筆)100,000/天50M/月$1.00/M
D1 儲存GB-月(含 index)5 GB5 GB$0.75/GB
R2 Class Aput / list / copy / multipart1M/月$4.50/M
R2 Class Bget / head10M/月$0.36/M
R2 儲存GB-月10 GB$0.015/GB
R2 egress免費免費免費
DO 請求HTTP / RPC / WS 訊息 / alarm100,000/天1M/月$0.15/M
DO durationGB-s(牆鐘時間 × 128 MB)13,000 GB-s/天400,000 GB-s/月$12.50/M GB-s
DO SQLite 儲存rows read / written / GB5M 讀、100K 寫、5 GB / 天同 D1同 D1
Queues每 64 KB 的寫/讀/刪各一次10,000/天1M/月$0.40/M
Workers Logs每個 log event200,000/天20M/月$0.60/M
Workers AINeurons10,000/天10,000/天$0.011 / 1,000 Neurons
Browser Runbrowser hours + 併發數10 分鐘/天、3 併發10 小時/月、10 併發$0.09/小時、$2.00/併發
ContainersvCPU-s(只算 active)+ GiB-s + GB-s(算 provisioned(要 Paid)375 vCPU-min、25 GiB-h、200 GB-h$0.000020/vCPU-s 等
Vectorize維度數(查詢的與儲存的)30M 查詢、5M 儲存 /月50M 查詢、10M 儲存$0.01/M 查詢維度
Hyperdrive查詢數(兩個方案都免費100,000/天上限無上限
Imagesunique transformation / stored / delivered5,000 transform/月同左$0.50/1,000 等
Analytics Enginedata point 寫入 / SQL 讀查詢100,000 寫、10,000 讀 /天10M 寫、1M 讀 /月$0.25/M、$1.00/M
Workflows請求 + CPU + 儲存 + steps3,000 steps/天500,000 steps/月$0.80 / 100,000 steps

方案最低消費:官方原文 —— “The Workers Paid plan includes Workers, Pages Functions, Workers KV, Hyperdrive, and Durable Objects usage for a minimum charge of $5 USD per month for an account.”

⚠️ 注意那句話點名的產品:R2、D1、Queues、Images、Workers AI、Containers 不在這 $5 裡面。

  • 🔴 Analytics Engine 的價目是「還沒開始收」:頁面上寫著 “Currently, you will not be billed for your use of Workers Analytics Engine”。第 22 章那個「隨便寫」的建議暫時還成立,但別當永久。
  • 🔴 Workflows 的 steps 與 storage 計費「不早於 2026-08-10」開始(changelog 原文)。寫作當下是九天後。 第 21 章那些 step 數量的設計,很快就會有價格。
  • ⚠️ Browser Rendering 與 Browser Run 兩個定價頁都活著、數字相同,但沒有任何一頁說後者取代前者。當成兩個並存的介面看待。
  • Workers 每次請求的最低計費 CPU 時間:pricing 頁與 limits 頁都沒有寫。不要假設有 1 ms 下限。
  • D1 每次查詢的最低計費列數:同樣沒有文件。

42.3 🔴 KV:miss 也是一次計費讀取

Section titled “42.3 🔴 KV:miss 也是一次計費讀取”

官方原文:

“All operations incur charges, including fetches for non-existent keys that return a null (Workers API) or HTTP 404 (REST API).”

範例的 /cost/kv 三個呼叫全部是計費讀取:

{ "hit": "v", "miss": null, "missWithMetadata": { "value": null, "metadata": null, "cacheStatus": null } }

後果:cache miss 的路徑成本是 KV 讀 + D1 查詢,不是「只有 D1 查詢」。第 8 章那個 cache-aside 的算式要把 miss 那一邊的 KV 讀也算進去。

還有一條容易誤解的:

“Workers KV pricing for read, write and delete operations is on a per-key basis. Bulk read operations are billed by the amount of keys read in a bulk read operation.”

bulk API 省的是延遲,不是錢。 一次寫 5,000 個 key 和分 5,000 次寫,價格完全一樣。

而且 KV 的寫比讀貴 10 倍($5.00/M vs $0.50/M)。任何「每次請求都寫一下 KV」的設計(存 session、記最後存取時間)在流量上來之後會是帳單的主角。


42.4 🔴 R2:list() 是 Class A,head() 不免費

Section titled “42.4 🔴 R2:list() 是 Class A,head() 不免費”
操作類別價格
put / list / copy / multipart 的每個 partClass A$4.50/M
get / headClass B$0.36/M
delete免費

list()get() 貴 12.5 倍。list() 放在熱路徑上(例如「列出這個使用者的檔案」每次載入頁面都跑一次)是本系列列的五大燒錢模式的第一名。

head() 是 Class B,不是免費。head() 做「檔案存不存在」的檢查,每次都要付錢,而且miss 也要付(實測 head("a/nope.txt")null,但那是一次 Class B 操作)。

delete 免費,所以清理舊資料沒有成本壓力 —— 但別忘了 lifecycle rule 的 storage class transition 是 Class A

egress 免費是 R2 相對 S3 最大的優勢,官方原文:

“Egressing directly from R2, including via the Workers API, S3 API, and r2.dev domains does not incur data transfer (egress) charges and is free.”

未授權的請求(HTTP 401)不計費。


42.5 Queues:一則訊息大約三次 operation

Section titled “42.5 Queues:一則訊息大約三次 operation”

官方原文,兩句都很關鍵:

“An operation is counted for each 64 KB of data that is written, read, or deleted.”

“Operations are per message, not per batch. A batch of 10 messages (the default batch size), if processed, would incur 10x write, 10x read, and 10x delete operations.”

所以:

  • 一則 ≤ 64 KB 的訊息走完正常流程 = 3 次 operation(寫 + 讀 + 刪)。
  • 65 KB 的訊息 = 每個動作 2 次,總共 6 次。
  • 每次重試多一次讀。 第 19 章那個「無上限的 retry 迴圈」在這裡直接變成錢。
  • 進 DLQ 的訊息額外算寫入。
  • 過期的訊息算一次寫 + 一次刪。
  • batch 不省錢。 batch 省的是 Worker invocation 與 CPU,不是 queue operation。

訊息要小。 把 payload 塞進 R2/KV 再傳一個指標,比塞進訊息本體便宜 —— 只要總大小會跨過 64 KB 的界線。


42.6 Durable Object:hibernation 是省錢開關

Section titled “42.6 Durable Object:hibernation 是省錢開關”

DO 的 duration 是牆鐘時間,不是 CPU 時間,而且不管你實際用多少記憶體,一律以 128 MB 計

“Duration is billed in wall-clock time as long as the Object is active and not eligible for hibernation.”

所以 GB-s = 活著的秒數 × (128 MB / 1 GB) = 秒數 × 0.125

關鍵的那一句:

“Durable Objects that are idle and eligible for hibernation are not billed for duration, even before the runtime has hibernated them.”

注意是「eligible for」,不是「已經 hibernate」。 只要你用的是 hibernation API(第 16 章),閒置的連線立刻停止計費,不用等 runtime 真的把它睡著。

反過來說:一個沒用 hibernation API 的 WebSocket 連線,即使完全沒有訊息,也是 24 小時 × 0.125 GB-s = 10,800 GB-s/天。一個連線。這就是第 16 章那個 hibernation 為什麼不是可選的。

另外兩條:

  • state.setWebSocketAutoResponse() 處理掉的訊息不計牆鐘時間,也不收費。 ping/pong 心跳走這條路就是免費的。
  • 進來的 WebSocket 訊息在計算「請求數」時套用 20:1 的比例。

#模式為什麼貴怎麼發現
1熱路徑上的 R2.list()Class A,$4.50/M,是 get() 的 12.5 倍在 R2 metrics 看 Class A 曲線是否跟著流量走
2缺 index 的 D1 查詢實測 2,500 倍(5,000 vs 2);ORDER BY … LIMIT 甚至讀兩倍表大小meta.rows_read,本機就看得到
3沒用 hibernation 的 WebSocket一個閒置連線 10,800 GB-s/天DO metrics 的 GB-s 與連線數不成比例
4忘了 disconnect 的 browser session按 browser hours 計,而且 Sessions API 同時算併發Browser Run 的 duration 與請求數不成比例
5無上限的 retry 迴圈每次重試 = 一次 queue 讀 + 一次 Worker invocation + CPUqueue operation 數 ÷ 訊息數 明顯大於 3

第 2 個是最貴也最容易發現的 —— 下一節有數字。


範例的 scripts/cost-model.mjs 把整個系列的設計(KV cache-aside + D1 + Queues + 每個 slug 一個 DO + 結構化 log)算成錢。假設:cache 命中率 90%、每 200 次點擊一次建立、queue consumer 每 10 則聚合成一次 DO 呼叫。

=== 10,000 clicks / month ===
usage $0.00 + $5.00 plan minimum = $5.00/month
=== 1,000,000 clicks / month ===
queues operations $0.80
usage $0.80 + $5.00 plan minimum = $5.80/month
=== 100,000,000 clicks / month ===
workers requests $27.60
workers CPU $2.06
kv reads $45.00
kv writes $47.50
queues operations $119.60
DO requests $1.35
workers logs $109.20
usage $352.31 + $5.00 plan minimum = $357.31/month

三個觀察,每一個都反直覺:

  1. 一百萬次點擊/月幾乎是免費的。 $5.80。免費額度覆蓋了絕大多數專案 —— 不要在這個量級做成本優化,那是浪費時間。
  2. 🔴 一億次點擊時,最大的兩項是 Queues($119.60)與 Logs($109.20),加起來比 Workers 請求 + CPU + KV 全部還多。這兩個都是「你不會想到要算」的東西:queue 的 3× 放大,和「每次 invocation 一筆 log + 每次點擊一筆結構化 log」。
    • 對策:log 用 head_sampling_rate 抽樣(第 39 章)—— 但注意 log 抽樣會讓 debug 變難,這是真正的取捨。queue 那邊則是考慮在 Worker 裡先聚合再送。
  3. D1 完全不在帳單上($0.00)。25 B rows read/月的含量太大了 —— 只要你有 index。

同樣一億次點擊,同樣的設計,只是 slug 上少了一個 index。LinkForge 在這個量級大約有 50 萬個短網址:

=== the same 100M-click month with ONE missing index ===
d1 rows read 5.00e+12 -> $4,975/month
(the indexed version above: $0.00)

$4,975 vs $0。一個 index。而且是整份帳單其他所有項目加起來的 14 倍。

這就是為什麼本章從 meta.rows_read 開始講,而不是從價格表開始。 你在本機跑一次 /cost/d1 就能看到 5,000 vs 2;你不需要等帳單來告訴你。


成本不是唯一理由,但它是最容易量化的那個。三個判準:

1. CPU 密集的工作。 Workers 按 CPU ms 計費,$0.02/M。一個要跑 500 ms CPU 的請求,一百萬次就是 500M CPU ms = $10(扣掉含量)。同樣的工作在一台固定的機器上可能是幾塊錢的固定成本。轉折點大約在「單次請求 CPU > 100 ms 且流量穩定」。

2. 需要精確計數。 第 41 章講過 rate limit binding 是 per-colo 最終一致的,DO 才是全域強一致 —— 但 DO 把請求集中到一個機房,延遲的優勢就沒了。如果你的核心邏輯需要全域強一致,edge 的價值本來就打折。

3. 資料重力。 Hyperdrive(第 28 章)讓你連既有資料庫,但每次查詢還是要跨越到那個資料庫所在的地方。如果 90% 的請求都要打中心化資料庫,那你只是把延遲挪了位置,沒有消掉。

反過來,留在 edge 幾乎一定划算的情況:讀多寫少、可快取、地理分散的使用者、流量尖峰劇烈(不用為峰值買機器)、R2 egress 免費能省下大筆頻寬費。


#結論影響
1meta.rows_read 在本機就看得到,那個數字就是帳單不需要猜,也不需要等帳單
2🔴 實測 5,000 列的表:WHERE slug = ? 沒 index 5,000 列,有 index 2 列2,500 倍
3🔴 ORDER BY clicks DESC LIMIT 10 沒 index 讀 10,000 列 —— 兩倍表大小「只取前十筆」的直覺是錯的
4SELECT COUNT(*) 有無 index 都是 5,000全表計數要自己維護計數器
5🔴 實測寫入放大:更新有 index 的欄位 rows_written = 2,沒 index 的 = 1index 不免費;rows written 比 read 貴 1000 倍
6🔴 KV 的 miss 也是計費讀取(官方明文,含 null 與 404)cache miss 成本 = KV 讀 + D1 查詢
7KV 計費以 key 為單位,bulk API 不省錢bulk 省的是延遲
8KV 寫比讀貴 10 倍($5.00/M vs $0.50/M)每請求寫 KV 的設計要重想
9🔴 R2 list() 是 Class A,比 get() 貴 12.5 倍熱路徑上的 list 是第一名燒錢模式
10🔴 head() 是 Class B,不免費,miss 也計費用 head 做存在性檢查要算成本
11R2 delete 免費;但 lifecycle 的 storage class transition 是 Class A
12R2 egress 完全免費,401 不計費相對 S3 最大的優勢
13Queues 每 64 KB 算一次 operation;一則正常訊息 = 3 次65 KB 的訊息直接翻倍成 6 次
14batch 不省 queue operation(10 則 = 10 寫 + 10 讀 + 10 刪)batch 省的是 invocation 與 CPU
15每次重試多一次讀;DLQ 多一次寫;過期多一寫一刪第 19 章的 retry 上限是成本問題
16DO duration 是牆鐘時間 × 固定 128 MB和實際記憶體用量無關
17🔴 「eligible for hibernation」就停止計費,不用等真的睡著只要用 hibernation API 就生效
18一個沒用 hibernation 的閒置 WebSocket ≈ 10,800 GB-s/天第 16 章的 hibernation 不是可選的
19setWebSocketAutoResponse() 處理的訊息不計時也不收費心跳免費
20進來的 WebSocket 訊息在請求計費上套 20:1
21Workers 計 CPU ms 不計牆鐘;等待 I/O 不算duration 明文免費
22⚠️ 每次請求的最低計費 CPU「沒有文件」不要假設有 1 ms 下限
23Containers:CPU 只算 active,記憶體與磁碟算 provisioned選錯 instance type 是固定成本
24Browser Run 的 Sessions API 同時計 duration 與併發;Quick Actions 只計 duration
25Vectorize 計的是維度數,不是向量數;不計 CPU / 記憶體 / index 數
26Hyperdrive 兩個方案都免費(Free 每天 10 萬次查詢上限)快取命中的查詢也算次數
27🔴 Analytics Engine「目前不收費」(官方原文)第 22 章的建議暫時成立
28🔴 Workflows 的 steps 與 storage 計費「不早於 2026-08-10」開始寫作當下是九天後
29$5 最低消費只涵蓋 Workers / Pages Functions / KV / Hyperdrive / DOR2、D1、Queues、AI、Containers 不在內
30🔴 模型結果:1M 點擊/月 = $5.80;100M 點擊/月 = $357.31百萬級不值得做成本優化
31🔴 一億次點擊時最大兩項是 Queues $119.60 與 Logs $109.20兩個都是「不會想到要算」的
32🔴 同樣一億次點擊,少一個 index = $4,975/月,是其餘全部的 14 倍一個 index

  1. /cost/d1,把你自己專案裡最熱的三個查詢貼進去量 rows_read。任何一個超過回傳列數十倍的,就是一個缺失的 index。
  2. ORDER BY … LIMIT 10 的 index 拿掉再量一次,親眼看到「兩倍表大小」。
  3. 算一下你的 KV 每月寫入次數 × $5/M。如果那個數字讓你不舒服,找出哪一條路徑在每次請求都寫 KV。
  4. 在你的 R2 metrics 上把 Class A 與 Class B 的曲線疊起來。如果 Class A 跟著流量走,你的熱路徑上有 list()
  5. scripts/cost-model.mjs --clicks <你的量級> 算你自己的規模,然後把 PRICES 對著官方頁面重新核對一遍 —— 這一步比算出來的數字更重要。
  6. 把模型裡的 log 事件數砍一半(模擬 head_sampling_rate: 0.5),看省多少,再問自己那半份 log 沒有的時候你要怎麼查問題。

下一章:第 43 章 LinkForge 總回顧與 production checklist —— 全系列收尾。