524
Cloudflare 自己的代碼,用在一個一路進得去、然後就沒聲音的請求上:連線成功了、來源機收到了,而 125 秒之後還是沒有任何 HTTP 回應可以送回來。
同樣三個數字,你站在請求的哪一邊,它就是不同的問題。直接讀你自己那一塊。
為什麼會看到它
請求卡兩分鐘以上,然後變成 Cloudflare 的 HTML 錯誤頁。兩分鐘比任何使用者願意等的時間都長,也比好幾家行動網路維持閒置連線的時間長,所以實務上這次失敗常常是以 abort 或網路錯誤的形式到你手上,根本不是一個狀態碼——於是調查方向被帶去你自己的程式碼,而不是來源機。它打中的是某一個端點,而且永遠是慢的那一個:匯出、報表、批次匯入、沒有邊界的搜尋,或是一個同步處理的上傳。
該怎麼做
用 `AbortController` 加一個計時器,給每個請求一個你自己選的、遠低於 125 秒的期限,讓使用者看到的是你的訊息,不是一頁基礎設施供應商沒有樣式的頁面——也讓耗時被記下來。接著把任何真的會跑很久的東西改成另一種形狀,這也是 Cloudflare 自己的建議:端點立刻回一個 job 識別碼,再去輪詢結果;因為不管你怎麼調逾時,都不可能讓一個兩分鐘的請求活過你和伺服器之間每一台代理、每一台負載平衡器和每一個行動網路。絕對不要自動重試 524。來源機非常可能在 Cloudflare 走人之後幾秒就把事情做完了,所以一次被重試的匯入會跑兩遍;如果這個操作非得可重試不可,就送一個冪等鍵,讓伺服器自己認出這是重複的。
為什麼會看到它
你的來源機接受了連線、也讀到了請求,這代表整個連線性問題的類別已經被排除掉了——連接埠、綁定位址、防火牆、Cloudflare 的 IP 範圍全都沒事,不然你拿到的會是 521、522 或 523。這個請求要嘛還在跑,要嘛從來沒開始。那正是 Cloudflare 指名的兩個原因:長時間執行的程序,以及過載的伺服器——而它們需要相反的修法:一個是慢查詢、鎖,或是一個對著持續變大的資料表沒有邊界的迴圈;另一個是工作行程池飽和,請求排在別人後面,應用程式根本還沒碰到它。
該怎麼做
你自己的存取紀錄會告訴你是哪一種,而那是第一份該讀的東西。如果那個請求有出現、而且耗時超過 125 秒,代表來源機是在 Cloudflare 放棄之後才做完的——這件事真的慢,紀錄裡有真實的耗時,問題在那個請求裡面。如果那個請求從頭到尾沒出現,代表沒有東西慢:它坐在應用程式前面的佇列裡,那是容量問題,你去對那個端點做效能分析是什麼都找不到的。從這裡開始,Cloudflare 文件裡的選項就是你實際上有的選項。把長時間的工作從請求路徑上移開,改成輪詢結果。任何非得超過 125 秒的東西,放到一個 DNS-only 的子網域後面,因為這個逾時只存在於被代理的流量上。用 Origin Analytics 盯著逼近門檻的回應時間,不要等它越過去。調大逾時只有 Enterprise 方案的區域做得到,透過 Cache Rules 或區域設定 API,而且最多 6,000 秒——所以對大多數人來說那個數字是固定的,該改的是設計。你自己的應用程式逾時也要設在 125 秒以下,這樣請求會被一個「能記下原因」的東西殺掉。
為什麼會看到它
網站是活著的,而且它收到了你要的東西——只是它太久沒有回答,於是擋在它前面的服務不等了,改把這一頁給你看。通常是某個很重的東西:一份大型匯出、一個大檔案上傳、一次跨大量資料的搜尋,或者一個比平常更忙的網站。同一個網站上其他東西往往都好好的,這就是為什麼從外面看,這次失敗顯得毫無道理。
該怎麼做
如果你要的東西很大,就要少一點:縮短日期範圍、換小一點的檔案、一次少幾筆。光是這個改變,解掉的 524 比你重新整理再多次都多,因為逾時是在講時間長度,而時間長度跟著大小走。重做上傳或送出之前,先確認它到底過了沒——逾時把答案藏起來了,但那件事非常可能在那之後一下子就完成了,所以檔案可能已經在那裡,再做一次會多出一份重複的。先去看對應的清單、資料夾或訂單紀錄。而在網站正忙的時候,馬上重新整理是最不該做的事,因為每一次重整都是在叫那台已經滿載的伺服器把同一件慢事再做一遍。
對著出錯的那個網址跑一次。它只印狀態碼、不印錯誤頁,所以你看到的是伺服器真正說了什麼,而不是瀏覽器畫出來的東西。
curl -sS -o /dev/null -D - --max-time 300 -w '\n%{http_code} connect=%{time_connect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' https://example.com/slow-report`--max-time 300` 是 curl 對整個操作的上限,而且它必須明顯高於 125 秒,否則會是 curl 先放棄,那你量到的是自己的耐心、不是 Cloudflare 的。524 在那份輸出裡的形狀非常好認:`connect` 只有零點幾秒,`ttfb` 和 `total` 都在 125 秒附近,而狀態碼是 524——一次很快的連線,接著一段很長的沉默,而這正是它跟 522 的分野,522 是連線本身從來沒完成。接著用 `--resolve example.com:443:203.0.113.10` 指向你的來源機位址,把邊緣節點從路徑上拿掉,再跑一次同樣的請求。如果來源機在 200 秒之後回答了,那就是這件事真的那麼慢,524 是一份準確的報告;而 curl 印出來的那個數字,就是這個請求真正需要的時間,也是你該拿來設計的數字。如果繞過邊緣之後來源機很快就回答,那多出來的時間是加在應用程式前面的——某個 Worker、某條 WAF 規則,或是連往來源機的 HTTP/2——那來源機就不是該看的地方。跑指令的同時盯著來源機自己的存取紀錄:一個出現在那裡、耗時超過 125 秒的請求,就證明了那件事是在 Cloudflare 不再聽之後才完成的,而這正是 524 之後重試寫入不安全的原因。而一個在那份紀錄裡從頭到尾沒出現的請求,代表它被排隊、從來沒開始,那個端點並不慢——是伺服器滿了。
524 不是 IETF 的狀態碼——登記的 5xx 範圍到 511 為止,520 到 526 屬於 Cloudflare,只有 Cloudflare 的文件在定義,而且只會出現在真的有被代理的流量上。Cloudflare 的定義精確得不尋常,值得讀兩遍:錯誤 524 表示 Cloudflare 成功連上了來源網頁伺服器,但來源機在預設的 125 秒之前沒有提供 HTTP 回應。前半句就是診斷。連線成功代表來源機有在監聽、監聽的是 Cloudflare 會代理的連接埠,而且防火牆有放 Cloudflare 進來——521、522、523 會提出的每一個問題都已經有答案了,一個都不必再查。剩下的全在應用程式裡面。那 125 秒是 Cloudflare 的 Proxy Read Timeout,寫在它的連線限制參考文件裡;只有 Enterprise 方案的區域可以調整,透過 Cache Rules 或區域設定 API 最多拉到 6,000 秒——所以在其他所有方案上,這個數字是環境的既定事實,不是一個可以調的設定。Cloudflare 列了兩個原因——來源網頁伺服器上有長時間執行的程序,以及來源網頁伺服器過載——而這兩個從邊緣看起來一模一樣,實際上卻是不同的問題:前者是請求正在執行、只是比逾時久,後者是請求根本還沒開始,因為工作行程池滿了。Cloudflare 文件裡的解法也照同一條線分開:慢的那支程序去找主機商談;長時間的 HTTP 操作改成狀態輪詢,不要一直開著一個請求;真的合理超過 125 秒的東西搬到一個 DNS-only(灰雲)的子網域後面,讓它完全不經過代理;並且用 Origin Analytics 在回應時間逼近門檻、還沒越過去之前就先看到它爬上來。有一個從 RFC 9110 §15.6.5 那個一般 504 帶過來的性質,在這裡更重要,因為計時器實在太長了:Cloudflare 不再聽的時候,來源機還在做事,所以 524 不能當成「什麼都沒發生」的證據。
| 容易搞混的 | 怎麼分 |
|---|---|
| 504 | 504 是 RFC 9110 §15.6.5 的 IETF 代碼,給一台沒有及時收到回應的閘道用,任何代理都可以回它。524 是 Cloudflare 的,代表 Cloudflare 自己那 125 秒的 Proxy Read Timeout 走完了。所以一個穿過 Cloudflare 抵達的 504,是 Cloudflare 後面某個東西產生、再被轉過來的,這代表計時器在你自己的技術堆疊裡、不在他們那邊——而耗時會指認出它,通常是 nginx 或 Application Load Balancer 的 60 秒。 |
522 | 兩個都是逾時,但它們量的是不同階段。522 是連線層級的:Cloudflare 的定義是送出 SYN 之後 19 秒內沒有 SYN+ACK,或連線建立之後 90 秒內請求沒被確認。524 是回應層級的,而且只有在上述全部成功之後才會發生。所以拿到 524 就等於證明了網路路徑、連接埠和防火牆全都正常,那是真的資訊,不是安慰。 |
| 521 | 521 是拒絕,524 是沉默,兩者完全互斥。Cloudflare 把 521 定義成來源機拒絕它的連線,指向一個停掉的行程、錯的綁定位址、一個不在 Cloudflare 代理清單裡的連接埠,或一道拒絕 Cloudflare 位址範圍的防火牆。而 524 靠著「連線成功」這件事,已經把上面每一項都排除了——所以看到 524 之後還花時間在連接埠和防火牆上,那些時間都花在錯的問題上。 |
520 | 520 是來源機回了一個 Cloudflare 用不了的東西——空的、未知的或非預期的,包括標頭超過它 128 KB 的上限;而 524 是來源機根本沒有及時回答。這個區別值得分清楚,因為兩邊的修法毫無共通之處:520 把你送去看你的應用程式吐出了什麼,包括格式壞掉的標頭和設定錯誤的 HTTP/2 to origin;524 則把你送去看它花了多久。 |
Cloudflare Tunnel | 來源機掛在通道後面,會改變你該去哪裡看,但不會改變那個計時器。125 秒的 Proxy Read Timeout 是「被代理的路徑」的性質,所以一個透過通道服務的請求撞到的是同一個上限,而連接器自己的紀錄就成了邊緣和應用程式之間的中間層。請把它跟來源機的存取紀錄一起看:一個出現在連接器紀錄、卻沒有出現在應用程式紀錄裡的請求,是被排在應用程式前面等,不是被應用程式拖慢的。 |
這些全都在你的瀏覽器裡跑,不會上傳任何東西。
查 524 的時候,通常也會順手看一下這幾個。
去讀回應標頭,不要讀那個網頁。curl -sS -o /dev/null -D - https://example.com/path 會只印標頭、不印內容,而 server、via 和 cf-ray 三個加起來,就能指出是哪一層回答的。有 cf-ray 的值代表這個回應是 Cloudflare 處理的,那個值也是他們客服會跟你要的編號。想把邊緣節點整個排除掉,就加上 --resolve example.com:443:203.0.113.10 再打一次:它會照樣送出原本的主機名稱和 SNI,但直接連到你指定的來源位址——答案變了,就代表邊緣節點和來源機講的不是同一件事。
不重要,而且絕對不要拿它來做判斷。RFC 9112 要求用戶端忽略原因片語,伺服器可以隨意改它,而 HTTP/2 和 HTTP/3 根本沒有這個欄位——所以在 HTTP/1.1 上是 404 Not Found,到了 HTTP/2 就只剩一個 404。這個網站會寫出登記在案的片語,是因為那是大家會拿去搜尋、也是會出現在 HTTP/1.1 紀錄裡的字串,不是因為有任何軟體依賴它。
5xx 和 429 可以重試,4xx 不要——下一次送過去也不會有任何不同。如果回應帶了 Retry-After 就照它做,RFC 9110 定義它就是為了這件事,值可以是秒數也可以是一個時間點。沒有的話,就用帶抖動的指數退避加上一個硬上限,而且只對冪等的方法這樣做:一個被重試的 POST 可能會刷兩次卡。對一台已經在失敗的伺服器丟出重試風暴,是短暫事故變成長時間事故最常見的那條路。
可以,唯一要守的規則是那個代碼必須是真的。所有會自動讀你回應的東西——搜尋引擎、監控、快取、用戶端的重試邏輯——都只看那個數字,從來不看那一頁寫了什麼。用 200 回一頁錯誤訊息,會把故障從你自己的警報裡藏起來;用 200 回一頁不存在的內容,會讓錯誤被當成內容收進索引;而對一個只是格式不對的請求回 500,會把值班的人送去堆疊裡錯的那一半。
524 還是卡住嗎?看完整的狀態碼對照表,或是回到上面,讀為你這一端寫的那一塊。