一次 cache miss 花了 539 ms,其中 527 ms 在等 origin 回應。這個拆解不是工程師事後翻 log 湊出來的,而是 Cloudflare 在示範裡自動畫出的 trace。
Cloudflare Traces 串起請求路徑
讀完這篇,你會知道分散式追蹤(distributed tracing)在回答什麼問題,Cloudflare Traces 把這套做法延伸到整條請求路徑代表什麼,以及在把它放進你的排錯流程之前,有哪些條件要先確認。文章假設你寫過 API、看過 log,但沒有用過 trace。
一個請求慢了,你得先問它去過哪些地方
假設有人回報你的 API「偶爾很慢」。請求從瀏覽器出發,在抵達你的 origin 之前,先經過 Cloudflare 這一層。Cloudflare 的說明提到,一條 trace 裡可以看到的支援項目包括安全規則、轉換(transformations)、cache 決策、路由、Worker 執行與 origin 處理。這份名單本身就是問題的輪廓:慢的那一段可能落在其中任何一站,而你手上若只有最終的回應時間,就只能從結果往回猜。
目前這個產品處於 open beta。來源寫的是「Cloudflare Traces is available in open beta from the dashboard, through the API, or with Terraform」,後面還接著說明可以匯出到 OTLP destination。open beta 的意思是功能還在補,文章後半有一份尚未支援的項目清單,本文會逐項整理。在那之前,得先把「追蹤」講清楚,因為這個詞在不同團隊嘴裡指的東西差很多。
一般說的 log,是一行一行的事件:某個時間點,某個元件說了一句話。metric 是彙總過的數字:每分鐘幾個請求,p99 是多少。兩者都有用,但在追問「這一個請求為什麼慢」時,各自都有缺口。log 散在不同系統裡,要靠時間戳或 request ID 手動拼起來;metric 把個別請求平均掉了,那個慢的請求早就消失在分母裡。
trace 補的正是這個缺口。它把同一個請求經過的每一步記成一棵樹,每一步有起訖時間,也有結果。Cloudflare 對自己產品的描述是,它「records each supported step as a span, including its timing, outcome, and relevant attributes」,也就是把每個支援的步驟記成一個 span,附上時間、結果與相關屬性。Cloudflare 內部的 trace 也是同一個形狀,來源提到那些 trace 往往一條就有上千個 span。你不用記住這個數字,它只說明一件事:請求路徑越長,手動拼湊越不可行。
trace 不會取代 log 和 metric,三者回答的問題不同。metric 告訴你整體有沒有變慢,log 保留單一元件在當下說了什麼,trace 回答的是「這一個請求的時間,沿著路徑分給了哪些步驟」。實務上常見的順序是 metric 先亮紅燈,再從慢的請求裡挑幾個去看 trace,最後回到某個元件的 log 找細節。Cloudflare Traces 補上的,是這條順序裡 Cloudflare 那一段的 trace。
Workers Tracing 之後,缺的是 Worker 以外的那一段
Cloudflare 並不是第一次做追蹤。來源寫道,「Last year, we launched automatic instrumentation for Worker invocations」,涵蓋對外的 fetch,以及對 KV、R2、D1、Durable Objects 和其他 Worker 的呼叫。換句話說,只要邏輯寫在 Worker 裡,Worker 內部發生的事已經有 span 可看,不需要自己在每個呼叫點包一層計時程式碼。
缺口在 Worker 之外。有些使用者只把 Cloudflare 放在 origin 前面,根本沒有 Worker;就算有 Worker,請求在抵達之前與離開之後經過的規則、cache 與路由,也不一定在同一條 trace 裡。後面這一點是推論:合理的推測是 Workers Tracing 的 span 以 Worker 呼叫為起點,所以 Worker 前後的步驟不在其中,來源沒有這樣說。來源明確寫出的目標是「The goal of Cloudflare Traces is to bring the same level of visibility to everyone using Cloudflare」,對象包括直接在 Cloudflare 上開發的人,也包括只把它放在 origin 前面的人。
這個差別對讀者的意義很實際。如果你的服務是一般的 Web 應用,前面掛著 Cloudflare 的 CDN 與 WAF,從來沒有部署過 Worker,那麼 Workers Tracing 對你幾乎沒有東西可看,而 Cloudflare Traces 才是第一次讓這一層出現在你的追蹤工具裡。反過來,如果你已經在用 Workers Tracing,這次的更新是把視野從 Worker 內部拉長到整條路徑。
啟用方式也值得先說。來源的描述是「Once tracing is enabled for a domain, Cloudflare generates these spans automatically.」單位是網域:對某個網域打開 tracing,支援的步驟就自動產生 span,前面引過的另一句是「There is no special instrumentation, config, or plugins required.」也就是不需要改應用程式,不需要加設定檔,也不需要裝外掛。對維運人員來說,這代表試用的成本主要是決定哪個網域、取樣率設多少,而不是排一個改程式碼的上線時程。
這種自動產生也有它的另一面。來源沒有說使用者能不能自選要記哪些步驟,合理的推測是不能,只能決定哪些網域、多少比例。來源把可記錄的範圍寫成「supported」,也就是目前支援的步驟,後面的計畫清單才會補上其他的。順帶一提費用,因為它跟這兩個產品的關係比較微妙:來源說新的計價將同時涵蓋 Cloudflare Tracing 與 Workers Tracing,生效日是 2026 年 12 月 1 日。已經在用 Workers Tracing 的人,不能把這件事當成「別人的新產品」。後面講計價時會再回來。
span、trace 與 traceparent,三個詞就夠用
先給定義,因為後面所有東西都建立在這三個詞上。trace 是一個請求從頭到尾的完整旅程。span 是旅程裡的一步,有開始時間、持續時間與結果。span 之間有父子關係:外層的步驟是父,它內部呼叫的步驟是子,所以一條 trace 會長成一棵樹。把這棵樹畫成瀑布圖,父 span 是一條長條,子 span 疊在下面,長條的長度就是耗時。
用來源的 cache 例子來說明巢狀。來源只說有「nested cache, upstream, and origin spans」,沒有寫誰包著誰;合理的推測是 cache 在外層,它底下有 upstream,upstream 底下有 origin。如果這個順序成立,每往內一層,代表「這一步為了完成自己,又去做了下一步」。所以外層 span 的耗時一定不短於它裡面的 span,兩者的差額就是外層自己花掉的時間。後面那張瀑布圖正是用這個差額在讀 Cloudflare 一側花了多少。
第三個詞 traceparent 解決的是另一個問題。請求不會永遠待在同一個系統裡:它從 A 服務走到 B 服務,B 若想讓自己的 span 掛到同一棵樹上,就得知道這個請求屬於哪條 trace、自己該掛在誰底下。唯一的辦法是 A 在請求上附一小段識別資訊,B 讀出來。W3C 把這段資訊的格式標準化成 traceparent header,所以不同廠商的工具能互相接上。
來源對 Cloudflare 這一側的描述分成兩個方向。進來的方向,Cloudflare 可以接受 W3C 的 traceparent header,讓 Cloudflare 的 span 加入既有的 trace;是否接受,由 incoming propagation policy 決定,原文是「An incoming propagation policy controls whether Cloudflare accepts that context.」出去的方向,「Cloudflare can also forward a new traceparent header to your origin」,讓 origin 與後面的服務能接著同一條 trace 往下走。下面的圖用一條線把這兩個方向畫出來,按鈕可以切換傳遞與否,看連線怎麼斷開。
按下按鈕切換 traceparent 傳遞與否 · 3 個節點 2 條連線
圖裡「關」的狀態是示意,不是 Cloudflare 的某個實際設定畫面。它想說的是 traceparent 在做的事:不傳,每個系統仍然會記自己的 span,只是這些 span 之間少了一條可以互相指認的線。來源給出的相關設定只有兩個,一是進來方向的 incoming propagation policy,二是出去方向轉發新的 traceparent;進來的 policy 擋掉之後 Cloudflare 的 span 具體會怎麼歸屬,來源沒有展開。
要看到完整的一條線,還需要最後一個條件。來源寫的是「you can send both Cloudflare and application spans to the same OpenTelemetry-compatible backend」,也就是讓 Cloudflare 的 span 與你的應用程式 span 進同一個後端。匯出的設定方式是「Configure an account-level destination, then choose which domains send traces to it.」先在帳號層級設定一個 destination,再指定哪些網域把 trace 送過去。這裡用的協定是 OTLP,也就是 OpenTelemetry 的傳輸協定,所以任何能收 OTLP 的觀測平台原則上都能當後端。
539 毫秒裡的 527:把一次 cache miss 攤開
來源貼了一張實際的 trace 截圖,文字描述是這樣的:「Here, you can see there was a cache miss that went to origin and spent 527ms of the 539ms getting a response.」整個請求 539 毫秒,其中 527 毫秒花在向 origin 取回回應。兩數相除約為 97.8%,這個比例是本文自己算的。下面把這兩個數字畫成一張瀑布圖,只有長度是來源給的資料,長條在列內的起點位置是示意。
這張圖的讀法很直接。要降這個請求的延遲,Cloudflare 這一層的規則與路由幾乎沒有可動的空間,因為差額只有 12 毫秒;真正的時間在 origin。這種結論過去需要在 origin 加計時,或者比對兩邊的 log 才能得到,現在在 dashboard 的 trace 裡展開巢狀的 cache、upstream 與 origin span 就看得見。來源的說法是「You can expand nested cache, upstream, and origin spans to see where the request spent its time.」
要注意這張 trace 回答了什麼、沒回答什麼。它指出時間花在 origin 這一段,沒有說 origin 裡面慢在哪:是資料庫查詢、後端的某個外部呼叫,還是單純排隊。要往下鑽,就是前面 traceparent 的用武之地。Cloudflare 把新的 traceparent 轉發給 origin,若 origin 的應用程式有接 OpenTelemetry,它的 span 會掛在 Cloudflare 的 origin span 底下,兩邊的瀑布圖拼成一張。沒接的話,這條 trace 就停在 origin 的門口。
「新的」traceparent 這個詞也有講究。來源寫的是 Cloudflare 轉發一個 new traceparent,沒有寫成原封不動地轉傳進來的那一個。合理的推測是,Cloudflare 把自己的 span 插進上下游之間,所以對 origin 來說,它的父節點變成 Cloudflare 的某個 span,而不是最初的呼叫端。這樣 origin 的 span 才會掛在 Cloudflare 的 origin span 之下,與瀑布圖的巢狀結構一致;來源沒有逐字寫出這個細節,需要確認的話,用一個測試請求看 origin 收到的 header 就知道。
除了「慢在哪」,來源還列了三個 Cloudflare 這一層自己能回答的問題,加上剛才那個共四個。下表把它們對應到各自要看的 span,欄位內容照來源描述整理,空格不補推測。
| 你想知道的事 | 要看的 span | span 裡有什麼 |
|---|---|---|
| 請求為什麼被擋或被挑戰 | 該步驟的 span events | 負責的那條規則 |
| Transform Rule 有沒有改寫 URL | http_request_transform | 每一項改動 |
| 哪個 Page Rule、Snippet 或 Worker 處理了請求 | workers_routing | 路由有沒有命中、路由類型、命中的 route pattern |
| 回應有沒有 cache,時間花在哪 | 巢狀的 cache、upstream、origin span | 請求在各段花掉的時間 |
這四列裡有三列在處理「為什麼是這個結果」,只有一列在處理時間。這跟傳統 APM 的印象不太一樣:Cloudflare 的規則層是設定驅動的,一個請求被擋、被改寫、被導向哪個 Worker,常常是因為某條規則命中了,不是程式碼跑慢了。把規則的命中寫進 span,等於把「是哪條規則做的」也變成可查詢的資料。來源對被擋的情形說得很具體:可以透過 span events 找到負責擋下或挑戰的那條規則。
來源還提到一個使用方式:Cloudflare Observability MCP server。照原文,「With the Cloudflare Observability MCP server, your agent can leverage our SQL API to query your traces」,讓你的 coding agent 用 SQL API 查 trace。文章描述的流程是讓 agent 找出對的請求,並比較失敗與成功的 trace,找出兩者 span 開始分歧的地方。這比較像一個工作流程的示範,不是功能保證;agent 查得準不準,取決於你給它的 trace 品質與查詢,來源沒有給任何準確度的資料。
取樣與費用:開著,不等於全收
trace 的資料量和請求量成正比,所以所有追蹤系統都要回答同一個問題:每個請求都記嗎?通常不會。來源提供的是兩層設計。第一層是基準取樣率,每個網域設一個;來源舉的例子是「You might trace 1% of requests during normal operation」,正常時段追 1% 的請求。第二層是 Trace Rules,用來覆寫基準:「Set a baseline sampling rate, then use Trace Rules to override it for matching traffic.」
Trace Rules 用的是 Cloudflare Rules 語言,來源說可以針對路徑、方法、header、IP 位址與地理位置下條件。來源給的兩個覆寫範例,一是對某位客戶的 hostname、來源 IP 或識別用的 request header,追蹤 100% 的流量;二是對帶著臨時除錯 header 的請求,追蹤 100%。兩個例子都是「平常抽樣、特定流量全收」,這樣的設計讓你在出事時不用先把整個網域調到 100%。
低取樣率有一個直接的代價,用算術就能看出來。假設某個問題每天出現 200 次,基準取樣率 1% 時,平均每天只有 2 次會被記下來;問題如果集中在某個客戶或某個路徑,你可以替它寫一條規則提高比例,如果只是零星出現,就得調高基準取樣率,或接受抓不到。這個例子的數字是本文假設的,只用來說明取樣率和「抓到問題的機會」之間的關係。
下面的圖用一個算術模型讓這件事有手感。這個模型是本文自己建的,不是來源的資料:假設每個請求獨立抽樣,規則命中的流量全部追蹤,其餘流量按基準取樣率。拖動基準取樣率與規則命中的流量占比,看整體被追蹤的請求占多少。
拖動兩個滑桿,看整體取樣比例如何變化 · 2 個參數
整體約 5.95% 的請求被追蹤,每 10,000 個請求約 595 個。
算術模型,非來源資料:整體比例 = 命中占比 + (1 − 命中占比) × 基準取樣率,命中的流量以 100% 追蹤
基準取樣 1%、規則命中 5% 流量時,約 5.95% 的請求被追蹤,是只靠基準的近六倍。
拖一下就會看到,在基準 1% 的設定下,只要有 5% 的流量命中規則,整體追蹤比例就從 1% 變成約 5.95%;命中占比拉到 20%,整體比例已經約 20.8%。曲線是直線,但它說明了一件在設定時容易忽略的事:Trace Rules 的命中條件寫得越寬,費用越由規則決定,基準取樣率反而退到次要位置。把「臨時除錯 header」做成規則時,記得它命中的不只是你自己的請求,任何帶著那個 header 的請求都會被全量追蹤。
接著是費用。來源的說法是新的計價將於 2026 年 12 月 1 日生效,適用於 Cloudflare Tracing 與 Workers Tracing,並說明計價依據是「how much observability data you ingest and how long you retain it」,也就是你寫入多少觀測資料,以及保存多久,不是 span 或事件的個數。下面的卡片把來源表格裡兩種方案的條件並排。
FREE
- 含 ingestion
- 0.5 GB,每日
- 保存期限
- 7 天
- 超額
- 不提供
PAID 與 ENTERPRISE
- 含 ingestion
- 50 GB
- 含 storage
- 10 GB-month,每個 billing cycle
- 保存期限
- 最長 365 天列為 open beta 之後的計畫
Free 方案的列在來源裡是「Free | 0.5 GB of ingestion per day | 7 Days | Not available」,最後一欄對應超額。合理的推測是,每天 0.5 GB 的額度與 7 天的保存期限,定位上就是讓人在 open beta 階段拿一個網域試跑;來源沒有解釋這組數字的設計理由。付費與 Enterprise 的表列是 50 GB 的 ingestion,以及每個 billing cycle 10 GB-month 的 storage。
真正難估的是 span 與容量的換算。來源的計價以資料量為單位,卻沒有給出每條 trace 或每個 span 大概占多少位元組,所以光靠請求量與取樣率,無法預先算出自己會落在 0.5 GB 之內還是之外。合理的做法是用 open beta 階段實測:挑一個網域,設定一個保守的基準取樣率,讓它跑幾天,再用實際的 ingestion 量回推。這條路在 12 月 1 日之前走完,價格出來時你已經有自己的數字。
把它放進排錯流程之前,先核對這幾件事
前面幾節講的是它能做什麼,這一節反過來,列出放進排錯流程之前值得核對的限制。其中多數來自來源自己列的計畫清單,少數是把來源的描述推到你的環境時會遇到的問題,後者會明說是推論。
先看範圍。來源有一份接在「Following the open beta, we plan to launch」之後的計畫清單,反過來讀,就是現在還沒有的東西。排在最前面的是更廣的自動 instrumentation:HTTP 路徑上要補 DDoS 規則與 Access 的 span,Workers 路徑上要補 Workflows、Queues 與 Pipelines。如果你出問題的環節剛好是其中之一,目前的 trace 在那一段是空的,而空的位置在瀑布圖上看起來就像那一步根本沒花時間。
傳遞的信任邊界是另一件事。清單裡有「Authenticated context propagation」,目的是讓受信任的呼叫端接續既有的 trace。這項還沒上線,現階段的機制是前面提到的 incoming propagation policy,來源描述它控制 Cloudflare 是否接受進來的 context。從這兩句話可以拼出一個設計上的疑問:如果接受與否是整體的開關,而你的網域對外公開,那麼任何人都能送 traceparent,決定要不要接受就不只是方便性的選擇。這是本文的推論,來源沒有談到濫用的情形。
採樣的彈性也有缺口。清單裡的 ad hoc tracing 是「Capture a specific request on demand without changing the baseline sampling rate」,意思是要抓某個特定請求時,不必動基準取樣率。沒有這項的時候,你只能靠 Trace Rules 搭配臨時 header 達到類似效果,而前面的圖已經示範過,規則設得太寬,整體比例會一路衝高。
再來是你自己的程式碼。來源提到 Workers 裡的 OpenTelemetry API 支援還在規劃,寫的是「Continue building out our OpenTelemetry APIs」,目的是讓你替既有的 span 加屬性,或讀取 trace context。反過來說,現在你想把使用者 ID 或租戶這類業務資訊寫進 Cloudflare 產生的 span,還沒有這條路;要帶自己的屬性,得靠應用層另外送出的 span。
保存期限要單獨算。Free 方案保存 7 天,更長的保存期限(最長 365 天)被來源列在 open beta 之後。需要拿三個月前的 trace 去對帳的團隊,現階段應該把 OTLP 匯出當成正式管道:把 trace 送進你自己的後端,保存多久由那個後端決定。這也符合來源對匯出的定位,也就是讓資料能在不同工具之間移動。
最後是時效。這份來源在 2026 年 10 月發布,計價在 12 月 1 日生效,open beta 的項目預期還會變動。本文關於額度與價格的敘述,以截至 2026 年 10 月 9 日讀到的來源版本為準,真要上線前請回到 Cloudflare 文件核對最新數字。同日的 roundup 有這則新聞的簡短版本。
如果只想花一個下午試,建議的順序是:挑一個流量不大的網域,啟用 tracing;基準取樣率設在來源範例的 1% 附近;先不寫 Trace Rules;把 OTLP destination 指到你現有的觀測後端;然後找一個已知偏慢的路徑,看 trace 裡的 origin span 占多少。如果像來源範例那樣,絕大部分時間落在 origin,下一步就是讓 origin 接上 OpenTelemetry,讓兩邊的 span 接起來。
Mental model:trace 是一個請求的旅程紀錄,Cloudflare Traces 讓這份紀錄從 Worker 往前後延伸到規則、cache、路由和 origin,而 traceparent 與 OTLP 決定這份紀錄能不能和你自己的 span 接成同一張圖。