本篇内容包括Celery多队列,异步任务失败重试,任务执行过程的监控,以及生产环境下在服务器上如何管理以及维护好每一个队列等等。
1.celery分布式队列,优先级队列,任务失败重试
这里简单的说一下多队列的使用场景,比如说你现在的系统中一共有两个异步任务,其中任务A花费时间大约是5秒,任务B花费时间大约是0.5秒。任务B的重要性比任务任务A要高很多很多。系统每次都会往队列中放10个任务A和一个任务B。在并发量很大的情况下就会因为任务A花费时间较长从而造成队列阻塞,导致后边特别多的任务B需要较长的等待时间才可以被执行。
而如果你的系统中共有两个队列,就可以为不同的队列分别设置worker去各自消费各自的消息,从而达到以上的效果。或者可以设置优先级队列也可以实现。
(1)首先说下多队列
# 配置 queue 队列
CELERY_QUEUES = (
Queue('default', routing_key='default'),
Queue('queue_item', routing_key='apps.item.tasks'),
Queue('queue_daily', routing_key='apps.daily.tasks'),
)
# 配置每一个Task的Router
CELERY_ROUTES = {
'apps.item.tasks.event_list': {
'queue': 'queue_item',
'routing_key': 'apps.item.tasks',
},
'apps.item.tasks.actual_personday': {
'queue': 'queue_item',
'routing_key': 'apps.item.tasks',
},
'apps.item.tasks.reset_progress': {
'queue': 'queue_item',
'routing_key': 'apps.item.tasks',
},
'apps.daily.tasks.repeat_rate': {
'queue': 'queue_daily',
'routing_key': 'apps.daily.tasks',
},
}
CELERY_QUEUES
即为队列的配置,Queue
中第一个参数为队列名称,第二个参数routing_key
即为当前队列所指定的路由键。
CELERY_ROUTES
即为任务分发管理器,可以在这里指定每一个task
所分发的消息队列。只需要指定队列名称以及队列路由键即可。(若是有异步任务没有在这里进行配置,则会放入默认队列中)
之后启动命令为:
celery -A projectName worker -E -l info -n worker_daily -Q queue_daily
celery -A projectName worker -E -l info -n worker_item -Q queue_item
这样就会由 worker_daily
消费队列 queue_daily
。worker_item
消费队列queue_item
。
(2)再说下优先级队列
CELERY_QUEUES = (
Queue('default', routing_key='default'),
Queue('queue_item', routing_key='apps.item.tasks',),
queue_arguments={'x-max-priority': 10}
)
跟多队列相比,优先级队列相对简单一些,只需要将其中一个队列设置为优先级队列即可。这里只是多出了一个queue_arguments={'x-max-priority': 10}
参数。他代表了当前队列的优先级为10(数字越大,优先级就越高),如果有多个优先级队列的话需要注意,低优先级的队列只有当高优先级队列完全阻塞的时候才会进行消费,这里就先拿一个优先级队列来举例。
在使用的时候如下
taskA.delay(queue='queue_item',priority=5)
taskA.delay(queue='queue_item',priority=5)
taskA.delay(queue='queue_item',priority=5)
taskA.delay(queue='queue_item',priority=5)
taskA.delay(queue='queue_item',priority=5)
taskB.delay(queue='queue_item',priority=10)
如上,当把异步任务放进队列的时候指定一下优先级,优先级高的就会优先执行。(这里有一个注意点,就是只有当第一个任务阻塞的时候,之后的异步任务才会进行优先级排序,当前正在消费的任务是不会受到影响的,只会影响他之后的)
(3)任务失败重试
@app.task(bind=True, default_retry_delay=30, max_retries=2)
def taskA(self):
# do something
try:
# do something
except Exception as e:
logger.error('%s taskA Error:' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))) ,e)
self.retry()
default_retry_delay
即为任务失败多少s后发起重试。max_retries
为最大尝试次数。需要失败重试的异步方法需接受一个参数self
。方法中 self.retry() 即可发起重试。
2.Flower监控
至此,异步任务已经配置完成。但是在生产环境下,如何快速准确的找到异常呢?这里我推荐一个工具,叫做flower
。他可以完成对队列以及Worker的监控。可以实时的进行worker的分配以及增加worker的并发数量等一些操作。
(1)首先安装该模块
pip install flower -i https://pypi.douban.com/simple/
(2)然后在项目根目录输入启动命令
celery -A projectName flower --port=5555 --basic_auth=root:abc123
这里的意思为 在端口5555 启动flower . 登录flower的账号和密码为root和abc123
3.Supervistor进程管理
上边已经讲过了,celery若是使用了多队列,那么就会有多个worker启动。每个worker都会需要一条启动命令,这样就会造成很大的负担。每次上线,或者更新异步代码,都要挨个的去启动每一个worker,而且若是因为误操作,或者代码出错导致worker异常宕掉,若无法及时的重启,则可能会造成无法挽回的后果。
所以这里使用supervistor这个进程管理工具来托管每一个worker的正常存活。supervistor可以保证该进行会永久的存活下去,除非手动的杀掉suopervistor。
(1)安装
pip install supervisor -i https://pypi.douban.com/simple/
(2)修改配置文件 /etc/supervisord.conf
, 在配置文件最后加上以下
[program:celery_daily]
command=celery -A projectName worker -E -l info -n worker_daily -Q queue_daily
directory=/user/web/oa
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=QUIT
stdout_logfile=/user/web/supervisor/logs/celery_daily.log
[program:celery_item]
command=celery -A projectName worker -E -l info -n worker_item -Q queue_item
directory=/data/www/web/oa
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=QUIT
stdout_logfile=/user/web/supervisor/logs/celery_item.log
[program:celery_flower]
command=celery -A projectName flower --port=5555 --basic_auth=root:abc123
directory=/user/web/oa
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=QUIT
stdout_logfile
为指定的日志文件存储的地方。directory
为指定命令执行的地方,command
就是在directory
目录下所执行的命令
(2)配置好后(wq保存退出),使用以下命令启动supervistor
supervistord -c /etc/supervisord.conf
(3)使用以下命令进入supervistor管理
supervistorctl
(4)常用的命令
start name 启动名为name的program
start all 全部启动
stop all 全部停止
restart all 全部重启