CeleryCelery任务重复执行排查:从Redis Stream消费组到幂等设计的实战

现象:任务莫名执行两次

上周五深夜,我们的订单系统突然出现大量重复发货通知。排查日志发现,同一个订单的异步任务(Celery + Redis)在短短几秒内被执行了两次,且两次都成功调用了第三方物流API。更诡异的是,这个任务既没有设置重试,也没有人为触发。

定位:从Celery日志到Redis Stream

首先查看Celery worker日志,发现两条相邻的Task accepted记录,任务ID相同但进程PID不同。这基本排除单worker内的重复消费,怀疑是消息队列层面出现了重复投递。

我们用的是Redis Stream作为broker(Celery 5.x支持)。检查Redis中的Stream组状态:

复制代码
XINFO GROUPS orders_stream
1) 1) "name"
   2) "celery"
   3) "consumers"
   4) (integer) 2
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "1699999999999-0"

注意到consumers数量为2,但我们的worker只有一个进程。继续查看消费者详情:

复制代码
XINFO CONSUMERS orders_stream celery
1) 1) "name"
   2) "worker-1"
   3) "pending"
   4) (integer) 1
   5) "idle"
   6) (integer) 0
2) 1) "name"
   2) "worker-1-stale"
   3) "pending"
   4) (integer) 0
   5) "idle"
   6) (integer) 86400

发现一个名为worker-1-stale的消费者,闲置时间长达一天。这通常是因为worker进程被强制kill(如OOM或手动重启)后,Redis Stream中的消费者没有自动清理。当这个僵尸消费者重新活跃(比如网络分区恢复),它会重新读取未确认的消息,导致重复消费。

修复:清理僵尸消费者并强化幂等

第一步:立即清理

复制代码
# 删除僵尸消费者
XGROUP DELCONSUMER orders_stream celery worker-1-stale
# 确认组状态
XINFO GROUPS orders_stream

第二步:代码层面加幂等保护

在任务入口处添加基于业务ID的去重:

复制代码
def process_order(order_id):
    # 使用Redis SETNX实现简单幂等
    key = f"order:{order_id}:processed"
    if not redis_client.set(key, "1", nx=True, ex=3600):
        logger.info(f"订单{order_id}已处理,跳过")
        return
    # 实际业务逻辑
    call_shipping_api(order_id)
    # 业务成功后删除key(可选,根据需求)

第三步:调整Celery配置

复制代码
# settings.py
CELERY_BROKER_TRANSPORT_OPTIONS = {
    'visibility_timeout': 3600,  # 设置可见超时,防止僵尸消费者长时间持有消息
    'consumer_auto_heartbeat': 10,
}

复盘:教训与最佳实践

  • 监控消费者状态:定期检查Stream组的消费者列表,发现长时间idle的消费者及时清理。
  • 幂等是底线:任何涉及外部副作用的任务都必须设计幂等,不能依赖消息队列的"至少一次"保证。
  • 优雅关闭worker :使用celery multi stop或发送SIGTERM,避免kill -9导致消费者未清理。
  • 测试故障场景:模拟worker宕机重启,验证消息不丢失且不重复。

这次踩坑让我们意识到,消息队列的可靠性不仅仅是"不丢消息",还要考虑"不重复"。在分布式系统中,幂等设计是工程师的基本功。

相关推荐
hanchenxing1 天前
CeleryCelery任务丢失排查:从原理到用Redis Stream兜底的实战
任务队列·redis stream
hey you~2 天前
云客服机器人知识库批量导入,接口开发实操方案
向量数据库·openapi·接口开发·幂等设计·云客服机器人·知识库批量导入·批量导入api
贾伟康4 天前
【口算王|02】HarmonyOS ArkTS 答题提交实战:防止重复提交并推进下一题
harmonyos·arkts·状态管理·arkui·幂等设计
贾伟康18 天前
【时光清单|03】HarmonyOS ArkTS 提醒服务实战:计算触发时间并防止重复注册
harmonyos·arkts·后台任务·幂等设计·通知提醒
小楼v8 个月前
深入全面理解幂等性设计原理及实现幂等的主流方案
后端·雪花算法·幂等性·幂等设计
蜂蜜黄油呀土豆9 个月前
RocketMQ 详解:从异步解耦到存储与消费全链路解析
消息队列·rocketmq·分布式账本·分布式系统·幂等设计