本页面介绍了如何使用“正好一次”语义接收和确认消息。只有拉取订阅类型支持正好一次传送,包括使用 StreamingPull API 的订阅者。
推送和导出订阅不支持正好一次传送。
推荐的客户端库版本
- 为获得最佳性能,请使用最新版本的客户端库、Python v2.13.6 或更高版本、Java v1.120.11 或更高版本、PHP v1.39.0 或更高版本、C# v3.2.0 或更高版本、C++ v2.1.0
仅传送一次
Pub/Sub 支持根据 Pub/Sub 定义的唯一消息 ID 在云区域内仅传送一次。
启用此功能后,Pub/Sub 会提供以下功能:
成功确认消息后,不会发生重新传送。
邮件未完成时不会重新传送。在确认时限到期或确认之前,消息被视为未完成。
如果有多个有效传送,则由于确认截止日期到期或客户端发起的否定确认,只能使用最新的确认 ID 来确认消息。任何具有之前的确认 ID 的请求都会失败。
重新提交与重复提交
请务必了解预期重新提交次数和意外重新提交次数之间的差异。
如果客户端针对消息发起了否定确认,或者客户端未在确认截止期限之前延长消息的确认期限,就可能发生重新传送。重新提交订单被视为有效,且系统按预期运行。
如需排查重新提交问题,请参阅处理重复项并强制重试。
“重复”是指消息在成功确认后或确认截止期限到期之前重新发送。
重新提交的邮件会在两次尝试重新传送之间保留相同的邮件 ID。
启用了“仅传送一次”的订阅不会收到重复传送的内容。
客户端库中的“正好一次传送”支持
受支持的客户端库具有一个通过响应进行确认的接口(例如:Go)。您可以使用此接口检查确认请求是否成功。如果确认请求成功,则保证客户端不会收到重新传送。如果确认请求失败,客户端可能会收到重新传送消息。
客户端也可以在没有确认接口的情况下使用受支持的客户端库。然而,在这种情况下,确认失败可能会导致消息重新传送但不发出提示。
受支持的客户端库具有用于设置最短租期延长时间的接口(例如:Go)。您必须将最小租期扩展的值设置为较大的数字,以避免任何与网络相关的确认失效。最大值设为 600 秒。
与“正好一次”传送相关的变量的默认值和范围以及这些变量的名称可能因客户端库而异。例如,在 Java 客户端库中,以下变量控制正好一次传送。
变量 | 说明 | 值 |
---|---|---|
setEnableExactlyOnceDelivery |
启用或停用“仅传送一次”。 | true 或 false Default=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 控制台、Google Cloud CLI、客户端库或 Pub/Sub API 创建“仅传送一次”的订阅。
拉取订阅
控制台
如需创建只有传送一次的拉取订阅,请按以下步骤操作:
在 Google Cloud 控制台中,进入订阅页面。
点击创建订阅。
输入订阅 ID。
从下拉菜单中选择或创建一个主题。
订阅将接收来自该主题的消息。
在仅传送一次部分,选择启用“仅传送一次”。
点击创建。
gcloud
如需创建只有传送一次的拉取订阅,请使用带有 --enable-exactly-once-delivery
标志的 gcloud pubsub subscriptions create
命令:
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
会捕获可能导致实际重新提交的事件,也可能没有噪声,具体取决于客户端行为。例如,重复的确认 ID 无效的 acknowledgment
或 ModifyAckDeadline
请求会反复递增指标。
以下指标也有助于了解客户端行为:
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 订阅会进行响应。因此,“正好一次”传送语义与推送订阅不太一致。
注意事项
如果未在 CreateSubscription 时指定确认时限,则仅一次启用了传送的订阅将默认确认时限为 60 秒。
较长的默认确认截止期限有助于避免网络事件导致的重新传送。受支持的客户端库不使用默认的订阅确认截止期限。
与常规订阅相比,“仅传送一次”订阅的发布到订阅延迟时间明显更长。
如果您需要高吞吐量,您的“正好一次”传送客户端还必须使用流式拉取。
即使启用了“仅传送一次”功能,订阅也可能因为发布端重复而收到同一消息的多个副本。发布端重复的原因可能是发布客户端或 Pub/Sub 服务多次重试了唯一发布。发布客户端多次进行重试后,会导致使用不同的消息 ID 重新提交。Pub/Sub 服务为响应客户端发布请求而进行多次唯一发布会导致重新提交具有相同消息 ID 的请求。
您可以在
subscription/exactly_once_warning_count
中重试失败的测试,受支持的客户端库会自动重试这些失败的操作。但是,与无效确认 ID 相关的失败无法重试。