本文將協助你在使用 EventProcessorClient Azure 事件中樞 事件處理器類型時,排除相關問題。 用它來解決共同的擁有權、CPU、記憶體和接收器問題。 關於使用 Azure 事件中樞 時可能遇到的其他常見問題解決方案,請參見「故障排除 Azure 事件中樞」。
當您使用事件處理器時,會出現 412 錯誤,表示前置條件失敗。
當客戶端嘗試取得或更新分區的擁有權時,如果本機的擁有權記錄版本已過期,則會發生 412 前置條件錯誤。 當另一個處理器實例竊取分割區擁有權時,就會發生此問題。 如需詳細資訊,請參閱下一節。
分割區擁有權經常變更
當實例數量 EventProcessorClient 改變(也就是新增或移除實例時),執行中的實例會嘗試在彼此間進行分區的負載平衡。 處理器數量改變後的幾分鐘內,分割區會更換所有者。 平衡後,分割區的所有權會變得穩定且變動不頻繁。 如果分割區擁有權在處理器數量保持不變時頻繁變動,通常表示有問題。 提交一個 GitHub 問題,附上日誌和重製版。
CheckpointStore 會透過擁有權記錄來判定分割區的擁有權。 在每個負載平衡週期中,EventProcessorClient 會執行下列工作:
- 提取最新的所有權紀錄。
- 檢查紀錄,看看哪些紀錄在分割區所有權到期期間沒有更新時間戳。 只會考慮符合此準則的記錄。
- 如果有任何未擁有的分割區,且
EventProcessorClient執行個體之間的負載不平衡,事件處理器用戶端會嘗試宣告某個分割區的擁有權。 - 更新拥有它的分區的擁有權記錄,這些分區有与該分區的活跃链接。
您可以在建立 EventProcessorClient 時使用 EventProcessorClientBuilder 來設定負載平衡和擁有權到期的間隔,如下列清單所述:
- loadBalancingUpdateInterval(Duration) 方法會指出負載平衡週期的執行頻率。
- partitionOwnershipExpirationInterval(Duration) 方法指出,自所有權記錄更新以來,處理器將分割區視為無人擁有之前所需經過的最短時間。
例如,如果某筆所有權記錄於上午 9:30 更新,且 partitionOwnershipExpirationInterval 為 2 分鐘。 當負載平衡週期發生,且發現擁有權紀錄在過去兩分鐘內或上午 9:32 前沒有更新時,它會認為該分割區是無主的。
如果其中一個分割區取用者發生錯誤,系統會關閉對應的取用者,但在下一次負載平衡週期之前,不會嘗試重新接管它。
"...目前接收者『<RECEIVER_NAME>』與 epoch『<0』正在斷開連線"
整個錯誤訊息看起來類似下列輸出:
New receiver 'nil' with higher epoch of '0' is created hence current receiver 'nil' with epoch '0'
is getting disconnected. If you are recreating the receiver, make sure a higher epoch is used.
TrackingId:<GUID>, SystemTracker:<NAMESPACE>:eventhub:<EVENT_HUB_NAME>|<CONSUMER_GROUP>,
Timestamp:2022-01-01T12:00:00}"}
此錯誤發生在新增或移除 EventProcessorClient 實例後進行負載平衡時。 負載平衡是持續的過程。 當你和消費者一起使用 時 BlobCheckpointStore ,預設每隔 ~ 30 秒,消費者會檢查哪些消費者對每個分割區有申訴。 接著,它會執行某些邏輯,以判斷是否需要從另一個消費者那裡「偷取」一個分割區。 用來判斷分割區獨佔擁有權的服務機制稱為 Epoch。
然而,如果你沒有新增或移除實例,那就有潛在的問題需要你處理。 如需詳細資訊,請參閱 分割區擁有權經常變更 一節和 提出 GitHub 問題。
高 CPU 使用率
CPU 使用率高通常是因為實例擁有太多分割區。 每個 CPU 核心不要超過 3 個分割區。 先為每個 CPU 核心設置 1.5 個分割區,然後透過增加擁有的分割區數量來測試。
記憶體不足與選定堆記憶體大小
如果 JVM 目前的最大堆積不足以執行應用程式,記憶體不足 (OOM) 問題就可能發生。 你可能想測量應用程式的堆積需求。 然後,根據結果,使用 -Xmx JVM 選項設定適當的最大堆積記憶體來調整堆積大小。
不要指定 -Xmx 超過可用記憶體的值,或主機(虛擬機或容器)設定的限制——例如容器設定中請求的記憶體。 分配足夠的記憶體讓主機支援 Java 堆積。
下列步驟描述測量最大 Java 堆積值的一般方法:
在接近生產環境的環境中執行應用程式,其中應用程式會在生產環境預期的尖峰負載下傳送、接收及處理事件。
等候應用程式達到穩定狀態。 此階段,應用程式與 JVM 會載入所有域物件、類別類型、靜態實例、物件池(TCP、資料庫連線池)等等。
在穩定狀態下,您會看到堆積集合的穩定鋸形圖樣,如下列螢幕快照所示:
當應用程式達到穩態後,使用像 JConsole 這類工具強制執行完整的垃圾回收(GC)。 觀察完整 GC 之後所佔用的記憶體。 您想要調整堆積的大小,讓完整 GC 之後只佔用 30%。 使用此值設定最大堆大小(使用
-Xmx)。
如果您是在容器中執行,請將容器的記憶體容量額外增加約 1 GB,以滿足 JVM 執行個體的非堆記憶體需求。
處理器用戶端停止接收
處理器用戶端通常會在主機應用程式中持續執行幾天。 有時候,它會注意到 EventProcessorClient 不會處理一或多個分割區。 通常,沒有足夠資訊來判斷為何會發生這個例外。
EventProcessorClient停止是嘗試從瞬時錯誤中復原時發生的底層原因(也就是競態條件)的徵狀。 如需我們需要的資訊,請參閱 提出 GitHub 問題。
處理器重新啟動時收到重複的 EventData
EventProcessorClient 和事件中樞服務保證至少傳遞一次。 您可以新增元資料來辨別重複的事件。 如需詳細資訊,請參閱 Stack Overflow 上的 Azure 事件中樞是否保證至少傳遞一次? 如果您只需要一次配送,可以考慮 服務匯流排,它會等待客戶的確認。 如需傳訊服務的比較,請參閱 在 Azure 傳訊服務之間選擇。
基礎層級用戶端停止接收
Event Hubs 函式庫提供 EventHubConsumerAsyncClient 作為低階取用者用戶端。 它專為需要對反應式應用程式有更大控制與彈性的進階使用者設計。 此用戶端提供低階介面,讓您能管理反應爐鏈中的背壓、螺紋與回收。 不同於 EventProcessorClient, EventHubConsumerAsyncClient 不包含所有終端機原因的自動復原機制。 因此,您必須處理終端事件,並選擇合適的反應爐操作員來實施復原策略。
當 EventHubConsumerAsyncClient::receiveFromPartition 連線發生無法重試的錯誤或一系列連線復原嘗試連續失敗時,方法會發出終端機錯誤,以耗盡最大重試限制。 雖然低階接收者嘗試從暫時性錯誤復原,但取用者用戶端的使用者預期會處理終端事件。 如果希望持續接收事件,應用程式應調整 Reactor 鏈結,在終端事件時建立新的消費者客戶端。
從傳統舊版移轉至新的客戶端程式庫
移轉 指南 包含從舊版用戶端移轉和移轉舊版檢查點的步驟。
後續步驟
如果這篇文章中的故障排除指引無法幫助你解決使用Azure SDK來處理Java客戶端函式庫的問題,請在Java GitHub儲存庫的Azure SDK中提出問題。