如果您在使用 Pub/Sub 时遇到问题,可查阅以下实用的问题排查步骤。
无法创建订阅
检查您是否已完成以下操作:
- 在
name
字段中指定订阅名称。对于版本 v1beta2 及更高版本,订阅名称必须采用projects/project-identifier/subscriptions/subscription-name
格式。 - 在
topic
字段中指定要订阅的现有主题的名称。对于版本 v1beta2 及更高版本,主题名称必须采用projects/project-identifier/topics/topic-name
格式。 - 在
pushEndpoint
字段中以小写字母指定https://
(而不是http://
或HTTPS://
)作为接收网址的协议。
推送订阅者接收不到任何消息
请检查以下各项:
- 在 Cloud Monitoring 中查找与订阅有关的错误。
- 在 App Engine 上,建议您在端点网址路径中使用
/_ah/push-handlers/
前缀,如注册 App Engine 端点中所述。此代码允许端点从 Pub/Sub API 接收推送消息。 - 在其他环境中,请确保无需登录即可从互联网访问您的端点网址。您可以通过使用诊断工具(如 cURL)访问网址来检查该网址是否受限制。
- 对于除
appspot.com
之外的网域,请确保在 Google Cloud Console 中注册该网域。如需了解详情,请参阅注册其他端点。
推送消息的传送时间会延迟数小时
一条未确认的推送消息可能会导致新消息延迟传送。如果推送端点发生故障或返回的状态代码不是 200
、201
、202
、204
或 102
,则系统不会确认消息。为了避免延迟,请更新端点代码以处理失败的消息,或手动拉取这些消息,然后确认。如需详细了解如何检测未确认的消息以及如何创建提醒,请参阅 Monitoring 概览。
403 (Forbidden)
错误
如果遇到此错误,请执行以下操作:
- 确保您已在 Cloud Console 中启用了 Pub/Sub API。
- 确保发出请求的主帐号对相关 Pub/Sub API 资源具有所需权限,尤其是在您使用 Pub/Sub API 进行跨项目通信时。
- 如果您使用的是 Dataflow,请确保
<projectId>@cloudservices.gserviceaccount.com
和 Compute Engine 服务帐号<projectId>-compute@developer.gserviceaccount.com
对相关 Pub/Sub API 资源都具有所需权限。如需了解详情,请参阅 Dataflow 安全和权限。 - 如果您使用的是 App Engine,请检查项目的权限页面,查看 App Engine 服务帐号是否被列为编辑者。如果不是,请将您的 App Engine 服务帐号添加为编辑者。通常情况下,App Engine 服务帐号的格式为
<project-id>@appspot.gserviceaccount.com
。
处理重复项并强制重试
如果您在确认时限之前未确认消息,Pub/Sub 会重新发送该消息。因此,Pub/Sub 可能会发送重复的消息。请使用 Google Cloud 的操作套件来监控具有 expired
响应代码的确认操作以检测此情况。如需获取此数据,请选择确认消息操作指标,然后按 response_code
标签对其进行分组或过滤。请注意,response_code
是指标上的系统标签,不是指标。

为了降低重复率,请延长消息时限。
- 客户端库会自动延长时限,但您应注意,可配置的最大延长时限有默认限制。
- 如果要构建自己的客户端库,请使用
modifyAckDeadline
方法延长确认时限。
或者,如需强制 Pub/Sub 重试消息,请将 modifyAckDeadline
设置为 0。
发布操作失败并显示 DEADLINE_EXCEEDED
这可能是客户端瓶颈导致的,例如服务 CPU 不足,线程运行状况不佳或网络拥塞。如果 Publish
调用返回 DEADLINE_EXCEEDED
,则异步 Publish
调用加入队列的速度比它们被发送到服务的速度更快,这会逐渐增加请求延迟时间。要针对不同参数(核心、工作器、消息大小)确定单个虚拟机的 Publish
吞吐量,请参阅测试 Cloud Pub/Sub 客户端以最大限度地提升流式传输性能。或者,您可能运行了某个具有已知问题的客户端库版本;请从下表中查看您的客户端库对应的问题跟踪器。
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
最后,您可以将截止时间设置为低于 Pub/Sub 的典型发布延迟时间(建议将初始截止时间设置为 10 秒,总超时设置为 600 秒)。
检查以下各项以帮助解决问题:
- 检查发布消息的速度是否快于客户端发送消息的速度。通常,每个异步
Publish
调用都会返回一个Future
对象。要跟踪等待发送的消息数量,请存储要通过此发布调用发送的消息数量,并仅在Future
对象的回调中将其删除。如果您进行Publish
调用的速度超过发送到 Pub/Sub 服务的请求能完成的速度,后续Publish
调用的延迟时间将大幅增加。 - 检查运行发布者的机器与 Google Cloud 之间是否有足够的上传带宽。用于开发的 WiFi 网络通常具有 1-10MB/s 的带宽,即每秒 1000-10000 条典型消息。在不限速的情况下循环发布这些消息可能会导致短时间内出现短暂的突发高带宽。您可以通过在 GCP 内的机器上运行发布者或降低发布消息的速率以匹配可用带宽来获得更多带宽。
- 请确保您为重试设置中定义的调用设置了足够长的超时。 即使您没有积累大量积压的未发送消息,也会出现请求延迟时间高峰导致错误的情况。将初始截止时间增加到 10 秒并将总超时增加到 600 秒会使超时率下降。请注意,如果您的问题是由持续的瓶颈(而非偶尔的超时)造成的,则重试次数越多,错误就越多。
- 检查您的主机和 Google Cloud 之间是否存在因启动网络拥塞或防火墙等原因造成的超长延迟时间。计算网络吞吐量提供了在不同场景下查找带宽和延迟时间的指南。
- 升级到最新版本的客户端库。确保您安装了所有相关更新,这些更新可能进行提升性能等修复。
- 检查托管发布者客户端的虚拟机是否资源不足,包括 CPU、RAM 和线程。有可能是调用在实际向服务发出请求之前一直在等待被安排。
- 归根结底,一个机器能发布的数据量有限。您可能需要尝试横向扩展或在多个机器上运行发布者客户端的多个实例。测试 Cloud Pub/Sub 客户端以最大限度地提升流式传输性能展示了 Pub/Sub 如何通过增加 CPU 数量在单个 Google Cloud 虚拟机上进行扩展。例如,对于 1KB 大小的消息,16 核 Compute Engine 实例可以达到 500 MB/s 到 700 MB/s 的传输速率。
使用过多的管理操作
如果您发现占用了过多管理操作配额,可能需要重构代码。例如,请参考下面的伪代码。在此示例中,管理操作 (GET
) 用于在尝试使用其资源之前检查是否存在订阅。GET
和 CREATE
都是管理操作:
if !GetSubscription my-sub { CreateSubscription my-sub } Consume from subscription my-sub
更有效的模式是尝试使用订阅中的消息(假设您可以合理地确定订阅名称)。在这种乐观方式中,您只能在发生错误时获取或创建订阅。请参考下面的示例:
try { Consume from subscription my-sub } catch NotFoundError { CreateSubscription my-sub Consume from subscription my-sub }