網誌

如何把部署的 502 錯誤降至零

每次部署 Mythex 的後端,都會有少量請求失敗,並回傳 502 Bad Gateway。數量不多,但部署期間出現 502,就代表某位用戶的點擊沒有任何反應,或是他正在看的建構停頓了一下。我們追查後發現兩個獨立的問題:一個自我修復的看門程式與部署互相角力,以及伺服器停止監聽與負載平衡器停止向它發送流量之間的時間差。修復之後,連續三次正式部署的數字由 10 降至 6,再降至 0。

架構

我們的 API 和協調器以容器形式運行在一組小型伺服器上,位於 AWS Application Load Balancer(ALB)之後。部署會逐台更新伺服器:排空舊容器,啟動新容器,然後移到下一台。每台伺服器上都有一個看門程式,每分鐘檢查容器是否在運行,並重新啟動任何停止的容器——它的存在,就是為了讓凌晨三點崩潰的程序自行恢復,無需有人被叫醒。

兩者單獨來看都合理。但放在一起就不然。

問題一:看門程式與部署競爭

看門程式每分鐘運行一次,並在一次健康檢查失敗後就進行「修復」。而部署會刻意排空服務長達 150 秒——在此期間,健康檢查本來就應該失敗。因此,看門程式在每一次部署期間都會觸發。

大多數時候它輸掉這場競賽,而無傷大雅。但有一次它贏了:它在部署進行中改寫了 compose 檔案(描述哪些容器應該運行的檔案),令一台伺服器完全沒有閘道容器——而部署工作卻報告成功。

修復方法:

  • 同一把鎖。 部署現在會取得與伺服器啟動腳本相同的檔案鎖,因此看門程式與部署永遠不會同時運行。
  • 四次失敗才行動,而不是一次。 看門程式需要連續四次健康檢查失敗才會採取行動。正在排空的服務不再被誤判為已死。
  • 單一定義。 compose 檔案現在只有一個來源,並發佈到伺服器,而不是可能彼此偏離的多份副本。
  • 驗證,而不是信任。 部署工作不再因為某個命令返回而通過。它會先檢查每台伺服器的 API、協調器、閘道和發佈工作程序,然後才可能成功。

問題二:伺服器比流量先離開

第二個問題較為隱蔽。當部署排空一台伺服器時,該伺服器會開始以 503 回應其健康端點,好讓負載平衡器將它移出輪替。我們的伺服器這樣做了 5 秒,然後才關閉。

但 ALB 只會每隔一段時間檢查健康狀況,而且要連續多次失敗才會停止向某個目標路由,端到端最多約需 60 秒。因此,在大約 55 秒內,負載平衡器仍會把真正的請求發送給一台已經停止監聽的伺服器。那些就是我們的 502。

修復方法是令兩條時間線互相配合:

  • 目標群組現在每 5 秒檢查一次,並在連續 2 次失敗後將目標標示為不健康——大約 10 秒便能察覺。
  • 排空會在開始讓健康檢查失敗之後,再繼續為真正的流量提供服務 15 秒,因此總會有重疊的時間。
  • 這些設定寫在負責佈建基礎設施的腳本中,而不是某人曾經在控制台上點擊設定的地方。

讓各數字互相吻合

這些逾時相互依賴。排空時間必須長於負載平衡器察覺所需的時間;排空加上關閉必須在容器被強制終止之前完成。某人在六個月後更改其中一個數字,然後悄悄地令錯誤重現,是很容易發生的事。

因此,我們把這些關係寫成測試:排空時間必須長於健康檢查間隔乘以失敗閾值;重新被標示為健康所需的時間必須保持簡短;整個排空過程必須能放入容器的停止寬限期之內。只要更改其中一個數字而沒有同時調整其他數字,CI 便會失敗。我們還對測試本身進行了變異測試——把每個數字改成錯誤的值,然後檢查是否有測試能夠捕捉到。

測量部署很容易出錯

我們最初的測量結果顯示,一次正常的部署大約有 3% 是壞的。但事實並非如此。我們計算的是所有非 200 的回應,而排空期間健康端點回傳的 503 並不是失敗——它是排空在盡其本分,告訴負載平衡器不要選取該伺服器,而該伺服器仍在繼續處理真正的請求。

用戶真正感受到的是 502:請求連一個能回應的目標都沒有到達。只計算這些,才得出真實的情況——連續三次正式部署分別為 10、6,然後是 0。

我們的心得

  • 自我修復需要知道計劃中的停機。 一個無法分辨部署與崩潰的看門程式,遲早會與部署互相角力。
  • 排空是一次握手。 伺服器必須持續提供服務,直到負載平衡器確定已停止發送流量,而這個時間是在負載平衡器上設定的,而不是在伺服器上。
  • 把不變量編碼為測試。 營運數字會逐漸偏移。把它們彼此關聯起來的測試則不會。
  • 在測量之前,先決定你要量度什麼。「錯誤」是錯誤的指標;「沒有到達任何目標的請求」才是正確的指標。

如果你在 Mythex 上發佈應用程式,這一切對你都是看不見的——這正是目標所在。相關閱讀:你的已發佈應用程式如何在重新發佈期間保持上線。

Mythex · Pricing · 用 AI 建造任何嘢 · 網站及應用程式範本 · Mythex 比較 · AI 應用程式開發詞彙表 · 免費 AI 應用程式開發工具 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(台灣)