Celery 核心知识点汇总
Celery:Python 分布式任务队列,异步任务、定时任务、任务调度;解耦耗时操作(邮件、推送、数据清洗、爬虫、定时脚本)
一、基础架构(四大组件)
- Task(任务) 业务函数,被装饰器
@app.task标记;支持普通任务、定时任务、任务链。 - Worker(工作进程) 消费任务、执行函数;可以单机多进程 / 多协程、多机分布式部署。
- Broker(消息中间件,消息代理) 存放待执行任务,Worker 从 Broker 拉取任务。 ✅ 常用:Redis / RabbitMQ
- RabbitMQ:官方推荐,可靠、支持消息确认、路由;
- Redis:简单易部署,适合中小型项目;不支持任务可靠投递(断电丢任务风险)
- Backend(结果存储,可选) 保存任务返回值、状态;不需要获取结果可关闭。 支持:Redis、MongoDB、Database、RPC
数据流:客户端提交任务 → Broker 排队 → Worker 取任务执行 → 结果存入 Backend
二、基础安装与最小 Demo
1.安装
pip install celery
# redis broker额外装redis客户端
pip install redis
2.项目结构 celery_app.py
from celery import Celery
# 创建实例
app = Celery(
"demo",
broker="redis://127.0.0.1:6379/0", # broker地址
backend="redis://127.0.0.1:6379/0" # 结果后端
)
# 定义任务
@app.task
def add(x, y):
return x + y
3.启动 worker
# 默认前台启动
celery -A celery_app worker --loglevel=info
# Windows注意:celery5.x不再支持默认prefork,使用solo/eventlet(协程)
celery -A celery_app worker -P eventlet --loglevel=info
4.调用任务三种方式
from celery_app import add
# 1. 同步调用(直接执行,不进队列)
res = add(2,3)
# 2. 异步调用【核心】发送任务到broker
res = add.delay(2,3)
# 3. 更灵活:支持队列、路由(指定某个队列)、倒计时
res = add.apply_async(args=(2,3), queue="default", countdown=5)
# 获取任务结果
res.id # 任务唯一task_id
res.get() # 阻塞等待结果,可设置超时 res.get(timeout=10)
res.status # PENDING/STARTED/SUCCESS/FAILURE
res.ready() # 是否执行完成
res.successful() # 是否成功
三、任务高级特性
1. 任务选项(装饰器参数)
@app.task(
bind=True, # 开启self参数,可以访问任务实例
max_retries=3, # 最大重试次数
default_retry_delay=10, # 默认重试间隔s
ignore_result=True, # 不保存返回值,关闭backend减轻压力
time_limit=30, # 硬超时:超过直接kill进程
soft_time_limit=25 # 软超时:抛出异常,可捕获处理
)
def demo_task(self):
try:
1/0
except Exception as e:
# 主动重试
self.retry(exc=e, countdown=5)
2. 任务编排(组合任务)
from celery import group, chain, chord, signature
# signature:任务签名,可预先封装参数
s = add.s(2, 3)
s.delay()
# chain 任务串行:A执行完结果传给B
chain(add.s(1,2) | add.s(10))()
# group 任务并行:同时执行多个任务
group(add.s(1,1), add.s(2,2))().get()
# chord = group + callback:所有并行任务完成后执行回调
chord(group(task1.s(), task2.s()))(callback.s())
3. 任务路由 & 多队列
业务隔离:不同任务投递不同队列,不同 worker 只消费指定队列
# 配置路由
app.conf.task_routes = {
"celery_app.add": {"queue": "math_queue"},
"celery_app.send_email": {"queue": "email_queue"}
}
# 启动worker只消费指定队列
celery -A celery_app worker -Q math_queue --loglevel=info
celery -A celery_app worker -Q email_queue --loglevel=info
四、定时任务(Celery Beat)
Beat:定时调度器,周期性向 Broker 发送任务;单机运行!多机启动会重复下发任务
方式 1:代码配置定时任务
app.conf.timezone = "Asia/Shanghai" # 时区必须配置!否则时间错乱
app.conf.beat_schedule = {
"every-10s-task": {
"task": "celery_app.add",
"schedule": 10.0, # 间隔秒
"args": (1,2) #位置参数
},
#每隔10秒运行
"daily-8-30": {
"task": "celery_app.add",
"schedule": crontab(hour=8, minute=30),
"args": (2, 3),
},
# 案例2:每天早上8点30分执行
}
# schedule 也可用crontab
from celery.schedules import crontab
crontab(hour=3, minute=0) # 每日凌晨3点
启动
# worker + beat分开启动(推荐生产)
celery -A celery_app worker --loglevel=info
celery -A celery_app beat --loglevel=info
持久化定时任务
默认 beat 定时存在内存,重启丢失;可使用 django-celery-beat 将定时规则存入数据库,动态增删定时任务(Django 项目常用)。
五、Worker 核心启动参数
# -A 指定app
# -c 并发进程数(prefork模式)
celery -A app worker -c 4
# 并发池模式
-P prefork # 默认多进程(Linux推荐)
-P eventlet # 协程(IO密集任务)
-P solo # 单进程(Windows调试)
# 后台守护运行(Linux)
celery -A app worker --detach
# 指定队列、名称、日志文件
celery -A app worker -Q queue1 -n worker1@%h --logfile=worker.log
六、重要配置(app.conf)
# 任务序列化,Celery 任务要从客户端发到 Broker(Redis/RabbitMQ),**必须把函数参数转换成字符串格式**,这个过程叫**序列化**;
Worker 拿到字符串,再还原成原始数据 → **反序列化**。
app.conf.task_serializer = "json"
app.conf.result_serializer = "json"
app.conf.accept_content = ["json"]
# 任务执行成功后,Backend(Redis)里保存的**返回结果有效期 1 小时**。
超过时间自动删除。
app.conf.result_expires = 3600
# 防止任务无限重试、死循环
app.conf.task_default_retry_delay = 5
# 任务发送后不可修改(预防消息篡改)
app.conf.security_key = "xxx"
# 开启任务确认(RabbitMQ有效)
# Redis broker 原生不支持acks_late可靠消费
app.conf.task_acks_late = True
七、常见状态
PENDING:等待执行STARTED:正在执行(默认关闭,需要启用task_track_started=True)SUCCESS:执行成功FAILURE:抛出异常失败RETRY:任务正在重试REVOKED:任务被撤销
撤销任务
from celery_app import add
res = add.delay(1,2)
app.control.revoke(res.id, terminate=True) # terminate=True直接kill运行中的worker
八、生产痛点与坑(高频面试)
- Redis Broker 消息丢失风险
- Worker 宕机:正在执行任务丢失;RabbitMQ 支持消息 ACK,Redis 不支持。
- 解决方案:重要业务改用 RabbitMQ;任务幂等设计。
- Beat 多实例重复调度 beat 只能单实例;多服务器部署需要分布式锁(redis 锁保证只启动一个 beat)。
- 任务幂等性 网络重试、任务重复下发,业务代码必须支持重复执行不出错。
- Worker 卡死、僵尸任务 设置
time_limit硬超时;IO 密集使用 eventlet 协程池;定期重启 worker。 - 结果 Backend 堆积 不用结果就
ignore_result=True;设置result_expires自动清理。 - Windows 兼容性 celery5 移除 prefork 支持,必须使用
-P solo / eventlet。 - 不要在任务中操作数据库长连接 worker 进程长期运行,数据库连接超时断开,任务内动态创建连接。
九、Django 集成 Celery 标准结构
project/
├── project/
│ ├── __init__.py
│ ├── celery.py # celery实例
│ ├── settings.py
├── app1/tasks.py # 业务任务
celery.py
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
app = Celery("project")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks() # 自动发现各app下tasks.py
__init__.py
from .celery import app as celery_app
__all__ = ["celery_app"]
settings.py 中以CELERY_开头配置:
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0"
CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/0"
十、监控
-
celery flower 可视化监控面板
pip install flower
celery -A celery_app flower --port=5555
功能:查看 worker、任务列表、撤销任务、耗时统计。
十一、面试精简提纲
- Celery 架构:Broker、Worker、Backend、Task 作用;Redis vs RabbitMQ 区别
- 异步任务 delay /apply_async 区别;任务获取结果方式
- 任务重试、超时、串行 / 并行任务链
- 多队列任务路由场景
- Celery Beat 定时任务原理、重复调度问题
- 消息丢失、幂等、僵尸任务解决方案
- Flower 监控、Django 集成流程
十二、Celery 完整可运行示例(Redis Broker + Backend)
目录结构
celery_demo/
├── celery_main.py # celery入口配置
└── tasks.py # 所有任务函数
1. 安装依赖
pip install celery redis
2. celery_main.py
from celery import Celery
from celery.schedules import crontab
# 1. 创建celery实例
app = Celery(
"celery_demo",
broker="redis://127.0.0.1:6379/0",
backend="redis://127.0.0.1:6379/0"
)
# 2. 全局配置
app.conf.update(
# 序列化配置
task_serializer="json",
result_serializer="json",
accept_content=["json"],
result_expires=3600, # 结果1小时过期
task_default_retry_delay=5, # 默认重试等待5秒
task_acks_late=True, # 延迟确认(仅RabbitMQ有效)
timezone="Asia/Shanghai", # 时区,定时任务必备
)
# 3. 任务路由:不同任务分发到不同队列
app.conf.task_routes = {
"tasks.add": {"queue": "math_queue"},
"tasks.send_msg": {"queue": "msg_queue"},
}
# 4. 定时任务 Beat 配置
app.conf.beat_schedule = {
"every-10s-add-task": {
"task": "tasks.add",
"schedule": 10.0,
"args": (10, 20)
},
"daily-3-clock": {
"task": "tasks.send_msg",
"schedule": crontab(hour=3, minute=0),
"args": ["凌晨三点定时消息"]
}
}
==========================
# 自动导入任务1
app = Celery(
"demo",
broker="redis://127.0.0.1:6379/0",
backend="redis://127.0.0.1:6379/0",
# 关键:include 列表
include=["tasks", "tasks_msg"] # 自动导入任务
)
# 自动导入任务2
app.autodiscover_tasks(["tasks"])
3. tasks.py(核心任务代码)
from celery_main import app
# ======================
# 普通任务:无需重试,不需要self
# ======================
@app.task(ignore_result=True)
def send_msg(content):
"""发送消息,不保存返回结果"""
print(f"发送消息:{content}")
return True
# ======================
# 带bind=True、支持重试、超时控制任务
# ======================
@app.task(
bind=True,
max_retries=3,
default_retry_delay=5,
time_limit=30, # 硬超时,30s强制杀死进程
soft_time_limit=25 # 软超时,25s抛出异常
)
def add(self, x, y):
try:
print(f"计算 {x} + {y}")
res = x + y
return res
except Exception as e:
# 手动重试,等待8秒,覆盖全局默认间隔
self.retry(exc=e, countdown=8)
4. 客户端调用测试 run.py
from tasks import add, send_msg
from celery import group, chain, chord
if __name__ == '__main__':
# 1. 基础异步调用
res = add.delay(2, 5)
print("task_id:", res.id)
# 阻塞获取结果
print("结果:", res.get(timeout=10))
# 2. 指定队列调用
add.apply_async(args=(3, 4), queue="math_queue")
# 3. chain 串行任务
# add(1,2)=3 → add(3,10)
c = chain(add.s(1, 2) | add.s(10))
print("chain结果:", c().get())
# 4. group 并行任务
g = group(add.s(1, 1), add.s(2, 2))
print("group并行结果列表:", g().get())
# 5. chord 并行 + 汇总回调
@app.task
def sum_callback(num_list):
return sum(num_list)
ch = chord(group(add.s(1, 5), add.s(2, 3)))(sum_callback.s())
print("chord汇总结果:", ch().get())
启动命令(新开多个终端)
终端 1:启动消费 math_queue 的 worker
celery -A celery_main worker -Q math_queue -n math_worker@%h --loglevel=info
终端 2:启动消费 msg_queue 的 worker
celery -A celery_main worker -Q msg_queue -n msg_worker@%h --loglevel=info
终端 3:启动定时调度 Beat
celery -A celery_main beat --loglevel=info
执行测试
python run.py
