- Celery 是什么?适用场景
Celery 是 Python 的一套分布式任务队列(Distributed Task Queue)框架,用于把耗时/异步工作放到后台 Worker 进程/机器上运行。
核心优势:解耦、异步、水平扩展。
常见场景:
• 生成/处理文件、图片/音视频转码、OCR、ML 推理等长耗时任务
• 调用第三方 API、批量爬取/数据管道等IO 密集任务
• 定时/周期性任务(每天/每小时跑批)
• 工作流编排(A→B→并发{C1…Cn}→汇总)
不适用:
• 强实时(毫秒级)或强一致 Exactly-once(Celery 语义是至少一次)
• 一次性小脚本(上 Celery 成本偏高)
⸻
- 核心架构与术语
• Client / Producer:发布任务(比如你的 Web/CLI)
• Broker:消息队列(Redis 或 RabbitMQ 最常见)
• Worker:消费并执行任务的进程集群
• Result Backend:存任务结果/状态(Redis、数据库、RPC……)
• Task:你写的函数,加上 @app.task
• Queue / Routing:把不同任务路由到不同队列/Worker
• Canvas:任务组合原语:chain 串行、group 并行、chord 并行后汇总
运行语义:At-least-once(至少一次执行),因此幂等性非常重要。
⸻
- 最小可运行:5 分钟起步(Redis 版)
3.1 安装
pip install "celery[redis]" redis
3.2 定义应用与任务 celery_app.py
from celery import Celery
app = Celery(
"demo",
broker="redis://localhost:6379/0",
backend="redis://localhost:6379/1",
)
app.conf.update(
task_serializer="json",
accept_content=["json"],
result_serializer="json",
timezone="Asia/Shanghai",
enable_utc=True,
)
@app.task(bind=True, autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={"max_retries": 5})
def add(self, x, y):
return x + y
3.3 启动 Worker
celery -A celery_app.app worker -l info -Q default -n worker@%h -c 4
• -c 4:并发 4(进程池默认 prefork)
• -Q default:监听 default 队列
3.4 发送任务
from celery_app import add
r = add.delay(2, 3) # 异步
print(r.id) # 任务ID
print(r.get(timeout=10)) # 同步等待(生产中建议少用)
⸻
- 与 FastAPI 集成:API 立刻返回,后台跑
4.1 目录结构(示例)
.
├─ app.py # FastAPI
└─ celery_app.py # Celery 定义
4.2 app.py
from fastapi import FastAPI, HTTPException
from celery.result import AsyncResult
from celery_app import app as celery, add
api = FastAPI()
@api.post("/tasks/add")
def create_add(x: int, y: int):
async_result = add.apply_async(args=[x, y], queue="default", countdown=0)
return {"task_id": async_result.id}
@api.get("/tasks/{task_id}")
def get_status(task_id: str):
ar = AsyncResult(task_id, app=celery)
# PENDING / STARTED / RETRY / FAILURE / SUCCESS
if ar.state == "FAILURE":
return {"state": ar.state, "error": str(ar.info)}
return {"state": ar.state, "result": ar.result}
• 前端调用 /tasks/add 立即得到 task_id(HTTP 200)
• 之后轮询 /tasks/{task_id} 获取进度/结果
→ 更高级可用 WebSocket/SSE 推送(接入 Celery 事件流)
⸻
- 定时任务(Celery Beat)
5.1 安装
pip install celery[redis] celery[timezone]
5.2 配置周期表
# celery_app.py 里追加
from celery.schedules import crontab
app.conf.beat_schedule = {
"every-5-min-clean": {
"task": "celery_app.cleanup",
"schedule": crontab(minute="*/5"),
}
}
@app.task
def cleanup():
# 清理临时文件/过期数据
return "ok"
5.3 启动 Beat + Worker
# 终端1
celery -A celery_app.app beat -l info
# 终端2
celery -A celery_app.app worker -l info -Q default
⸻
- 任务编排(Canvas):chain / group / chord
from celery import chain, group, chord
@app.task
def step1(x): return x + 1
@app.task
def step2(x): return x * 2
@app.task
def merge(results): # 用于汇总
return sum(results)
# 串行:((10+1) * 2)
res = chain(step1.s(10), step2.s())()
# 并行 + 汇总:并行算 step2(1..5) → merge(sum)
res2 = chord(group(step2.s(i) for i in range(1, 6)))(merge.s())
使用 chord 需要支持 chord 的后端(Redis/RabbitMQ 均可),并发 fan-out/fan-in 的常用套路。
⸻
- 可靠性与语义:必须掌握的选项
• 重试:autoretry_for + retry_backoff / 手工 self.retry(…)
• 超时:task_time_limit(硬) / task_soft_time_limit(软,可捕获 SoftTimeLimitExceeded)
• 确认与幂等:
• task_acks_late=True(执行完成才确认,worker crash 会重投,但要幂等)
• task_reject_on_worker_lost=True(进程意外退出时拒绝并重排)
• 数据库/支付类操作必须有幂等键与去重(例如 Redis SETNX/唯一约束)
• 预取/流控:worker_prefetch_multiplier(默认 4)
IO 任务可调大;CPU 任务建议 1,避免长任务把队列“吃空”
• 内存与稳定性:
• worker_max_tasks_per_child:每个子进程跑 N 个任务后重启,抑制泄漏
• worker_max_memory_per_child:超过内存阈值重启子进程
• 结果后端:不取结果就关闭结果(task_ignore_result=True)以减轻 Redis 压力
• 序列化安全:accept_content=[“json”],不要启用 pickle(安全风险)
⸻
- 性能调优:CPU vs IO、并发模型与路由
• 并发模型:默认 prefork(多进程)
• CPU 密集:prefork + -c≈CPU 核心数(或略高)
• IO 密集:可考虑 --pool=gevent 或 eventlet(第三方库要兼容)
• 路由与队列:按业务/优先级拆分队列
# celery_app.py
app.conf.task_routes = {
"celery_app.heavy_task": {"queue": "cpu"},
"celery_app.io_task": {"queue": "io"},
}
# 启动两个 Worker 分别监听
# celery -A celery_app.app worker -Q cpu -c 8
# celery -A celery_app.app worker -Q io --pool=gevent -c 200
• Chunk / Map:大批量小任务 → group+chunks 批处理减少开销
• 避免大 payload:任务参数只放指针(URL/ID/路径),大文件走对象存储
⸻
- 运维与监控
9.1 Flower(可视化监控)
pip install flower
celery -A celery_app.app flower --port=5555
可看任务/队列/Worker 状态、失败重试、撤销任务等。
9.2 命令行“指挥手册”
# 查看 Worker
celery -A celery_app.app status
celery -A celery_app.app inspect active
celery -A celery_app.app inspect scheduled
celery -A celery_app.app inspect reserved
# 控制
celery -A celery_app.app control rate_limit celery_app.add 10/m
celery -A celery_app.app control revoke <task_id> --terminate # 需要 time limit 配合
9.3 度量
• 队列长度、吞吐、失败率、重试率、任务时长分位
• Worker 存活/并发度、重启次数、内存
• Broker(Redis/RabbitMQ)延迟与连接数
可接入 Prometheus Exporter 或自建日志指标。
⸻
- 部署与生产建议
• 进程守护:systemd/supervisord/Docker Compose/K8s
• 多实例:不同队列不同 Worker,方便水平扩展与隔离
• 配置分离:生产/预发/本地不同 broker/backend/并发/队列名
• 日志:独立目录、JSON 格式、关联 task_id
• 升级:Celery 与 Kombu/redis/rabbit 客户端版本一起 pin 住,灰度升级 Worker
• 时钟:所有节点时钟同步(NTP),避免 ETA/定时偏差
• 安全:Broker/Backend 加 TLS,凭证不入仓库;参数不携带敏感明文
⸻
- 常见坑与排错清单
• “任务消失/重复执行”:检查 acks_late、prefetch_multiplier、Worker 崩溃、幂等性
• “卡在等待/延迟大”:看队列长度、并发 -c、QPS、Broker 性能/网络
• “内存涨”:worker_max_tasks_per_child、避免把大对象留在全局、升级库修复泄漏
• “chord 不回调”:后端不支持或配置错误;确保 result_backend 可用且事件开启
• “阻塞 Web 线程”:不要在 Web 线程里 result.get(),只返回 task_id 让前端轮询或订阅
⸻
- 与其他框架对比(简述)
• Celery:生态成熟、功能全(定时/编排/路由/监控);配置复杂、学习曲线陡
• Dramatiq / RQ / Huey:上手简单,特性少一些
• TaskIQ:现代感强、Typing 好;生态与资料量不及 Celery
• FastAPI BackgroundTasks:同进程轻量异步,不适合长任务/掉电恢复
⸻
- 速查代码片段(收藏)
任务重试 + 软/硬时限
from celery.exceptions import SoftTimeLimitExceeded
@app.task(bind=True, autoretry_for=(TimeoutError,), retry_backoff=2, retry_kwargs={"max_retries": 3},
soft_time_limit=60, time_limit=70)
def fetch(self, url):
try:
return do_io(url, timeout=10)
except SoftTimeLimitExceeded:
# 清理资源
raise
幂等保护(Redis 锁)
import time
import redis
r = redis.Redis()
@app.task(bind=True, acks_late=True)
def once_task(self, key):
lock = r.set(f"lock:{key}", "1", nx=True, ex=300) # 5 分钟
if not lock:
return "duplicate"
try:
time.sleep(5)
return "done"
finally:
r.delete(f"lock:{key}")
按队列路由
app.conf.task_routes = {"*.thumbnail*": {"queue": "media"}}
# celery -A celery_app.app worker -Q media -c 4
定时(crontab)
from celery.schedules import crontab
app.conf.beat_schedule = {
"daily-1am": {"task": "app.daily", "schedule": crontab(minute=0, hour=1)}
}
编排(并行后汇总)
res = chord(group(process.s(i) for i in range(100)))(aggregate.s())
⸻
一句话收尾
Celery = “把慢事丢后台 + 可编排 + 可横向扩展”。
抓住四根“安全绳”:幂等性、重试/确认、时限、监控;
再用路由/并发模型/预取做性能分层,你就能放心把生产中的“长任务”交给它。
1464






