第一反应是检查RabbitMQ自身健康度:运行celery -A proj inspect ping确认worker响应,用rabbitmqctl list_queues查看unack消息是否长期超100,关闭管理插件防stats拖慢,调worker_prefetch_multiplier=1和task_acks_late=True避免预取阻塞,设队列TTL与长度防磁盘写满。
查 Broker 延迟和连接健康度
消息积压第一反应不是加 worker,而是确认 rabbitmq 本身有没有卡住。很多团队在流量上涨后盲目扩容 worker,结果吞吐没涨,内网带宽先打满——因为所有 worker 都在反复重连或轮询空队列。
先做两件事:
• 运行 celery -A proj inspect ping,看每个 worker 是否秒回;如果某个 worker 显示在线但 ping 超时,说明子进程僵死或 AMQP 连接池耗尽
• 在 RabbitMQ 服务器上跑 sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged,重点关注 messages_unacknowledged 长期 >100 的队列——这说明 consumer 拿了消息却不 ack,大概率是任务卡死、没设超时、或崩溃后没清理连接
RabbitMQ 内存飙高也常被误判为“消息太多”,其实是管理插件(rabbitmq_management)在后台疯狂拉取 stats 数据。不用 Web 界面时,直接关掉:rabbitmq-plugins disable rabbitmq_management
调 prefetch_count 和 worker_prefetch_multiplier 到 1
默认 worker_prefetch_multiplier=4 是最大陷阱:一个 worker 进程会预取最多 4 × worker_concurrency 条任务到本地内存。一旦其中某条任务执行 30 秒(比如 PDF 渲染),其余 3 条就得干等,短任务饿死,长任务又拖慢整体周转。
必须同时满足两个条件才有效:
• worker_prefetch_multiplier = 1
• task_acks_late = True(任务执行完才通知 RabbitMQ 删除消息)
否则预取的任务在 worker 崩溃时会被锁住,既不重发也不释放,队列就“假死”了。
注意:prefetch_count 是 AMQP 层概念,Celery 会用 worker_prefetch_multiplier × worker_concurrency 自动设置它。所以别在 RabbitMQ 控制台手动改 prefetch_count,Celery 启动时会覆盖。
确认 worker_concurrency 没超载
并发数不是核数翻倍就行。设太高会导致 Python GIL 下频繁切换、内存 RSS 暴涨;设太低又吃不满 CPU。经验起点是:worker_concurrency = CPU 核心数 × 1.2,然后观察真实负载:
• celery -A proj inspect stats 里看 pool.processes 和 total_memory
• htop 中 CPU idle% 持续 >30%,说明可微增 concurrency
• 单个 worker 进程 RSS >1.5GB,说明任务本身内存开销大,该拆分逻辑或换用 --pool=gevent 降低内存 footprint
别迷信 --autoscale=10,3:它依赖任务耗时稳定。如果一批任务里混着 100ms 的短信和 90s 的视频转码,autoscale 根本来不及反应,只会让积压雪球越滚越大。
关掉无用事件和心跳
Celery 默认每秒向 Broker 发送心跳和 task events(如 task-sent、task-received),这些数据全走 RabbitMQ,但 Flower 外基本没人消费。它们不参与任务执行,却占大量带宽和内存。
启动时加参数关掉:
• --without-heartbeat:停心跳
• --without-gossip:停 worker 间状态广播
• --task-events=False 或配置 worker_send_task_events = False
如果真需要监控,用 Zabbix 或 Prometheus 抓 Celery 的 /metrics 端点,而不是靠 RabbitMQ 转发原始 events。后者在千级 worker 规模下,光 event 消息就能把 RabbitMQ 内存打爆。
最常被忽略的一点:RabbitMQ 队列没设 x-max-length 或 TTL,消息堆积到磁盘写满才报错。上线前务必检查所有队列声明是否包含 arguments={'x-max-length': 10000, 'x-message-ttl': 3600000} —— 不是“以防万一”,是“必须有”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











