PubSub BigQuery订阅出现同ID不同发布时间重复消息排查求助
Pub/Sub到BigQuery订阅重复消息(同message_id但不同publish_time)排查与解决方案
我们部署了Pub/Sub到BigQuery的订阅,出现重复消息推送至BigQuery的情况,当前订阅配置如下:
Write metadata : Enabled
Drop unknown fields : Disabled
Subscription expiration : Subscription will never expire.
Acknowledgement deadline : 10 seconds
Subscription message retention duration : 7 days
Retain acknowledged messages : No
Exactly once delivery : Disabled (cannot be enabled)
Message ordering: Disabled
Dead lettering: Disabled
Retry policy : Retry immediately
原本未启用Exactly once delivery,重复消息属预期,但发现单条message_id为7376235078582047的消息,JSON数据一致但publish_time不同(2023-04-08 12:15:08.664000 UTC、2023-04-08 12:15:12.593000 UTC),日志无有效信息,以下是排查方向和解决方案:
排查方向
- 确认是否为发布端重复发送:同message_id但不同publish_time,大概率是发布端逻辑问题。检查发布客户端:是否存在重试时复用原message_id的情况?比如捕获发布异常后,直接重试未生成新ID的消息对象,导致Pub/Sub接收两条同ID但不同时间的消息。
- 检查Pub/Sub服务端指标:查看订阅核心指标,如
subscription/num_undelivered_messages、subscription/num_retained_acked_messages,确认是否存在消息重复留存异常;同时排查是否因服务端内部重试导致投递重复,但这种情况publish_time通常一致。 - 验证BigQuery写入环节:查看BigQuery写入日志(若已启用),确认是Pub/Sub推送两次,还是BigQuery端重复写入。若为写入超时导致Pub/Sub未收到ACK触发重试,message_id和publish_time应一致,因此更偏向发布端问题。
解决方案
- 规范发布端message_id生成:确保每次发布(包括重试)都生成唯一的message_id,避免复用旧ID,从源头区分重复发布的消息。
- BigQuery端添加去重机制:
- 使用
MERGE语句替代直接插入,以message_id为唯一键,仅插入不存在的记录; - 给表添加
message_id的唯一约束,或通过分区表配合定期去重查询清理重复数据。
- 使用
- 调整订阅配置:当前确认超时10秒、立即重试的策略,若BigQuery写入耗时较长,易触发ACK超时导致重试。可调大
Acknowledgement deadline(如30秒以上),同时启用Dead lettering,将多次重试失败的消息移入死信队列,减少无效重复推送。 - 补充日志埋点:在发布端和Pub/Sub推送链路添加日志,记录message_id、publish_time、请求ID等关键信息,便于后续快速定位重复消息来源。
内容的提问来源于stack exchange,提问作者Vishnu Sriramula
相关产品推荐
相关产品推荐

