本頁面說明如何使用 Pub/Sub 的「一次性」功能接收及確認訊息,以便追蹤及避免重複處理訊息。啟用這項功能後,Pub/Sub 會提供下列語意:
訂閱者可以判斷訊息是否已成功收到確認。
訊息成功確認後,系統不會重新傳送。
訊息未送達時不會重新傳送。在確認期限到期或訊息已確認前,系統會將訊息視為未解決。
如果有多個有效的傳送作業,由於確認期限已過或用戶端啟動的否定確認,只有最新的確認 ID 才能用於確認郵件。任何含有先前確認 ID 的要求都會失敗。
啟用「僅需處理一次」後,訂閱者只要遵循下列指南,即可確保訊息只會處理一次:
在確認期限內確認訊息。
保留訊息處理進度的相關資訊,直到訊息成功確認為止。
使用訊息處理進度的相關資訊,以免在確認失敗時重複執行工作。
只有提取訂閱類型支援確切一次傳送,包括使用 StreamingPull API 的訂閱者。推送和匯出訂閱項目不支援僅傳送一次。
Pub/Sub 支援在雲端區域內,根據 Pub/Sub 定義的唯一訊息 ID 傳送一次訊息。
建議的用戶端程式庫版本
- 為獲得最佳效能,請使用最新版本的用戶端程式庫:Python v2.13.6 以上版本、Java v1.139.0 以上版本、PHP v1.39.0 以上版本、C# v3.2.0 以上版本、C++ v2.1.0、Go v1.25.1 以上版本、Node v3.2.0 以上版本 和 Ruby v2.12.1 以上版本。
再次傳送與重複
請務必瞭解預期和非預期的重新放送之間的差異。
重新傳送的原因可能是用戶端對訊息發出負面確認,或是用戶端未在訊息確認期限到期前延長訊息的確認期限。系統會將重送視為有效,並視為正常運作。
如要排解重新提交的問題,請參閱「處理重複項目」。
重複訊息是指在成功收到確認訊息後,或在確認期限到期前,重新傳送的訊息。
重送的郵件會在重送嘗試之間保留相同的郵件 ID。
啟用「僅傳送一次」的訂閱項目不會收到重複的傳送內容。
用戶端程式庫支援「僅傳送一次」
支援的用戶端程式庫具有回應確認介面 (例如 Go)。您可以使用這個介面,檢查確認要求是否成功。如果確認要求成功,用戶端就不會收到重送的內容。如果確認要求失敗,客戶可以預期會收到重新傳送的內容。
用戶端也可以不使用確認介面,使用支援的用戶端程式庫。不過,在這種情況下,確認失敗可能會導致訊息靜默重新傳送。
支援的用戶端程式庫具有可設定最小租用權延長時間的介面 (例如 Go)。您必須將最低租用期延長時間設為較高的值,以免發生任何網路相關的確認訊息到期問題。最大值設為 600 秒。
如果您使用 Java 用戶端程式庫,並使用
setChannelProvider()
方法透過自訂 gRPC 通道初始化訂閱者,建議您在建構TransportChannelProvider
時,將maxInboundMetadataSize
設為至少 1 MB。針對這項設定,您可以使用InstantiatingGrpcChannelProvider.Builder.setMaxInboundMetadataSize()
或ManagedChannelBuilder.maxInboundMetadataSize()
方法。
與一次一送相關的變數預設值和範圍,以及變數名稱,在不同用戶端程式庫中可能有所不同。舉例來說,在 Java 用戶端程式庫中,下列變數會控制精確一次提交。
變數 | 說明 | 值 |
---|---|---|
setEnableExactlyOnceDelivery |
啟用或停用「僅傳送一次」功能。 | true 或 false,預設值為 false |
minDurationPerAckExtension |
延長修改確認期限時,最短可使用的秒數。 | 範圍:0 到 600。預設值:無 |
maxDurationPerAckExtension |
延長修改確認期限的時間上限 (以秒為單位)。 | 範圍:0 到 600。預設值:無 |
在「精確一次」傳送作業中,如果確認 ID 已過期,則向 Pub/Sub 提出的 modifyAckDeadline
或 acknowledgment
要求會失敗。在這種情況下,服務會將已過期的確認 ID 視為無效,因為較新的遞送作業可能已在進行中。這是為了確保一次只送達一次而設計的機制。接著,您會看到 acknowledgment
和 ModifyAckDeadline
要求傳回 INVALID_ARGUMENT
回應。當精確一次傳送功能遭到停用時,如果確認 ID 已過期,這些要求就會傳回 OK
。
為確保 acknowledgment
和 ModifyAckDeadline
要求具有有效的確認 ID,建議您將 minDurationPerAckExtension
的值設為較高的數字。
區域考量
只有在訂閱者連線至同一個區域的服務時,才會提供「僅傳送一次」的傳送保證。如果訂閱者應用程式分散在多個區域,即使啟用「僅傳送一次」傳送模式,仍可能導致重複傳送訊息。發布者可以將訊息傳送至任何區域,且仍可維持「一次一送」的保證。
當您在 Google Cloud中執行應用程式時,預設會連線至同區域中的 Pub/Sub 端點。因此,在 Google Cloud內的單一區域中執行應用程式,通常可確保您與單一區域互動。
當您在 Google Cloud以外或多個地區執行訂閱者應用程式時,您可以使用位置端點設定 Pub/Sub 用戶端,確保連線至單一地區。Pub/Sub 的所有位置端點都會指向單一區域。如要進一步瞭解位置端點,請參閱「Pub/Sub 端點」。如需 Pub/Sub 的所有位置端點清單,請參閱「位置端點清單」。
建立採用「僅傳送一次」的訂閱項目
您可以使用 Google Cloud 控制台、Google Cloud CLI、用戶端程式庫或 Pub/Sub API,建立具備「一次一送」功能的訂閱項目。
提取訂閱項目
控制台
如要建立確切一次傳送的拉取訂閱,請按照下列步驟操作:
在 Google Cloud 控制台中,前往「訂閱項目」頁面。
按一下「Create Subscription」 (建立訂閱項目)。
輸入「Subscription ID」(訂閱 ID)。
從下拉式選單中選擇或建立主題。
訂閱項目會接收主題的訊息。
在「僅傳送一次」專區中,選取「啟用僅傳送一次」。
按一下 [建立]。
gcloud
如要建立具備「僅傳送一次」傳送模式的拉取訂閱項目,請使用 gcloud pubsub subscriptions create
指令搭配 --enable-exactly-once-delivery
標記:
gcloud pubsub subscriptions create SUBSCRIPTION_ID \ --topic=TOPIC_ID \ --enable-exactly-once-delivery
更改下列內容:
- SUBSCRIPTION_ID:要建立的訂閱項目 ID
- TOPIC_ID:要附加至訂閱項目的主題 ID
REST
如要建立具備「僅傳送一次」功能的訂閱項目,請使用 projects.subscriptions.create
方法。
PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID Authorization: Bearer $(gcloud auth print-access-token)
更改下列內容:
- PROJECT_ID:要建立訂閱項目的專案 ID
- SUBSCRIPTION_ID:要建立的訂閱項目 ID
如要建立具備「僅傳送一次」功能的拉取訂閱項目,請在要求主體中指定這項功能:
{ "topic": "projects/PROJECT_ID/topics/TOPIC_ID", "enableExactlyOnceDelivery": true, }
更改下列內容:
- PROJECT_ID:含有主題的專案專案 ID
- TOPIC_ID:要附加至訂閱項目的主題 ID
C++
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 C++ 環境。詳情請參閱 Pub/Sub C++ API 參考說明文件。
C#
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 C# 環境。詳情請參閱 Pub/Sub C# API 參考說明文件。
Go
在試用這個範例之前,請先按照 快速入門:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 Pub/Sub Go API 參考說明文件。
Java
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 Java 環境。詳情請參閱 Pub/Sub Java API 參考說明文件。
Python
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 Python 環境。詳情請參閱 Pub/Sub Python API 參考說明文件。
Node.js
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 Node.js 環境。詳情請參閱 Pub/Sub Node.js API 參考說明文件。
Node.js
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 Node.js 環境。詳情請參閱 Pub/Sub Node.js API 參考說明文件。
Ruby
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的操作說明設定 Ruby 環境。詳情請參閱 Pub/Sub Ruby API 參考說明文件。
PHP
在嘗試這個範例之前,請先按照 快速入門:使用用戶端程式庫中的 PHP 設定說明進行操作。詳情請參閱 Pub/Sub PHP API 參考說明文件。
訂閱「僅傳送一次」訊息傳送功能
以下是使用用戶端程式庫訂閱精確一次傳送功能的程式碼範例。
提取訂閱項目
Go
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Go。詳情請參閱 Pub/Sub Go API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Java
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Java。詳情請參閱 Pub/Sub Java API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Node.js
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Node.js。詳情請參閱 Pub/Sub Node.js API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
PHP
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 PHP。詳情請參閱 Pub/Sub PHP API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Python
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Python。詳情請參閱 Pub/Sub Python API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Ruby
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Ruby。詳情請參閱 Pub/Sub Ruby API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
C++
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 C++。詳情請參閱 Pub/Sub C++ API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
C#
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 C#。詳情請參閱 Pub/Sub C# API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
Node.js (TypeScript)
在嘗試這個範例之前,請先按照 Pub/Sub 快速入門:使用用戶端程式庫中的操作說明設定 Node.js 環境。 詳情請參閱 Pub/Sub Node.js API 參考說明文件。
如要向 Pub/Sub 進行驗證,請設定應用程式預設憑證。詳情請參閱「為本機開發環境設定驗證機制」。
監控「僅傳送一次」訂閱項目
subscription/exactly_once_warning_count
指標會記錄可能導致重複送達 (有效或重複) 的事件數量。這項指標會計算 Pub/Sub 無法處理與確認 ID 相關聯的要求次數 (ModifyAckDeadline
或 acknowledgment
要求)。失敗的原因可能是伺服器或用戶端。舉例來說,如果用於維持「確切一次」傳送資訊的持久層無法使用,則會是伺服器型事件。如果用戶端嘗試使用無效的確認 ID 確認訊息,則會是用戶端事件。
瞭解指標
subscription/exactly_once_warning_count
會擷取可能或不可能導致實際重送的事件,並根據用戶端行為產生雜訊。舉例來說,重複的 acknowledgment
或 ModifyAckDeadline
要求含有無效的確認 ID,會不斷遞增指標。
下列指標也能協助您瞭解用戶端行為:
subscription/expired_ack_deadlines_count
指標會顯示已認證 ID 到期數量。確認 ID 到期可能會導致ModifyAckDeadline
和acknowledgment
要求失敗。service.serviceruntime.googleapis.com/api/request_count
指標可用於擷取ModifyAckDeadline
或acknowledgment
要求的失敗情形,也就是要求到達 Google Cloud 但未到達 Pub/Sub 的情況。這項指標不會記錄某些失敗情形,例如用戶端與 Google Cloud中斷連線。
在大多數可重試的失敗事件中,支援的用戶端程式庫會自動重試要求。
配額
僅傳送一次訂閱項目須遵守額外的配額規定。這些配額適用於:
- 在每個區域啟用精確一次傳送功能後,從訂閱項目消耗的訊息數量。
- 在每個區域使用啟用「僅傳送一次」功能的訂閱項目時,已確認或延長期限的訊息數量。
如要進一步瞭解這些配額,請參閱「配額」主題中的表格。
僅傳送一次遞送和訂閱排序
Pub/Sub 支援有序傳送,以便實現「僅傳送一次」的傳送方式。
使用排序與「僅傳送一次」傳送模式時,Pub/Sub 會預期確認訊息會依序傳送。如果確認訊息順序錯誤,服務就會以暫時性錯誤拒絕要求。如果確認期限在傳送訊息的順序確認之前到期,用戶端就會收到重新傳送的訊息。因此,當您使用排序與確切一次傳送功能時,用戶端傳輸量就會限制為每秒一千則訊息的排序。
僅傳送一次和推送訂閱
Pub/Sub 僅支援使用提取訂閱項目的「僅傳送一次」傳送方式。
使用推播訂閱項目訊息的用戶端會透過回應推播要求的成功回應,確認訊息。不過,用戶端無法得知 Pub/Sub 訂閱是否收到回應並加以處理。這與拉取訂閱不同,後者是由用戶端發出確認要求,而 Pub/Sub 訂閱會在要求成功處理時回應。因此,「僅傳送一次」的語意與推送訂閱不太相容。
注意事項
如果在建立訂閱項目時未指定確認期限,啟用「僅傳送一次」的訂閱項目預設確認期限為 60 秒。
延長預設的確認回應期限,有助於避免因網路事件而導致的重新傳送。支援的用戶端程式庫不會使用預設的訂閱確認期限。
與一般訂閱項目相比,「僅傳送一次」訂閱項目的發布端到訂閱端延遲時間會大幅增加。
如果您需要高處理量,則精確傳送用戶端也必須使用串流提取。
即使啟用「僅傳送一次」功能,訂閱項目仍可能會收到多個相同訊息的副本,這是因為發布端重複發布。發布端重複內容可能是因為發布用戶端或 Pub/Sub 服務重試多次。發布端用戶端在重試時發布多個不重複的訊息,導致重送訊息時使用不同的 訊息 ID。Pub/Sub 服務會針對用戶端發布要求,發布多則不重複的訊息,導致重複傳送相同的訊息 ID。
您可以重試
subscription/exactly_once_warning_count
中的失敗項目,支援的用戶端程式庫會自動重試這些項目。不過,如果失敗原因是無效的確認 ID,就無法重試。