排解 App Engine 應用程式延遲情況加重的問題

在許多情況下,應用程式延遲情況加重最終會導致 5xx 伺服器錯誤。由於錯誤和延遲峰值的根本原因可能相同,請套用下列策略來排解延遲問題:

  1. 找出延遲問題的範圍
  2. 找出原因
  3. 疑難排解

找出延遲問題

請思考以下問題,定義問題的範圍:

  • 這項問題會影響哪些應用程式、服務和版本?
  • 這項問題會影響服務的哪些端點?
  • 這會影響全球所有客戶,還是特定客戶?
  • 事件的開始和結束時間為何?請考慮指定時區。
  • 具體錯誤為何?
  • 觀察到的延遲差異是什麼?通常會指定為特定百分位數的增加值。舉例來說,延遲時間在第 90 百分位數時增加了 2 秒。
  • 您如何測量延遲時間?具體來說,您是否在用戶端進行測量,或是在 Cloud Logging 或 App Engine 服務基礎架構提供的 Cloud Monitoring 延遲資料中看到這項資訊?
  • 您的服務有哪些依附元件?這些依附元件是否發生事件?
  • 您最近是否曾變更程式碼、設定或工作負載,導致這個問題發生?

服務可能會自訂監控和記錄功能,方便您進一步縮小問題範圍。定義問題的範圍有助於您找出可能的根本原因,並決定後續的疑難排解步驟。

找出原因

判斷要求路徑中哪個元件最有可能導致延遲或錯誤。要求路徑中的主元件如下:

用戶端 --> 網際網路 --> Google Front End (GFE) --> App Engine 服務架構 --> 服務執行個體

如果上述資訊無法指出失敗原因,請在查看服務執行個體的健康狀況和效能時,套用下列策略:

  1. 監控 App Engine 要求記錄。如果您在這些記錄中看到 HTTP 狀態碼錯誤或延遲時間增加,問題可能出在執行服務的執行個體。

  2. 如果服務執行個體數量未擴充至符合流量層級,執行個體可能會超載,導致錯誤和延遲情形升高。

  3. 如果您在 Cloud Monitoring 中看到錯誤或延遲情形增加,問題可能來自負責記錄 App Engine 指標的負載平衡器上游。在大多數情況下,這表示服務例項有問題。

  4. 如果監控指標顯示延遲時間增加或出現錯誤,但要求記錄中沒有顯示,表示負載平衡器發生錯誤,或執行個體發生嚴重錯誤,導致負載平衡器無法轉送要求。如要區分這些情況,請查看事件開始前的請求記錄。如果要求記錄顯示延遲時間在失敗前增加,表示應用程式執行個體在負載平衡器停止將要求轉送至該執行個體之前,就已開始失敗。

疑難排解

本節將說明以下要求路徑中元件的疑難排解策略,以解決延遲時間過長的問題:

  1. 網際網路
  2. Google Front End (GFE)
  3. App Engine 服務基礎架構
  4. 應用程式執行個體
  5. 應用程式依附元件

網際網路

應用程式可能會因為連線不佳或頻寬較低而發生延遲問題。

網路連線品質不佳

如要判斷問題是否出在網際網路連線不佳,請在用戶端上執行下列指令:

$ curl -s -o /dev/null -w '%{time_connect}\n' <hostname>

time_connect 的值代表用戶端與最近的 Google Front End 連線的延遲時間。如果連線速度緩慢,請進一步使用 traceroute 排解問題,判斷網路上哪個節點造成延遲。

從不同地理位置的用戶端執行測試。App Engine 會自動將要求轉送至最近的 Google 資料中心,這會根據用戶端的位置而有所不同。

頻寬偏低

應用程式可能會快速回應;不過,網路瓶頸會導致 App Engine 服務基礎架構無法快速透過網路傳送封包,進而延遲回應時間。

Google Front End (GFE)

應用程式可能會因為路由不正確、從 HTTP/2 用戶端傳送的並行要求,或 SSL 連線終止而發生延遲問題。

將用戶端 IP 對應至地理區域

Google 會根據用戶端在 DNS 查詢中使用的用戶端 IP 位址,將 App Engine 應用程式主機名稱解析為與用戶端最近的 GFE。如果用戶端的 DNS 解析工具未使用 EDNS0 通訊協定,Google 可能不會將用戶端要求轉送至最近的 GFE。

HTTP/2 首行封鎖

由於 GFE 會在第一線封鎖,因此 HTTP/2 用戶端並行傳送多個要求時,可能會出現延遲時間增加的情形。如要解決這個問題,用戶端必須使用 QUIC 通訊協定

自訂網域的安全資料傳輸層 (SSL) 終止

GFE 可能會終止 SSL 連線。如果您使用的是自訂網域而非 appspot.com 網域,則 SSL 終止作業需要額外的跳躍。這可能會增加部分地區應用程式的延遲時間。詳情請參閱「對應自訂網域」。

App Engine 服務基礎架構

由於服務全局事件或自動調整大小,應用程式可能會出現延遲情形。

服務層級事件

Google 會在服務健康狀況資訊主頁上發布全服務嚴重異常的詳細資料。不過,Google 會逐步推出更新,因此服務層級事件不太可能會同時影響到所有執行個體。

自動調度資源

下列自動調整大小的情況可能會導致延遲時間增加或發生錯誤:

  • 流量擴增速度過快:App Engine 自動調度可能無法隨著流量增加而快速擴充執行個體,導致暫時性超載。一般來說,當流量是由電腦程式而非使用者產生時,就會發生超載。如要解決這個問題,請節制產生流量的系統。

  • 流量突然暴增:如果自動調整型服務需要以更快的速度擴充,而不會影響延遲時間,則流量突然暴增可能會導致延遲時間增加。使用者流量通常不會造成頻繁的流量尖峰。如果發現流量激增,請調查原因。如果批次系統會間歇性地執行,您可以平滑流量或使用不同的調整設定。

  • 自動配置器設定:您可以根據服務的資源調度特性設定自動配置器。在下列情況下,縮放參數可能會變得不理想:

    • 如果 App Engine 標準環境的資源調度設定過於激進,可能會導致延遲。如果您在記錄中看到狀態碼為 500 的伺服器回應,以及「在嘗試處理要求時等待太久,因此終止要求」訊息,表示在等待閒置執行個體時,要求在待處理佇列中逾時。

    • 即使您已配置足夠的執行個體,手動調度可能會導致待處理時間增加。如果應用程式提供使用者流量,建議您不要使用手動調整大小。手動調整資源調度較適合工作負載,例如工作佇列。

    • 基本調整可降低成本,但會增加延遲時間。建議您不要為延遲時間敏感的服務使用基本調整功能

    • App Engine 的預設資源調度設定可為大多數服務提供最佳延遲時間。如果您仍看到有大量待處理時間的要求,請指定執行個體數量下限。如果您調整調整縮放設定,藉此減少閒置執行個體以降低成本,一旦負載突然增加,就可能發生延遲時間尖峰的風險。

建議您使用預設的縮放設定進行成效基準測試,然後在每次變更這些設定後執行新的基準測試。

部署作業

如果在部署後不久就出現延遲情形,表示您在遷移流量前未充分擴充。較新的執行個體可能未預熱本機快取,因此服務速度會比舊執行個體慢。

為避免延遲時間飆升,請勿使用與現有服務版本相同的版本名稱部署 App Engine 服務。如果您重複使用現有版本名稱,就無法逐步將流量遷移至新版本。由於 App Engine 會在短時間內重新啟動每個執行個體,因此要求可能會變慢。如要還原為先前版本,也必須重新部署。

應用程式執行個體

本節將說明可套用至應用程式執行個體和原始碼的常見策略,以便提升效能並縮短延遲時間。

應用程式程式碼

應用程式程式碼的問題可能很難偵錯,尤其是如果問題是間歇性發生或無法重現的情況。

如要解決問題,請按照下列步驟操作:

  • 如要診斷問題,建議您使用記錄監控追蹤功能來檢測應用程式。您也可以使用 Cloud Profiler

  • 請嘗試在本機開發環境中重現問題,這樣您就能執行 App Engine 中可能無法執行的特定語言偵錯工具。

  • 如要進一步瞭解應用程式失敗的原因和發生的瓶頸,請對應用程式進行負載測試,直到失敗為止。設定執行個體數量上限,然後逐步增加負載,直到應用程式失敗為止。

  • 如果延遲問題與應用程式程式碼新版本的部署作業有關,請回溯,判斷新版本是否造成這項事件。不過,如果您持續部署,那麼由於部署頻繁,因此很難根據發生時間判斷部署作業是否導致事件。

  • 應用程式可能會將設定儲存在 Datastore 或其他位置。建立設定變更時間表,判斷是否有任何變更與延遲時間增加的開始時間相符。

工作負載變更

工作負載變更可能會導致延遲時間增加。部分監控指標可用來判斷工作負載是否有變化,包括 qps、API 用量和延遲時間。也請檢查請求和回應大小是否有變化。

記憶體壓力

如果監控顯示記憶體用量呈鋸齒狀模式,或是記憶體用量因部署作業而下降,記憶體可能會發生耗損,導致效能問題。記憶體流失也可能導致垃圾收集頻繁發生,進而導致延遲時間變長。如果您無法追蹤這項問題是否為程式碼的問題,請嘗試佈建記憶體較大的執行個體。

資源耗用

如果應用程式執行個體的延遲時間上升,且與執行個體年齡有關,則可能有資源耗用問題導致效能問題。部署完成後,延遲時間會降低。舉例來說,如果資料結構因 CPU 使用率提高而逐漸變慢,可能會導致任何受 CPU 限制的工作負載變慢。

程式碼最佳化

如要縮短 App Engine 的延遲時間,請使用下列方法改善程式碼:

  • 離線工作:使用 Cloud Tasks 可避免使用者要求阻擋應用程式等待工作完成 (例如傳送郵件)。

  • 非同步 API 呼叫:確保程式碼不會在等待 API 呼叫完成時遭到封鎖。

  • 批次 API 呼叫:批次版本的 API 呼叫通常比傳送個別呼叫更快。

  • 將資料模型去規格化:透過將資料模型去規格化,減少對資料持久層的呼叫延遲時間。

應用程式依附元件

監控應用程式的依附元件,偵測延遲時間峰值是否與依附元件失敗有關。

工作負載變更和流量增加,可能會導致依附元件的延遲時間增加。

非縮放依附元件

如果應用程式的依附元件未隨著 App Engine 執行個體數量增加而調整,當流量增加時,依附元件可能會超載。例如 SQL 資料庫,應用程式執行個體數量越多,資料庫連線數量就會越多,這可能會導致資料庫無法啟動,進而造成連鎖故障。如要解決這個問題,請按照下列步驟操作:

  1. 部署不會連線至資料庫的新預設版本。
  2. 關閉先前的預設版本。
  3. 部署新的非預設版本,以便連結至資料庫。
  4. 將流量緩慢遷移至新版本。

為預防措施,請設計應用程式,使用自動調節調節功能,放棄對依附元件的要求。

快取層失敗

如要加快要求速度,請使用多層快取,例如邊緣快取、Memcache 和例項內記憶體。其中一個快取層發生故障時,可能會導致延遲時間突然增加。舉例來說,Memcache 的清除作業可能會導致更多要求傳送至速度較慢的 Datastore。