如果您在使用 Pub/Sub 时遇到问题,可查阅以下实用的问题排查步骤。
无法创建主题
验证您是否拥有必要的
权限。
如需创建 Pub/Sub 主题,您需要
对项目具有 Pub/Sub Editor (roles/pubsub.editor) Identity and Access Management
角色。如果您没有此角色,请与您的管理员联系。
如需了解有关主题的更多问题排查信息,请参阅以下页面:
无法创建订阅
检查您是否已执行以下操作:
验证您是否拥有必要的 权限。 如需创建 Pub/Sub 订阅,您需要 对项目具有 Pub/Sub Editor (roles/pubsub.editor) IAM 角色。 如果您没有此角色,请与您的管理员联系。
为订阅指定了名称。
指定了要将订阅附加到的现有主题的名称。
如果创建推送订阅,请在
pushEndpoint字段中以小写字母指定https://(而不是http://或HTTPS://)作为接收网址的协议。
如需了解有关订阅的更多问题排查信息,请参阅以下页面:
排查 拉取、 推送、 BigQuery、 或 Cloud Storage 问题
排查权限问题
Pub/Sub 权限控制哪些用户和服务账号可以对您的 Pub/Sub 资源执行操作。如果权限配置错误,可能会导致权限被拒错误并中断消息流。 审核日志会详细记录所有权限更改,以便您确定这些问题的来源。
如需使用审核日志排查 Pub/Sub 权限问题,请执行以下操作:
获取查看Logs Explorer 所需的权限。
如需了解更多信息,请参阅准备工作。
在 Cloud de Confiance 控制台中,前往 Logs Explorer 页面。
选择现有的 Cloud de Confiance 项目、文件夹或组织。
以下是可用于查找相关日志的过滤条件列表:
resource.type="pubsub_topic" OR resource.type="pubsub_subscription": 在排查可能涉及主题或订阅配置更改 或访问权限控制的任何问题时,请以此查询作为起点。您可以将其与其他过滤条件结合使用,以进一步优化搜索。protoPayload.methodName="google.iam.v1.SetIamPolicy":当您怀疑问题是由权限不正确或缺失引起的时,请使用此查询。它可以帮助您跟踪谁对 IAM 政策进行了更改以及这些更改的内容。这对于排查以下问题非常有用:用户无法发布到主题或订阅,应用被拒绝访问 Pub/Sub 资源,或访问权限控制发生意外更改。protoPayload.status.code=7:当您遇到与权限明确相关的错误时,请使用此查询。这有助于您确定哪些操作失败以及谁在尝试执行这些操作。您可以将此查询与之前的查询结合使用,以确定可能导致权限被拒的特定资源和 IAM 政策更改。
分析日志以确定事件的时间戳、进行更改的主账号以及所做更改的类型等因素。
根据从审核日志中收集的信息,您可以采取纠正措施。
排查 Terraform 权限问题
将 Pub/Sub 与 Terraform 搭配使用时,请在 Terraform 代码中明确授予所需的角色。例如,对于发布,您应用的服务帐号需要 roles/pubsub.publisher 角色。如果未在 Terraform 代码中明确定义此角色,则将来的 terraform apply 可能会将其移除。这种情况通常发生在不相关的更新期间,导致可靠的应用突然因 PERMISSION_DENIED 错误而失败。
在代码中明确定义角色可以防止这些意外的回归。
订阅被删除
Pub/Sub 订阅可以通过两种主要方式删除:
具有足够权限的用户或服务帐号有意删除订阅。
订阅会在一段时间(默认情况下为 31 天)无活动后自动删除。如需详细了解订阅 到期政策,请参阅到期期限。
如需排查已删除的订阅问题,请执行以下步骤:
在 Cloud de Confiance 控制台中,前往 Pub/Sub 订阅 页面,并验证订阅是否不再列出。 如需详细了解如何列出订阅, 请参阅列出订阅。
查看审核日志。前往 Logs Explorer 。 使用过滤条件
protoPayload.methodName="google.pubsub.v1.Subscriber.DeleteSubscription"查找已删除的订阅。检查日志以确定是有人删除了订阅,还是由于无活动而删除了订阅。InternalExpireInactiveSubscription表示订阅因无活动而被删除。 如需详细了解如何使用审核日志进行问题排查,请参阅 使用审核日志排查 Pub/Sub 问题。
403 (Forbidden) 错误
403 错误通常表示您没有执行操作的正确权限。例如,当您尝试发布到主题或从订阅中拉取时,可能会收到 403 User not authorized 错误。
如果遇到此错误,请执行以下操作:
- 确保您已在 Cloud de Confiance 控制台中启用 Pub/Sub API。
确保发出请求的主账号对相关 Pub/Sub API 资源具有 所需权限, 尤其是在您使用 Pub/Sub API 进行跨项目通信时。
如果您使用的是 Dataflow,请确保
{PROJECT_NUMBER}@cloudservices.s3ns-system.iam.gserviceaccount.com和 Compute Engine 服务账号{PROJECT_NUMBER}-compute@developer.s3ns-system.iam.gserviceaccount.com对相关 Pub/Sub API 资源都具有所需权限。 如需了解详情,请参阅 Dataflow 安全性和权限。如果您使用的是 App Engine,请检查项目的 权限页面,查看 App Engine 服务账号是否被 列为 Pub/Sub Editor。如果不是,请将您的 App Engine 服务账号添加为 Pub/Sub Editor。通常情况下, App Engine 服务账号的格式为
<project-id>@appspot.s3ns-system.iam.gserviceaccount.com。您可以使用审核日志来排查权限问题。
其他常见错误代码
如需查看与 Pub/Sub API 相关的其他常见错误代码 及其说明的列表,请参阅错误代码。
连接超时、延迟或网络错误
当 Pub/Sub 客户端应用尝试连接到 Cloud de Confiance by S3NS 服务时,您可能会遇到间歇性或持续性故障。这些问题可能表现为:
- 发布消息时出现严重延迟,可能会导致应用积压。
- 超时错误,例如 gRPC
DEADLINE_EXCEEDED、code = DeadlineExceeded或java.net.SocketTimeoutException。 - 网络 I/O 故障,例如
UNAVAILABLE: io exception或Connection refused错误,尝试访问pubsub.googleapis.com或oauth2.googleapis.com等服务时出现。
即使您未更改 Pub/Sub 配置或应用代码,也可能会出现这些连接问题。当本地或 VPC 防火墙对 Google API 使用硬编码的 IP 地址许可名单时,这种情况经常发生。Google 服务(包括 Pub/Sub 及其依赖项(如身份验证服务))使用动态 IP 地址范围。如果您的防火墙未考虑新的 IP 地址,则可能会阻止流向新 IP 地址的流量,从而导致连接和身份验证失败。
为确保连接稳定,请避免为 Google 服务使用基于静态 IP 的防火墙规则。请改用以下方法:
- 将防火墙配置为允许使用 Google 发布的默认网域 IP 范围(而不是硬编码的地址)的流量。如需了解如何获取 这些范围并自动更新防火墙规则,请参阅默认网域的 IP 地址。
- 启用 专用 Google 访问通道,这 允许 VPC 网络中的实例访问 Google API 和服务,而无需遍历公共互联网,从而简化防火墙 管理。
JWT 无效:令牌必须是短期令牌
如果您的应用与
Pub/Sub API 交互时收到类似 Invalid JWT: Token must be a short-lived token (60
minutes) and in a reasonable timeframe 的错误,这通常表示
身份验证凭据的时间存在问题。
此错误发生在验证用于对 API 请求进行身份验证的 JSON Web 令牌 (JWT) 期间。常见原因是运行 Pub/Sub 库的客户端机器与 Google 的身份验证服务器之间存在显著的时间差(时间偏差)。由于 JWT 的有效时间窗口有限,因此时钟差异可能会导致它们被视为已过期或尚未生效。
如需解决此问题,请同步客户端机器的时钟:
验证机器上的日期、时间和时区是否正确。
使用网络时间协议 (NTP) 服务保持系统时间同步,并验证该服务是否正在运行且配置正确。
使用过多的管理操作
如果您发现占用了过多
管理操作配额,
可能需要重构代码。例如,请参考下面的伪代码。在此示例中,管理操作 (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
}
您可以使用以下代码示例以您选择的语言实现此模式:
Go
以下示例使用 Go Pub/Sub 客户端库的主要版本 (v2)。如果您仍在使用 v1 库,请参阅 迁移到 v2 的指南。 如需查看 v1 代码示例的列表,请参阅 已废弃的代码示例。
在尝试此示例之前,请按照 《快速入门:使用客户端库》中的 Go 设置说明进行操作。 如需了解详情,请参阅 Pub/Sub Go API 参考文档。
Java
在尝试此示例之前,请按照《快速入门:使用客户端库》中的 Java 设置说明进行操作。 如需了解详情,请参阅 Pub/Sub Java API 参考文档。
Node.js
在尝试此示例之前,请按照《快速入门:使用客户端库》中的 Node.js 设置说明进行操作。如需了解详情,请参阅 Pub/Sub Node.js API 参考文档。
Node.ts
在尝试此示例之前,请按照 《快速入门:使用客户端库》中的 Node.js 设置说明进行操作。 如需了解详情,请参阅 Pub/Sub Node.js API 参考文档。
Python
在尝试此示例之前,请按照《快速入门:使用客户端库》中的 Python 设置说明进行操作。 如需了解详情,请参阅 Pub/Sub Python API 参考文档。
C++
在尝试此示例之前,请按照《快速入门:使用客户端库》中的 C++ 设置说明进行操作。如需了解详情,请参阅 Pub/Sub C++ API 参考文档。