本文提供 Pub/Sub 提取訂閱項目的常見疑難排解提示。如要進一步瞭解提取訂閱項目,請參閱提取訂閱者指南。
如要有效監控 Pub/Sub 訂閱項目,建議先查看訊息傳遞延遲時間健康狀態分數 (subscription/delivery_latency_health_score),瞭解哪些因素可能導致延遲時間異常或增加。
最舊未確認訊息的存在時間持續增加
oldest_unacked_message_age 是監控 Pub/Sub 訂閱項目健康狀態的重要指標。這項指標會測量訂閱項目待處理項目中,尚未由訂閱者確認 (acked) 的最舊訊息存在時間 (以秒為單位)。這項指標可提供寶貴的洞察資訊,協助您瞭解潛在的處理延遲或瓶頸。
監控待處理訊息可確保訊息處理作業及時有效率。追蹤最舊未確認訊息的存在時間,即可主動找出消費者落後的情況。這種做法可讓您及早介入,解決效能降低的潛在問題。
您可以調查的常見待處理問題包括:
用戶端設定問題
如果 oldest_unacked_message_age 和 num_undelivered_messages 指標同時增加,可能表示訂閱者無法跟上訊息量。在這種情況下,請著重調查訂閱者元件:
用戶端健康狀態:分析託管訂閱者用戶端的機器資源使用率,例如 CPU、記憶體和網路頻寬。找出可能阻礙處理效率的壓力點。
用戶端程式碼:查看最近的程式碼變更和錯誤記錄。訂閱者程式碼中的錯誤或效率不彰,可能會大幅影響訊息處理速率。請注意,特定訊息可能會有問題。舉例來說,多則訊息可能需要同時存取資料庫中的同一列。這種行為可能導致爭用和高延遲。
配額限制:確認您未超出任何 Pub/Sub 配額或代管服務限制。如果訂閱者託管於 Google Cloud,請查看 Compute Engine 或 GKE 資源配額,避免潛在瓶頸。
訂閱者對訊息發出負面確認
如果訂閱者對訊息發出否定確認 (nack),代表訊息無法成功處理。Pub/Sub 接著會嘗試重新傳送同一則訊息。如果訊息重複收到負面確認,可能會導致重複訊息,並可能大幅延遲訊息傳送。
請注意,對訊息執行 NACK 操作,不保證下次提取時會擷取其他訊息。Pub/Sub 的重新傳送政策可能會繼續重新傳送未確認的訊息,然後才傳送新訊息。因此,請勿將 NACK 做為篩選或略過特定訊息的方法。請改為設定重試政策,最好是指數輪詢,以便對可能稍後處理但需要更長時間才能重新傳送的個別訊息進行輪詢。
如需刻意略過特定訊息,建議您確認收到訊息,即使不處理也一樣。這樣一來,系統就會將這些訊息從訂閱項目中移除,避免不必要的重新傳送,並減少資源消耗。無論是否刻意,未確認訊息都會導致待處理項目問題和重複傳送。
高傳送延遲
Pub/Sub 的傳送延遲時間,是指訊息從發布端傳送至訂閱端所需的時間。以下各節將說明傳送延遲時間過長的可能原因。
訂閱者人數不足
如果用戶端使用 StreamingPull,請為訂閱項目維持多個 StreamingPull 開放連線,以確保低延遲。如果沒有有效的訂閱端連線,Pub/Sub 就無法及時傳送訊息。單一串流可能會成為單點故障,增加延遲風險。subscription/open_streaming_pulls 指標可讓您瞭解有效串流連線的數量。請使用這項指標,確保您隨時有足夠的串流來處理收到的訊息。
如果用戶端使用一元提取,請對訂閱項目維持多個未完成的提取要求,以持續降低延遲。如果要求頻率過低,待處理工作中的訊息可能會累積,導致延遲時間增加。這種做法有助於盡量減少連線中斷,並縮短傳送延遲時間。
如果需要高處理量和低延遲,同時盡可能減少作業負擔和處理成本,建議使用高階用戶端程式庫。根據預設,高階用戶端程式庫會使用 StreamingPull API,因為這通常是盡可能縮短延遲時間的較佳選擇。高階用戶端程式庫包含預先建構的函式和類別,可處理驗證、處理量和延遲時間最佳化、訊息格式設定及其他功能的基礎 API 呼叫。
用戶端設定問題
請參閱「用戶端設定問題」。
待處理工作量過多
請注意,Pub/Sub 訂閱項目中待處理的未確認訊息會增加端對端延遲時間,因為訂閱者不會立即處理訊息。
排序鍵和「僅傳送一次」
排序鍵和僅限一次傳遞是很有用的功能,但需要 Pub/Sub 內部額外協調,才能確保正確傳遞。這項協調作業可能會降低可用性並增加延遲時間。雖然在穩定狀態下,差異微乎其微,但任何必要的協調步驟都可能導致延遲時間暫時增加,或錯誤率提高。如果啟用排序功能,則必須先確認排序鍵相同的早期訊息,才能傳送含有排序鍵的訊息。
請考量訊息排序或「僅一次」傳遞是否為應用程式的必要功能。如果低延遲是您的首要考量,建議盡量減少使用這些功能,有助於縮短訊息處理延遲時間。
郵件大小增加
訊息大小突然增加,可能會延長 Pub/Sub 和用戶端之間的傳輸時間,並減慢用戶端處理訊息的速度。
如果發現傳送延遲時間增加,可以使用 topic/message_sizes 指標 (依 topic_id 分組) 查看訊息大小。找出訊息大小激增與觀察到的效能問題之間的關聯。
遺失郵件
如果您懷疑訊息未成功傳送給訂閱者,可能是下列其中一個原因所致。
Pub/Sub 訂閱項目中有多個消費者時的訊息分配
在 Pub/Sub 中,訊息可能會不平均地分配給同一訂閱項目的消費者。Pub/Sub 會在所有活躍用戶端之間平衡訊息負載,但主要目標是盡可能提高整體訊息處理量,並盡量減少待處理項目,而非確保完全平均分配。系統會動態將更多訊息導向處理能力較高的消費者,也就是能快速確認訊息,且不受流量控制設定限制的消費者。如果消費者處理訊息的速度不同,或在不同條件下運作 (例如資源可用性、網路延遲),則可能處理不同數量的訊息。一般來說,速度較快、回應較迅速的消費者會接收及處理較多訊息。
這種跨多個消費者的分配方法,代表訊息的接收和處理順序可能不盡相同。因此,除非訂閱項目已啟用訊息排序功能,且發布者包含排序鍵,否則無法保證消費者會按照發布順序處理訊息。
請注意,訊息可能已傳送至用戶端,而未確認訊息的待處理項目不一定表示您會在下一個提取要求中收到這些訊息。請注意,消費者可能是使用 Google Cloud 控制台或 Google Cloud CLI 提取訊息的使用者,或是在本機執行自訂訂閱者來檢查訊息。
如果是一元提取用戶端,您可能會發現某些提取要求傳回零則訊息。如「訂閱者數量不足」一節所述,建議您維持多個未完成的提取要求,因為即使有待處理訊息,部分要求傳回的訊息數量仍可能少於設定的訊息數量上限,甚至可能為零。這是因為其他消費者可能持有可用訊息的租約。
如果消費者未在確認期限內確認訊息,或否定確認 (NACK) 訊息,Pub/Sub 會嘗試重新傳送訊息。這項重新傳送嘗試可以針對訂閱項目的任何有效消費者進行,不一定是最初接收訊息的消費者。因此,在訂閱項目的生命週期內,特定訊息 ID 可能會傳送至多個不同的訂閱項目連結消費者,並由這些消費者嘗試處理,直到其中一個消費者成功確認為止。
如果您懷疑訊息發布行為異常,請調查是否有同時連結至訂閱項目的多個消費者,並檢查個別成效指標和設定。
篩選訂閱項目
檢查訂閱項目是否附加篩選器。如果是,您只會收到符合篩選條件的訊息。Pub/Sub 服務會自動確認不符合篩選條件的訊息。請考量篩選器對待處理指標的影響。
使用 returnImmediately 選項
如果用戶端使用一元提取,請檢查 returnImmediately 欄位是否設為 true。這個欄位已淘汰,用於指示 Pub/Sub 服務立即回應提取要求,即使傳回時沒有訊息也一樣。這可能導致提取要求傳回 0 則訊息,即使有待處理項目也一樣。
用戶端設定問題
如果您使用 Java 用戶端程式庫,並透過 setChannelProvider() 方法使用自訂 gRPC 管道初始化訂閱者,請務必在建構 TransportChannelProvider 時,將 maxInboundMessageSize 設定設為至少 20 MB (符合程式庫的預設值)。如果這個值小於 10 MB,系統將無法正確接收大於 maxInboundMessageSize 的郵件。常見的設定方法包括 InstantiatingGrpcChannelProvider.Builder.setMaxInboundMessageSize() 和 ManagedChannelBuilder.maxInboundMessageSize()。
處理重複項目
在下列情況下,訂閱者可能會收到重複的訊息:
重新提交。用戶端否定確認訊息,或確認期限已過。這是正常現象。
重複提交。在成功確認或確認期限到期前,系統重新傳送訊息。啟用僅傳送一次的訂閱項目不會收到重複的訊息。
發布商重複傳送訊息。發布者因應用程式邏輯而傳送訊息兩次。Pub/Sub 服務會將這些訊息視為不同的 Pub/Sub 訊息,並指派專屬訊息 ID。
如果訊息 ID 相同,表示 Pub/Sub 重新傳送或重新傳遞訊息。如果訊息 ID 不同,表示重複訊息是在發布端上游產生。
已過期的確認期限
如果訂閱端無法在確認期限內確認訊息,Pub/Sub 通常會重複傳送訊息。導致郵件重新傳送,造成重複傳送的假象。您可以使用 subscription/expired_ack_deadlines_count 指標,評估訂閱者錯過確認期限的比率。進一步瞭解如何監控確認期限到期情形。
如要降低重複率,請延長訊息期限。
- 用戶端程式庫會自動處理期限延長作業,但您可以設定的延長期限上限有預設限制。
- 如果您要建構自己的用戶端程式庫,請使用
modifyAckDeadline方法延長確認期限。
如果訂閱者提取訊息的速度快於處理和確認訊息的速度,部分訊息可能會過期,需要延長期限。不過,如果訂閱端仍無法處理,重複延長期限最終會失敗。最糟糕的情況下,這可能會導致訂閱者充斥重複訊息,加劇待處理工作量。過期的重複項目,然後產生新的重複項目。
為避免訂閱者不堪負荷,請減少訂閱者一次提取的訊息數量。這樣一來,訂閱者在期限內要處理的訊息就會減少。訊息到期和重新傳送的次數減少。
如要減少訂閱者一次提取的訊息數量,請在訂閱者的流量控制設定中,降低未處理訊息數量上限。沒有一體適用的值,因此您必須根據處理量和訂閱者容量,調整未完成訊息數量上限。請注意,每個應用程式處理訊息的方式不同,確認訊息所需的時間也不同。
強制重試
如要強制 Pub/Sub 重試訊息,請傳送 nack 要求。如果您並非使用高階用戶端程式庫,請傳送 modifyAckDeadline 要求,並將 ackDeadlineSeconds 設為 0。
排序鍵
Pub/Sub 重新傳送含有排序鍵的訊息時,也會重新傳送後續所有含有相同排序鍵的訊息,即使這些訊息先前已確認也一樣。這是為了保留序列的順序。不過,系統無法嚴格保證,只有在成功確認序列中的先前訊息後,才會傳送依附訊息。
訂閱者正在傳送訊息的否定確認
請參閱「訂閱者對訊息發出 NACK」。
跳轉作業
對時間戳記或快照執行搜尋作業時,Pub/Sub 會重新傳送在時間戳記後發布或包含在快照中的訊息。即使訂閱項目已啟用「僅一次」傳遞功能,仍會發生這種重新傳遞行為。詳情請參閱「使用『僅傳送一次』功能搜尋」。
下游簡化
訂閱者和其他下游系統可能會簡化訊息。例如,Dataflow 支援僅一次傳遞。如果下游意外出現重複訊息,原因可能在於訂閱者,而非 Pub/Sub。
排解 StreamingPull 訂閱項目問題
要求延遲時間指標與端對端傳送延遲時間之間的關係
如果是 StreamingPull,指標 serviceruntime.googleapis.com/api/request_latencies 代表串流開啟的時間。這項指標無法用來判斷端對端傳送延遲時間。
請改用傳遞延遲時間健康狀態分數,檢查哪些因素導致端對端傳遞延遲時間增加。
StreamingPull 連線關閉,狀態並非「OK」
StreamingPull 串流一律會以非 OK 狀態關閉。與一元 RPC 的錯誤狀態不同,StreamingPull 的這個狀態只是表示串流已中斷連線。要求並未失敗。因此,雖然 StreamingPull API 的錯誤率可能高達 100%,但這是正常現象。
StreamingPull 串流一律會因錯誤而關閉,因此在診斷錯誤時,檢查串流終止指標並無幫助。請改為著重於 StreamingPull 回應指標 subscription/streaming_pull_response_count,並依 response_code 或 response_class 分組。
請留意下列錯誤:
如果訂閱項目待處理訊息是以停用的 Cloud KMS 金鑰加密,就可能發生「Failed precondition」(未符合先決條件) 錯誤。如要繼續提取,請還原金鑰存取權。
如果 Pub/Sub 無法處理要求,可能會發生無法使用錯誤。這極有可能是暫時情況,用戶端程式庫會重試要求。如果您使用的是用戶端程式庫,則無須採取任何行動。
如果訂閱項目遭到刪除或根本不存在,就可能發生找不到錯誤。如果提供的訂閱路徑無效,就會發生後者的情況。