排查拉取订阅问题

本文档提供了有关 Pub/Sub 拉取订阅的一些常见问题排查提示。如需详细了解拉取订阅,请参阅拉取订阅者指南

为了有效地监控您的 Pub/Sub 订阅,建议您先查看传送延迟时间健康状况得分 (subscription/delivery_latency_health_score),以检查哪些因素可能会导致延迟时间出现意外或增加。

最早的未确认消息的存在时长不断增加

oldest_unacked_message_age 是监控 Pub/Sub 订阅运行状况的关键指标。它测量订阅积压中尚未由订阅者确认(确认)的最旧消息的存在时间(以秒为单位)。该指标可针对潜在的处理延迟或瓶颈提供有价值的数据洞见。

监控消息积压可确保及时、高效地处理消息。通过跟踪最早的未确认消息的存在时间,您可以主动发现消费者落后的情况。通过这种方式,您可以及早进行干预,以解决与性能下降有关的潜在问题。

以下是一些您可以调查的常见积压问题

客户端配置问题

oldest_unacked_message_agenum_undelivered_messages 指标同时增加时,可能意味着订阅者无法跟上消息量。在这种情况下,请将调查重点放在订阅者组件上:

  • 客户端健康状况:分析托管订阅者客户端的机器上的资源利用率,例如 CPU、内存和网络带宽。查找可能阻碍处理效率的压力点。

  • 客户端代码:查看最近的代码更改并检查错误日志。订阅者代码中存在错误或低效会严重影响消息处理速率。请注意,特定消息可能存在问题。例如,多条消息可能需要同时访问数据库中的同一行。此行为可能会导致争用和高延迟。

  • 配额限制:验证您是否未超出托管服务施加的任何 Pub/Sub 配额或限制。如果订阅者托管在 Google Cloud 中,请查看 Compute EngineGKE 的资源配额,以防止潜在的瓶颈。

订阅者已否定消息

当订阅者否定消息(NACK)时,它会向 Pub/Sub 发出无法成功处理该消息的信号。然后,Pub/Sub 会尝试重新传送相同的消息。针对邮件重复添加 nack 会导致重复,并可能导致邮件递送出现长时间延迟。

请注意,通过 NACK 并不能保证下一次拉取会提取不同的消息。Pub/Sub 的重新提交政策可能会继续在发送新消息之前重新提交 NACK 消息。因此,请勿依赖 NACK 作为过滤或跳过特定消息的方法。而应设置重试政策(最好是指数退避算法),以便退回可能稍后可处理但在重新提交前需要较长时间的个别邮件。

如果您需要有意跳过某些消息,建议的方法是确认这些消息,即使您并未处理这些消息。这样做可以将其从订阅中移除,避免不必要的重新提交,并减少资源消耗。无论是否有意地让邮件未确认,都会造成积压问题并造成重复递送。

传送延迟时间较长

Pub/Sub 中的传送延迟时间是指来自发布者的消息到达订阅者所需的时间。以下部分介绍了可能导致传送延迟较长的原因。

订阅人数不足

对于使用 StreamingPull 的客户端,为了持续实现低延迟,请为订阅维持多个打开的 StreamingPull 连接。如果没有活跃的订阅者连接,Pub/Sub 将无法及时传送消息。单个数据流可能发生单点故障,从而增加了延迟风险。您可以通过 subscription/open_streaming_pulls 指标了解活跃的流式传输连接的数量。使用此方法可确保您始终有足够的视频流来处理传入的消息。

对于使用一元拉取的客户端,为了持续实现低延迟,请为订阅维护多个待处理的拉取请求。不频繁的请求可能会积压积压中的消息,并增加延迟时间。这种方法有助于最大限度地减少连接缺口并缩短传送延迟时间。

如果您需要高吞吐量、低延迟,同时尽可能减少运营开销和处理成本,则建议您使用高级客户端库。默认情况下,高层级客户端库使用 StreamingPull API,因为它往往是最大限度地缩短延迟时间的更好选择。高级客户端库包含预构建的函数和类,用于处理底层 API 调用,以实现身份验证、吞吐量和延迟时间优化、消息格式设置以及其他功能。

客户端配置问题

请参阅客户端配置问题

积压高

请注意,Pub/Sub 订阅中未确认的消息积压的消息会固有增加端到端延迟时间,因为订阅者不会立即处理消息。

订购密钥和仅传送一次

排序键和“正好一次”传送是有价值的功能,但在 Pub/Sub 中需要额外的协调才能确保正确传送。这种协调可以降低可用性并增加延迟时间。虽然在稳定状态下的差异很小,但任何必要的协调步骤都可能会导致延迟时间暂时增加或错误率增加。如果启用了排序,则在具有相同排序键的消息被 ACK 之前,无法传递具有排序键的消息。

考虑消息排序或正好传送一次对于您的应用是否必不可少。如果您优先考虑缩短延迟时间,请尽量减少使用这些功能有助于减少消息处理延迟时间。

邮件大小变大

消息大小突然增加可能会增加 Pub/Sub 与客户端之间的传输时间,并减慢客户端中的消息处理时间。

如果您发现递送延迟时间增加,可以使用 topic/message_sizes 指标(按 topic_id 分组)查看邮件大小。将消息大小的任何峰值与观察到的性能问题相关联。

丢失的消息

如果您怀疑消息未成功传送给订阅者,可能是以下某个原因导致的。

具有多个使用方的 Pub/Sub 订阅中的消息分发

在 Pub/Sub 中,消息可能会在使用方之间不均匀分布。出现此行为的原因是 Pub/Sub 在活跃使用方之间分配消息以提高效率。有时,单个使用方收到的消息数量可能少于预期,或者只接收一部分消息,而不是其他使用方。

请注意,对客户端而言,消息可能已经未完成,积压的未确认消息不一定表示您会在下一个拉取请求中收到这些消息。请注意,使用方可能是使用 Google Cloud 控制台或 Google Cloud CLI 中的拉取功能,或在本地运行自定义订阅者来检查消息的人员。

对于一元拉取客户端,您可能会观察到一些拉取请求返回零消息。如没有足够的订阅者部分中所述,建议保留多个未完成的拉取请求,因为某些请求返回的消息数可能少于配置的最大消息数,甚至为零消息。

如果您怀疑存在上述任何行为,请调查是否有多个使用方同时附加到订阅并对其进行检查。

按订阅过滤

检查订阅是否附加了过滤条件。这种情况下,您只会收到与过滤器匹配的邮件。Pub/Sub 服务会自动确认与过滤条件不匹配的消息。考虑过滤条件如何影响积压指标

使用 returnImmediately 选项

如果您的客户端使用的是一元拉取,请检查 returnImmediately 字段是否设置为 true。这是一个已弃用的字段,用于告知 Pub/Sub 服务立即响应拉取请求,即使它没有返回任何消息也是如此。即使出现积压,这也会导致拉取请求返回 0 条消息。

处理重复的联系人

如果订阅者无法在确认时限内确认消息,通常就会出现 Pub/Sub 中的消息重复情况。这会导致邮件重新提交,从而产生重复的印象。您可以使用 subscription/expired_ack_deadlines_count 指标来衡量订阅者错过确认时限的比率。详细了解如何监控确认截止期限

如需降低重复率,请延长消息截止时间。

  • 客户端库会自动处理截止期限延长,但是您可以配置最长延长期限有默认限制。
  • 如果您要构建自己的客户端库,请使用 modifyAckDeadline 方法延长确认时限。

如果从订阅程序中拉取消息的速度快于处理和确认消息的速度,则某些消息可能会过期并需要延长期限。然而,如果订阅者仍不堪重负,多次延期最终最终会失败。在最糟糕的情况下,这可能会导致订阅者中充斥着重复内容,加剧积压。到期重复项将生成新的重复项。

为避免订阅者应接不暇,请减少订阅者每次拉取的消息数。这样,订阅者在截止时间内要处理的消息就会减少。过期的消息变少,重新提交的消息也变少。

如需减少订阅者同时拉取的消息数,您需要在订阅者的流控制配置中降低未完成消息数上限设置。没有放之四海而皆准的值,因此您必须根据吞吐量和订阅者容量来调整未完成消息的数量上限。请注意,每个应用处理消息的方式各不相同,并且确认消息所用的时间也不同。

强制重试

如需强制 Pub/Sub 重试消息,请发送 nack 请求。如果您使用的不是高级客户端库,请发送 modifyAckDeadline 请求,并将 ackDeadlineSeconds 设为 0。

排序键

当 Pub/Sub 重新提交具有排序键的消息时,它还会使用同一排序键重新传送所有后续消息,即使这些消息之前已得到确认也是如此。这样做是为了保持该序列的顺序。但是,并不严格保证相关消息仅在成功确认序列中的先前消息后才会发送。

订阅者通过 NACK 处理消息

请参阅订阅者正在接收消息

排查 StreamingPull 订阅问题

StreamingPull 流始终以不正常状态关闭。与一元 RPC 的错误状态不同,StreamingPull 的此状态仅表示数据流已断开连接。请求未失败。因此,虽然 StreamingPull API 错误率可能达到令人惊讶的 100%,但这种行为是设计上的。

由于 StreamingPull 流始终以错误关闭,因此在诊断错误时检查数据流终止指标并没有帮助。相反,请专注于按 response_coderesponse_class 分组的 StreamingPull 响应指标 subscription/streaming_pull_response_count

请查找以下错误:

  • 如果订阅积压中有消息使用已停用的 Cloud KMS 密钥加密,则可能会出现不满足前提条件错误。如需恢复拉取,请恢复对密钥的访问权限

  • 如果 Pub/Sub 无法处理请求,则可能会发生不可用错误。这很可能是一种暂时情况,客户端库会重试请求。如果您使用的是客户端库,则无需执行任何操作。

  • 如果订阅被删除或最初不存在,则可能会出现“未找到”错误。如果您提供的订阅路径无效,就会出现后一种情况。