超時操作指南

簡介

設定通訊超時對於改善通訊流程非常重要。它們有助於偵測問題並穩定分散式系統。JK 可以使用多種不同的超時類型,這些類型可以個別設定。由於歷史原因,它們在預設情況下全部停用。本操作指南說明其使用方式,並提供尋找適當數值的提示。

所有超時都可以在 workers.properties 檔案中設定。如需所有工作執行緒設定項的完整參考,請參閱工作執行緒參考。此頁面假設您至少使用 JK 1.2.16 版。在必要時會提到對較新版本的依賴關係。

請勿將超時設定為極端值。過小的超時可能會適得其反。

後端上的長時間垃圾回收暫停與某些超時不符。請嘗試最佳化您的 Java 記憶體和 GC 設定。

JK 超時屬性

CPing/CPong

CPing/CPong 是我們使用小型測試封包來檢查後端連線狀態的概念。JK 可以直接在建立新的後端連線 (連線模式) 之後以及在將每個要求傳送至後端 (前置模式) 之前直接使用此類測試封包。從 1.2.27 版開始,當連線閒置很長一段時間時,也可以使用它 (間隔模式)。可以設定 CPong 回答 CPing 的最大等待時間 (超時) 和間隔模式中的閒置時間。

後端將以最少的處理資源需求非常快速地回答測試封包。正面的回答告訴我們,可以存取後端,並且後端正在主動處理要求。它無法偵測是否已部署並執行某些內容。CPing/CPong 的好處是快速偵測到與後端的通訊問題。缺點是會稍微增加延遲時間。

工作者屬性 ping_mode 可設定為字元的組合,用於判斷在哪些情況下使用測試封包

  • C:連線模式,逾時 ping_timeout 會被 connect_timeout 覆寫
  • P:前置後置模式,逾時 ping_timeout 會被 prepost_timeout 覆寫
  • I:間隔模式,逾時 ping_timeout,閒置時間 connection_ping_interval
  • A:所有模式

多個值必須串接,且沒有任何分隔字元。我們建議使用所有 CPing 測試。如果您的應用程式對延遲非常敏感,則應該只使用連線和間隔模式的組合。

透過 ping_mode 啟用 CPing 探測已新增至版本 1.2.27。對於較舊的版本,僅存在連線和前置後置模式,且必須透過明確設定 connect_timeoutprepost_timeout 來啟用。

工作者屬性 ping_timeout 設定所有模式的 CPong 預設等待逾時(毫秒)。預設值為「10000」毫秒。只有在您透過 ping_mode 啟用 CPing/Cpong 探測時,才會使用此值。除非您遇到非常長的 Java 垃圾回收暫停,否則預設值應該沒問題。根據您的網路延遲和穩定性,良好的自訂值通常介於 5000 到 15000 毫秒之間。您可以使用 connect_timeoutprepost_timeout 覆寫用於連線和前置後置模式的逾時。請記住:不要使用極小的值。

工作者屬性 connect_timeout 設定連線建立期間 CPong 的等待逾時(毫秒)。如果您要覆寫使用 ping_timeout 設定的一般逾時,可以使用此屬性。若要使用連線模式 CPing,您需要透過 ping_mode 啟用它。由於 JK 通常使用持續連線,因此開啟新連線是一個罕見的事件。因此,我們建議啟用連線模式。根據您的網路延遲和穩定性,良好的值通常介於 5000 到 15000 毫秒之間。請記住:不要使用極小的值。

工作者屬性 prepost_timeout 設定請求轉發之前 CPong 的等待逾時(毫秒)。如果您要覆寫使用 ping_timeout 設定的一般逾時,可以使用此屬性。若要使用前置後置模式 CPing,您需要透過 ping_mode 啟用它。啟用這種類型的 CPing/CPong 會為每個請求增加一點延遲。通常這點延遲很小,而 CPing/CPong 的好處更為重要。因此,我們通常也建議使用 prepost_timeout。根據您的網路延遲和穩定性,良好的值通常介於 5000 到 10000 毫秒之間。請記住:不要使用極小的值。

在版本 1.2.27 之前,ping_modeping_timeout 不存在,若要啟用連線或前置後置模式 CPing,您必須將 connect_timeout 分別設定為 prepost_timeout 為某個合理的正值。

低階 TCP 逾時

某些平台允許設定 TCP socket 上所有作業的逾時。這適用於 Linux 和 Windows,其他平台不支援此功能,例如 Solaris。如果您的平台支援 TCP 傳送和接收逾時,您可以使用工作者屬性 socket_timeout 設定它們。您無法將兩個逾時設定為不同的值。

即使您的平台不支援 socket 逾時,JK 仍會接受此屬性。在此情況下,設定屬性不會產生任何效果。預設值為「0」,且逾時已停用。您可以將屬性設定為某些秒數值(非毫秒)。然後,JK 會將後端連線的傳送和接收逾時設定為此值。逾時為低層級,個別用於 socket 上的每個讀取和寫入作業。

使用此屬性會讓 JK 對某些類型的網路問題做出更快速的反應。很遺憾的是,socket 逾時有負面效應,因為對於大多數平台而言,一旦觸發逾時,就沒有好的方法可以從此逾時復原。對於 JK 而言,沒有辦法判斷此逾時是因為真正的網路問題而觸發,還是只因為未及時從後端收到回應封包。因此請記住:不要使用極小的值。

對於建立連線的一般情況,您可以使用 socket_connect_timeout。它會取得毫秒值,且適用於大多數平台,即使不支援 socket_timeout。我們建議使用 socket_connect_timeout,因為在某些網路故障情況下,由於 TCP 重新傳輸,建立連線期間的故障偵測可能需要花費數分鐘。根據您的網路品質,1000 到 5000 毫秒之間的逾時應該就足夠了。請注意,socket_timeout 以秒為單位,而 socket_connect_timeout 以毫秒為單位。

連線池和閒置逾時

JK 在每個網路伺服器程序中以連線池的方式處理後端連線。連線以持續模式使用。在要求成功完成後,我們會保持連線開啟,並等待下一個要求轉發。連線池能夠根據想要平行轉發要求的執行緒數量而增加。

大多數應用程式都有依據每日時段或每月日期而變化的負載。連線池不斷增加的其他原因可能是後端暫時變慢,導致前端(例如網路伺服器)壅塞。許多後端會為每個處理的輸入連線使用一個專用執行緒。因此,通常希望在負載減少時縮小連線池。

JK 允許池中的連線在一段閒置時間後關閉。這個最大閒置時間可以使用屬性 connection_pool_timeout 設定,單位為秒。預設值為「0」,會停用關閉閒置連線。

我們通常建議使用大約 10 分鐘的值,因此將 connection_pool_timeout 設定為 600(秒)。如果您使用這個屬性,請也在 Tomcat server.xml 設定檔的 AJP Connector 元素中將屬性 keepAliveTimeout(如果已明確設定)或 connectionTimeout 設定為類似的值。注意keepAliveTimeoutconnectionTimeout 必須以毫秒為單位。因此,如果您將 JK connection_pool_timeout 設定為 600,您應該將 Tomcat keepAliveTimeoutconnectionTimeout 設定為 600000。

JK 連線並不會在超過逾時時間後立即關閉。相反地,有一個自動的內部維護工作每 60 秒執行一次,檢查所有連線的閒置狀態。60 秒的間隔可以使用全域屬性 worker.maintain 調整。我們不建議變更這個值,因為它有許多副作用。在版本 1.2.26 之前,維護工作只會在處理要求時執行。因此,如果您的網路伺服器有長時間沒有收到任何要求的程序,就無法關閉其池中的閒置連線。從版本 1.2.27 開始,您可以在使用具備執行緒 APR 的 Apache HTTP Server 2.x 或 Microsoft IIS 時設定一個獨立的監控執行緒。

最大連線池大小可用屬性 connection_pool_size 設定。我們通常不建議將此屬性與 Apache HTTP Server 搭配使用。對於 Apache,我們會自動偵測每個程序的執行緒數量,並將最大池大小設定為此值。對於 Microsoft IIS,我們使用預設值 250(1.2.20 版本之前:10)。我們強烈建議將此值調整為 IIS 的請求數量,一個網路伺服器程序應該能夠平行傳送至後端。您應該衡量在尖峰時段需要多少連線才能沒有效能問題,然後根據成長率等因素增加一些百分比。最後,您應該檢查您的網路伺服器程序是否能夠使用至少與您設定的池大小一樣多的執行緒。

JK 屬性 connection_pool_minsize 定義池縮小時保留多少個閒置連線。預設值為最大池大小的一半。

防火牆連線中斷

閒置連線的一個特殊問題來自防火牆,這些防火牆通常部署在網路伺服器層和後端之間。根據其設定,如果閒置時間過長,它們會從其狀態表中靜默中斷連線。

從 JK 和網路伺服器的觀點來看,另一方根本不會回應任何流量。由於 TCP 是可靠的通訊協定,它會偵測遺失的 TCP ACK,並嘗試重新傳送封包一段相對較長的時間,通常是幾分鐘。因此,您應該始終在 JK 端使用 connection_pool_timeout 和 connection_pool_minsize,在 Tomcat 端使用 keepAliveTimeoutconnectionTimeout 以防止閒置連線中斷。

此外,使用布林屬性 socket_keepalive,您可以設定標準的 socket 選項,在每個連線閒置一段時間後自動傳送 TCP keepalive 封包。預設值設定為 false。如果您懷疑防火牆會中斷閒置連線,您應該將此設定為 true

很遺憾,這些封包的預設間隔和演算法是特定於平台的。您可能需要檢查您平台的 TCP 調整選項,了解如何控制 TCP keepalive。通常,預設間隔比防火牆對閒置連線的逾時時間長很多。儘管如此,我們建議您與防火牆管理員和平台管理員溝通,以便他們就防火牆和平台 TCP 調整的良好設定值達成共識。

如果我們的建議都沒有幫助,而且您確實遇到閒置連線中斷的問題,您可以停用在 JK 與 Apache HTTP Server 搭配使用時使用持續性連線。為此,您可以在 Apache 設定中設定「JkOptions +DisableReuse」。這會造成的效能影響程度取決於您的網路和防火牆的詳細資訊。

回覆逾時

JK 也能對要求回覆使用逾時。此逾時不會測量回應的完整處理時間。相反地,它會控制連續回應封包之間允許的時間。

在多數情況下,這正是實際上想要的。例如,考慮執行時間很長的下載。你無法設定有效的全域回覆逾時,因為下載可能持續好幾分鐘。不過,多數應用程式在開始傳回回應之前,處理時間有限。對於那些應用程式,你可以設定明確的回覆逾時。與回覆逾時不協調的應用程式是批次類型應用程式、資料倉儲和報告應用程式,它們預期會觀察到很長的處理時間。

如果 JK 中止等待回應,因為回覆逾時已觸發,則沒有辦法在後端停止處理。儘管你在網路伺服器中釋放處理資源,但要求仍會繼續在後端執行,一旦回覆逾時觸發,就沒有辦法傳回結果。

JK 使用工作者屬性 reply_timeout 設定回覆逾時。預設值為「0」(逾時已停用),你可以將其設定為任何毫秒值。

結合 Apache HTTP 伺服器,你也可以使用 Apache 環境變數設定更彈性的 reply_timeout。如果你將變數 JK_REPLY_TIMEOUT 設定為某個整數值,則會使用此值,而不是工作者組態中的值。這樣一來,你可以使用 mod_setenvif 和 mod_rewrite,根據 URI、查詢字串等,更彈性地設定回覆逾時。如果環境變數 JK_REPLY_TIMEOUT 未設定,或設定為負值,則會使用工作者的預設回覆逾時。如果 JK_REPLY_TIMEOUT 包含值「0」,則會為要求停用回覆逾時。

結合負載平衡工作者,如果回覆逾時觸發,JK 會停用負載平衡器的成員工作者。然後,工作者會一直停用,直到在下次自動維護工作期間復原為止。從 JK 1.2.24 開始,你可以使用 max_reply_timeouts 來改善此行為。此屬性允許偶爾執行時間很長的請求,而不會停用工作者。只有當這些請求發生得太頻繁時,工作者才會被負載平衡器停用。

負載平衡器錯誤偵測

本機和全域錯誤狀態

負載平衡器工作者不只具有平衡負載的能力。它也會在發生錯誤時處理要求的黏著性和故障轉移。當負載平衡器偵測到其成員之一發生錯誤時,它需要決定該錯誤是嚴重的,還是僅是暫時性的錯誤,或者可能只與處理的實際要求有關。暫時性的錯誤稱為本機錯誤,嚴重的錯誤稱為全域錯誤。

如果負載平衡器決定應將後端置於全域錯誤狀態,則網路伺服器不會再傳送任何要求到那裡。如果未使用任何階段複製,這表示位於各別後端的使用者階段都已不再可用。使用者會被傳送到另一個後端,並且必須重新登入。因此,全域錯誤狀態對使用者來說並非透明的。應用程式仍然可用,但使用者可能會遺失一些工作。

在某些情況下,在區域錯誤和全域錯誤之間做出決定是很容易的。例如,如果在將回應傳送回用戶端(瀏覽器)時發生錯誤,則後端損壞的可能性非常低。因此,這種情況是區域錯誤的典型範例。

不過,有些情況則較難以決定。如果負載平衡器無法建立與後端的連線,可能是因為暫時過載(因此後端沒有更多可用執行緒),或者是因為後端已不再運作。根據詳細資料,正確的狀態可能是區域錯誤或全域錯誤。

錯誤升級時間

在 1.2.26 版本之前,大多數錯誤都被解釋為全域錯誤。從 1.2.27 版本開始,許多先前被解釋為全域錯誤的錯誤,只要後端仍忙碌,就會轉換為區域錯誤。忙碌表示其他同時請求會傳送至同一個後端(成功或失敗)。

在許多情況下,沒有完美的方法可以在區域錯誤和全域錯誤之間做出決定。負載平衡器根本沒有足夠的資訊。在 1.2.28 版本中,您現在可以調整負載平衡器從區域錯誤切換到全域錯誤的速度。如果負載平衡器的成員在區域錯誤狀態停留太久,負載平衡器會將其升級為全域錯誤狀態。

在區域錯誤狀態中容忍的時間由負載平衡器屬性 error_escalation_time(以秒為單位)控制。預設值是 recover_time 的一半,因此除非您變更了 recover_time,否則預設值為 30 秒。

error_escalation_time 使用較小的值會讓負載平衡器對嚴重錯誤做出更快速的反應,但也承擔了在不太嚴重的狀況下更常遺失工作階段的風險。您可以將 error_escalation_time 降低至 0 秒,這表示所有潛在嚴重的區域錯誤都會立即升級為全域錯誤。

請注意,沒有良好的基本錯誤偵測,整個升級程序都是沒有用的。因此,在考慮調整 error_escalation_time 之前,您絕對應該使用 socket_connect_timeout 並使用 ping_modeping_timeout 啟用 CPing/CPong。