本文档提供了一些针对 Pub/Sub 拉取订阅的常见问题排查提示。如需详细了解拉取订阅,请参阅拉取订阅者指南。
为了有效监控 Pub/Sub 订阅,建议您先查看传送延迟时间健康状况得分 (subscription/delivery_latency_health_score),以检查哪些因素可能会导致延迟时间意外或增加。
最早的未确认消息的存在时间不断增加
oldest_unacked_message_age
是监控 Pub/Sub 订阅运行状况的关键指标。它用于衡量订阅积压工作中最早的未被订阅者确认 (acked) 的消息的存在时间(以秒为单位)。此指标可提供有关潜在处理延迟或瓶颈的宝贵数据洞见。
监控消息积压可确保及时高效地处理消息。通过跟踪最早的未确认消息的存在时间,您可以主动发现消费者落后的情况。这样,您就可以及早介入,解决与性能下降相关的潜在问题。
您可以调查的一些常见积压问题包括:
客户端配置问题
如果 oldest_unacked_message_age
和 num_undelivered_messages
这两个指标同时增加,可能意味着订阅者跟不上消息量。在这种情况下,请重点调查订阅者组件:
客户端健康状况:分析托管订阅者客户端的计算机上的资源利用率,例如 CPU、内存和网络带宽。查找可能阻碍处理效率的压力点。
客户端代码:查看近期的代码更改并检查错误日志。订阅者代码中的 bug 或低效之处可能会显著影响消息处理速率。请注意,特定消息中可能存在问题。例如,多条消息可能需要同时访问数据库中的同一行。此行为可能会导致争用和高延迟。
配额限制:验证您是否未超出托管服务施加的任何 Pub/Sub 配额或限制。如果订阅者托管在 Google Cloud中,请查看 Compute Engine 或 GKE 资源配额,以防止出现潜在的瓶颈。
订阅者否定确认了消息
当订阅者否定确认 (nack) 消息时,会向 Pub/Sub 发出信号,表明该消息无法成功处理。然后,Pub/Sub 会尝试重新传送同一消息。针对某条消息重复发送否定确认会导致消息重复,并可能导致消息传送延迟时间过长。
请注意,否定确认消息并不能保证下一次拉取会提取不同的消息。Pub/Sub 的重新递送政策可能会继续重新递送已否定确认的消息,然后再递送新消息。因此,请勿将 NACK 用作过滤或跳过特定消息的方法。请改为设置重试政策,最好是指数退避,以便退避那些可能稍后可以处理但需要更长时间才能重新传送的个别消息。
如果您需要有意跳过某些消息,建议的方法是确认这些消息,即使您不会处理它们也是如此。这样可将其从订阅中移除,避免不必要的重新传送,并减少资源消耗。无论是有意还是无意,不确认消息都会导致积压问题和重复传送。
高交付延迟时间
Pub/Sub 中的传送延迟是指从发布者发送消息到订阅者收到消息所用的时间。以下部分介绍了可能导致交付延迟时间较长的一些原因。
订阅者人数不足
对于使用 StreamingPull 的客户端,为了实现始终较低的延迟时间,请保持与订阅的多个 StreamingPull 连接处于打开状态。如果没有有效的订阅者连接,Pub/Sub 无法及时传送消息。单个数据流可能成为单点故障,从而增加延迟风险。subscription/open_streaming_pulls
指标可让您了解活跃的流式传输连接数。使用此参数可确保您始终有足够的流来处理传入的消息。
对于使用一元拉取的客户端,为了实现始终较低的延迟时间,请保持向订阅发出的多个待处理拉取请求。不频繁的请求可能会在积压中累积消息,从而增加延迟时间。这种方法有助于最大限度地减少连接中断,并缩短传送延迟时间。
如果需要高吞吐量和低延迟,同时尽可能减少运营开销和处理成本,建议使用高级客户端库。默认情况下,高级客户端库使用 StreamingPull API,因为该 API 通常是缩短延迟时间的更佳选择。高级客户端库包含预建的函数和类,可处理身份验证、吞吐量和延迟时间优化、消息格式设置以及其他功能的底层 API 调用。
客户端配置问题
请参阅客户端配置问题。
积压高
请注意,Pub/Sub 订阅中未确认的消息积压会固有地增加端到端延迟时间,因为订阅者不会立即处理消息。
排序键和“仅传送一次”
排序键和“正好一次”传送是非常有用的功能,但它们需要在 Pub/Sub 中进行额外的协调,以确保正确传送。这种协调可能会降低可用性并增加延迟时间。虽然在稳定状态下差异很小,但任何必要的协调步骤都可能会导致延迟时间暂时增加或错误率增加。如果启用了排序,则在具有相同排序键的较早消息得到确认之前,无法传送具有排序键的消息。
考虑消息排序或“正好一次”传送对于您的应用是否绝对必要。如果低延迟是您的首要考虑因素,那么尽量减少使用这些功能有助于减少消息处理延迟。
消息大小增加
消息大小突然增加可能会增加 Pub/Sub 与客户端之间的传输时间,并减慢客户端的消息处理时间。
如果您发现传送延迟时间有所增加,可以使用 topic/message_sizes
指标(按 topic_id
分组)检查消息大小。将消息大小的任何峰值与观察到的性能问题相关联。
缺少消息
如果您怀疑消息未成功传送给订阅者,可能是以下原因之一造成的。
在具有多个消费者的 Pub/Sub 订阅中分发消息
在 Pub/Sub 中,消息可能会在各个消费者之间不均匀地分布。出现此行为的原因是 Pub/Sub 会在活跃的订阅者之间分配消息,以提高效率。有时,单个使用方收到的消息可能比预期少,或者收到的消息子集与其他使用方不同。
请注意,消息可能已发送给客户端,而未确认消息的积压并不一定意味着您会在下一个拉取请求中收到这些消息。请注意,消费者可能是使用 Google Cloud 控制台或 Google Cloud CLI 中的拉取功能的用户,也可能是运行本地自定义订阅者来检查消息的用户。
对于一元 Pull 客户端,您可能会发现某些 pull 请求返回的消息数量为零。如订阅者数量不足部分中所述,建议保持多个未完成的拉取请求,因为某些请求返回的消息数可能少于配置的最大消息数,甚至可能返回零条消息。
如果您怀疑存在上述任何行为,请调查是否有多个订阅者同时附加到相应订阅,并检查这些订阅者。
按订阅过滤
检查订阅是否附加了过滤条件。在这种情况下,您只会收到与过滤条件匹配的消息。Pub/Sub 服务会自动确认与过滤条件不匹配的消息。不妨考虑一下过滤条件如何影响积压工作指标。
使用选项 returnImmediately
如果您的客户端使用的是一元 Pull,请检查 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 无法处理请求时,可能会出现不可用错误。这很可能是一种暂时性情况,客户端库会重试请求。如果您使用的是客户端库,则无需采取任何行动。
如果订阅被删除或从未存在过,则可能会出现“未找到”错误。如果您提供的订阅路径无效,则会发生后一种情况。