本文档提供了一些常见的 Pub/Sub 拉取订阅问题排查提示。如需详细了解拉取订阅,请参阅拉取订阅者指南。
为了有效监控 Pub/Sub 订阅,建议您先查看传送延迟时间健康状况得分 (subscription/delivery_latency_health_score),以检查哪些因素可能会导致意外延迟或延迟时间增加。
最早的未确认消息的存在时间不断增加
oldest_unacked_message_age
是监控 Pub/Sub 订阅运行状况的重要指标。该指标衡量订阅积压工作中尚未由订阅者确认(已确认)的最早消息的存在时间(以秒为单位)。此指标可提供有关潜在处理延迟或瓶颈的重要数据洞见。
监控消息积压可确保及时高效地处理消息。通过跟踪最早的未确认消息的存在时长,您可以主动发现消费者未及时确认消息的情况。通过这种做法,您可以尽早干预,解决与性能下降相关的潜在问题。
您可以调查的一些积压常见问题包括:
客户端配置问题
如果 oldest_unacked_message_age
和 num_undelivered_messages
指标同时增加,则可能表示订阅者未跟上消息量。在这种情况下,请重点调查订阅方组件:
客户端运行状况:分析托管订阅方客户端的计算机上的资源利用率,例如 CPU、内存和网络带宽。找出可能影响处理效率的压力点。
客户端代码:查看近期的代码更改并检查错误日志。订阅者代码中的 bug 或效率低下可能会显著影响消息处理速率。请注意,特定邮件可能会出现问题。例如,多条消息可能需要同时访问数据库中的同一行。此行为可能会导致争用和高延迟。
配额限制:请检查您是否超出了任何 Pub/Sub 配额或托管服务施加的限制。如果订阅方托管在 Google Cloud 中,请查看 Compute Engine 或 GKE 资源配额,以防出现潜在瓶颈。
订阅者对消息发出了否定确认
当订阅者对消息发送否定确认 (nack) 时,会向 Pub/Sub 发出消息未能成功处理的信号。然后,Pub/Sub 会尝试重新传送同一消息。对消息重复发送 nack 会导致重复,并且可能会导致消息传送延迟时间过长。
请注意,取消订阅消息并不能保证下次拉取会提取其他消息。Pub/Sub 的重新传送政策可能会继续在有新消息之前重新传送未封装的消息。因此,请勿依赖 nack 来过滤或跳过特定消息。而是应设置重试政策(最好是指数退避),以便针对可能稍后可处理但需要稍长时间才能重新提交的个别消息进行退避。
如果您需要有意跳过某些消息,建议的方法是确认收到这些消息,即使您不会处理这些消息也是如此。这样可以将其从订阅中移除,避免不必要的重新提交,并减少资源消耗。无论有意还是无意,如果不确认消息,都会导致积压问题和重复传送。
传送延迟时间较长
Pub/Sub 中的传送延迟时间是指从发布者到订阅者传送消息所需的时间。以下部分介绍了导致传送延迟时间较长的一些可能原因。
订阅者数量不足
对于使用 StreamingPull 的客户端,为了实现始终如一的低延迟,请维持多个与订阅的打开式 StreamingPull 连接。如果没有有效的订阅者连接,Pub/Sub 将无法及时传送消息。单个数据流可能会成为单点故障,从而增加延迟的风险。subscription/open_streaming_pulls
指标可让您了解活跃的流式传输连接数量。使用此方法可确保您始终有足够的串流来处理传入的消息。
对于使用单个拉取操作的客户端,为了始终保持较低的延迟时间,请针对您的订阅维持多个待处理的拉取请求。请求不频繁可能会导致积压消息并增加延迟时间。这种方法有助于最大限度地减少连接中断,并缩短传送延迟时间。
如果您需要高吞吐量和低延迟时间,同时尽可能减少运营开销和处理费用,建议使用高级客户端库。默认情况下,高级客户端库使用 StreamingPull API,因为它通常是用于最大限度缩短延迟时间的更好选择。高级客户端库包含预构建的函数和类,用于处理底层 API 调用,以实现身份验证、吞吐量和延迟时间优化、消息格式设置和其他功能。
客户端配置问题
请参阅客户端配置问题。
积压高
请注意,Pub/Sub 订阅中未确认消息的消息积压会固有地增加端到端延迟时间,因为订阅者不会立即处理消息。
排序键和“仅传送一次”传送
排序键和“恰好一次”传送是十分有用的功能,但需要在 Pub/Sub 中进行额外的协调才能确保正确传送。这种协调可能会降低可用性并增加延迟时间。虽然在稳定状态下差异很小,但任何必要的协调步骤都可能会导致延迟时间暂时增加或错误率增加。如果启用了排序,则在具有相同排序键的早期消息收到确认之前,系统无法传送具有排序键的消息。
考虑消息排序或“正好一次”传送是否对您的应用至关重要。如果您最看重低延迟,尽量减少使用这些功能有助于缩短消息处理延迟时间。
增加消息大小
消息大小突然增加可能会增加 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 重新传送带有排序键的消息时,它也会重新传送具有相同排序键的所有后续消息,即使这些消息之前已确认也是如此。这样做是为了保留序列的顺序。不过,我们无法严格保证,系统只会在序列中之前的消息成功确认后发送依赖消息。
订阅者正在取消订阅消息
请参阅订阅者正在暂停消息。
排查 StreamingPull 订阅问题
请求延迟时间指标与端到端传送延迟时间之间的关系
对于 StreamingPull,指标 serviceruntime.googleapis.com/api/request_latencies 表示数据流处于打开状态的时间。该指标对确定端到端传送延迟时间没有帮助。
请使用传送延迟时间健康状况得分,而不是请求延迟时间指标,检查哪些因素导致端到端传送延迟时间增加。
StreamingPull 连接以非正常状态关闭
StreamingPull 流始终以不正常状态关闭。与单个 RPC 的错误状态不同,StreamingPull 的此状态仅表示流已断开连接。请求不会失败。因此,虽然 StreamingPull API 错误率可能高达 100%,但这是特意设计的。
由于 StreamingPull 流始终以错误关闭,因此在诊断错误时检查流终止指标并没有什么帮助。不妨关注 StreamingPull 响应指标 subscription/streaming_pull_response_count
,按 response_code
或 response_class
分组。
请查找以下错误:
如果订阅积压输入量中存在已停用的 Cloud KMS 密钥加密的消息,则可能会发生前提条件检查失败错误。如需继续拉取,请恢复对密钥的访问权限。
当 Pub/Sub 无法处理请求时,可能会发生不可用错误。这很可能是一种暂时性情况,客户端库会重试请求。如果您使用的是客户端库,则无需采取任何行动。
如果订阅已被删除或从未存在,则可能会出现“未找到”错误。如果您提供的订阅路径无效,就会出现后一种情况。