高负载下使用pubsub_v1.PublisherClient的Google Pub/Sub丢消息问题
排查Pub/Sub高负载下消息丢失的可能原因
一、客户端发布逻辑问题
- 批量发送配置缺失:默认情况下,
PublisherClient会开启批量发送(batching),当消息数量/大小未达阈值或未到超时时间时,消息会暂存于客户端内存。若批处理任务在发送完成前意外退出(如OOM、强制终止),这些未发送的缓存消息会直接丢失。可显式配置批量参数,降低消息滞留风险:from google.cloud import pubsub_v1 batch_settings = pubsub_v1.types.BatchSettings( max_messages=100, # 每批最多承载100条消息 max_bytes=10**6, # 每批最大容量1MB max_latency=0.1, # 最长等待0.1秒就触发发送 ) self.publisher = pubsub_v1.PublisherClient( credentials=credentials, batch_settings=batch_settings ) - 异常处理不严谨:你的代码将所有异常统一包装为400错误,但Pub/Sub客户端会自动重试部分可恢复异常(如网络抖动、服务限流)。直接抛出异常终止流程,可能导致部分消息未完成重试就宣告失败。建议区分可重试与不可恢复错误,保留客户端原生重试逻辑。
- 不必要的锁机制:
PublisherClient本身是线程安全的,手动加锁会阻塞发送流程,增加消息在客户端的停留时间,既降低发送效率,也提升了进程意外退出时的消息丢失概率。
二、Pub/Sub订阅与投递问题
- 订阅者处理失败未重试:若订阅BigQuery的消费者处理消息时失败(如BigQuery写入超时、Schema不匹配),且未配置重试策略或死信队列,Pub/Sub在达到最大重试次数后会丢弃消息。需检查订阅的重试设置(默认指数退避,但有最大重试时长限制),并配置死信队列捕获无法处理的消息。
- Push订阅的确认漏洞:如果用Push模式将消息推送到服务端写入BigQuery,若服务端在处理完成前崩溃且未返回错误响应,Pub/Sub会判定消息已成功处理,导致消息丢失。建议改用Pull模式,手动控制消息ACK:仅当BigQuery写入成功后,才确认Pub/Sub消息;失败则NACK,让Pub/Sub重新投递。
- 订阅者吞吐量不足:高负载下,订阅者处理速度跟不上消息发送速度,会导致消息堆积。若超过Pub/Sub默认7天的消息保留时间,未处理的消息会被自动删除。需监控订阅的未确认消息数,及时扩容订阅者实例。
三、BigQuery写入环节问题
- 写入失败未捕获:写入BigQuery时可能出现隐性失败(如重复键冲突、字段类型不匹配),若订阅者未捕获这些异常就ACK消息,会造成消息丢失。需在写入BigQuery的代码中添加异常捕获逻辑,仅当收到BigQuery的成功响应后,才确认Pub/Sub消息。
- BigQuery写入延迟:BigQuery流式写入存在一定延迟,测试时若立即查询统计,可能遗漏尚未完成写入的消息,误判为丢失。建议等待一段时间后再统计,或通过BigQuery的
streaming_insert_stats监控写入状态。
四、测试统计准确性问题
- 发送端统计误差:Newman的任务统计是否准确?比如是否存在任务未完全执行就提前结束的情况,导致实际发送消息数少于预期。可在Python代码中添加日志,记录每条消息的发布结果(message_id),将实际成功发送的数量与Newman统计对比。
- 重复消息去重干扰:若业务逻辑有去重机制,可能过滤掉重复投递的消息,导致统计的“丢失”实际是去重后的结果。需检查BigQuery表的去重规则,确认是否有被过滤的消息。
内容的提问来源于stack exchange,提问作者Irfaan Sulaiman
相关产品推荐
相关产品推荐

