简介
Celery作为一款出色的分布式任务框架,上手简单,效率高,尤其在处理需要异步处理的耗时操作时非常适用
原理
当你在A程序中,需要处理一个比较耗时但是又不是需要立即返回结果的任务、或者是当单机处理效率过低需要横向拓展的时候,选择Celery绝对没问题。
A把任务task扔到Broker中,然后就继续干自己的事情去了,剩下的交给其他的 Worker去做,Worker监听队列,有任务就去消费,嗯,原理就是这么简单,就是生产者消费者模型。
开始Celery之旅吧
Broker
通常使用RabbitMQ和Redis,作为消息队列
Backend
通常使用Redis来做存储任务的消费结果。结果的保存有效期可以在APP的设置中去配置
APP
from celery import Celery, platforms
from kombu import Exchange, Queue
from config import (
get_broker_and_backend,
get_mongo
)
tasks = [
'tasks.master', 'tasks.ctrip', 'tasks.ceair'
] # 任务列表
config_status = 'DEV'
broker_and_backend = get_broker_and_backend(config_status)
broker, backend = broker_and_backend
app = Celery('My_Task', include=tasks, broker=broker, backend=backend) # 通过config获取配置
app.conf.update(
CELERY_TIMEZONE='Asia/Shanghai',
CELERY_ENABLE_UTC=True,
# CELERYD_LOG_FILE=worker_log_path, # 日志路径
# CELERYBEAT_LOG_FILE=beat_log_path,
CELERY_ACCEPT_CONTENT=['json'], # Celery接受的消息各式
CELERY_TASK_SERIALIZER='json', # 任务序列化方式
CELERY_RESULT_SERIALIZER='json', # 结果序列化方式
CELERYD_MAX_TASKS_PER_CHILD=1, # worker 接受最多任务数自动销毁,建议设置不要太大,否则会导致内存溢出
# CELERYBEAT_SCHEDULE={ # 定时任务,可选
# 'login_task': {
# 'task': 'tasks.login.execute_login_task',
# 'schedule': timedelta(hours=20),
# 'options': {'queue': 'login_queue', 'routing_key': 'for_login'}
# }
# },
CELERY_QUEUES=( # 队列的配置
Queue('Ceair', exchange=Exchange('Ceair', type='direct'), routing_key='Ceair'),
Queue('Ctrip', exchange=Exchange('Ctrip', type='direct'), routing_key='Ctrip'),
),
)
其他配置
限制任务 的频率
CELERY_ANNOTATIONS = {’*’:{‘rate_limit’:‘10/s’}}
每次获取的任务数
CELERYD_PREFETCH_MULTIPLIER = 4
celery任务执行结果的超时时间
CELERY_TASK_RESULT_EXPIRES = 1200
单个任务的运行时间限制,否则会被杀死
CELERYD_TASK_TIME_LIMIT = 60
任务过期时间,celery任务执行结果的超时时间
CELERY_TASK_RESULT_EXPIRES = 24 * 60 * 60
任务发送完成是否需要确认,对性能会稍有影响
CELERY_ACKS_LATE = True
压缩方案选择,可以是zlib, bzip2,默认是发送没有压缩的数据
CELERY_MESSAGE_COMPRESSION = ‘zlib’
规定完成任务的时间
在5s内完成任务,否则执行该任务的worker将被杀死,任务移交给父进程
CELERYD_TASK_TIME_LIMIT = 5
celery worker的并发数,默认是服务器的内核数目,也是命令行-c参数指定的数目
CELERYD_CONCURRENCY = 4
每个worker执行了多少任务就会死掉,默认是无限的
CELERYD_MAX_TASKS_PER_CHILD = 40
Tasks
from main import app
@app.task
def task1():
print("this is task 1")
@app.task
def task2():
print("this is task 2")
通过app.task装饰器将该函数装饰成一个celery 的task,就可以在Celery中将该任务send出去了
app.send_task('tasks.ceair.run', args=(start, end, 500, tdays, xdays, "domestic"), queue='Ceair',
routing_key='Ceair')
将任务send到指定的队列中
Worker
celery -A main worker -Q ceair -P gevent -C 100
启动一个worker,监听队列队列为ceair,使用gevent并发的方式
其他常用参数:
-b 连接的broker
-c 并发数
-P 并发的方式 默认为多进程 可选gevent thread
-l 日志的级别
-Q 监听的队列
任务
任务的调用方式有三种
- send_task
不会对方法进行校验 - delay
对apply_async的一个封装 - apply_async
可选参数
task_id:默认为uuid
countdown: 延时时长
expires:任务过期时间
retry:是否重试
priority:优先级 0-255 0最高
queue: 队列
任务状态:
1. PENDING 任务正在等待执行或未知
2. STARTED 任务已经开始
3. SUCCESS 执行成功
4. FAILURE 执行失败
5. RETRY 重试
6. REVOKED 取消