Celery入门与Flower监控

Celery 的应用场景

  • Web应用
  1. 用户发送一个需要较长时间处理的请求;
  2. 传统思想会等待请求的结果(即常见到的转圈圈);
  3. 为了避免用户一直等待响应结果,在服务端可以通过异步的方式处理需要花费较长时间请求(例如调用外部服务API类似叮叮通知,邮件系统等);
  4. 服务后端创建相应的任务(创建任务是很快速的过程,执行具体任务才是真正耗时的操作),并将任务ID返回(响应)给用户;
  5. 在前端看来,此次请求已经成功了,但是具体邮件是不是发成功了,没有直接给出结果,如果想看状态或结果,只需要拿到返回的任务ID再发送请求即可;
  6. 用户可主动通过ID查看任务的执行进度,或通过前端轮询查看任务处理进度,常见的进度条就可以通过轮询实现;
  7. 如果用户不关心邮件发送的结果,就直接该干嘛干嘛去了,不用再关心;
  8. 如果需要动态监控任务状态及结果,从后台服务端看,任务结束后需要调用回调函数,将任务处理后的结果及数据进行转存或推送。
  • 定时任务

有一些业务场景可能需要做定时任务,如定时发送邮件等

Celery的几个组件

  • 任务
    即执行异步工作的载体,可以接受参数并执行异步工作,通过ID监控执行状态
  • 中间件(broker)或消息队列(massage queue)
    连接了异步任务的创建者和任务的执行者,通常任务的创建者创建较快,但是执行者并不能相同节奏的完成,即需要一个管道,任务生产者将任务放入其中供执行者从中领取
  • worker
    相当于一个劳动力或者雇工,给他一个消息队列,就能执行队列中交给的任务

Celery 架构图

在这里插入图片描述

从最简单的应用开始

(安装环境以linux或macOS为例)

  • 安装虚拟环境(可以参考网络其他教程,此处仅列出大致命令)
$ pip3 install virtualenvwrapper -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host mirrors.aliyun.com
$ mkdir ~/.virtualenv
$ vim ~/.brashrc
# 在文件末尾追加
export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh

$ source ~/.bashrc
$ mkvirtualenv celeryVirtualEnv
$ workon customized_upload_env
$ pip install redis==3.5.3  # 安装redis客户端
$ pip install celery==5.1.2  # 安装celery
  • 安装redis服务
    一般redis服务端安装在本机环境中,虚拟环境安装客户端
    Macbook 使用brew安装redis
    # brew install redis
    # redis-server
    # redis-cli 能够正常进入redis命令行即可
  • 编写测试程序
$ cat tasks.py
from celery import Celery

APP_NAME = 'main'
BROKER_NAME = 'redis://127.0.0.1:6379/0'
BACKEND = 'redis://127.0.0.1:6379/1'
app = Celery(name=APP_NAME, broker=BROKER_NAME,backend=BACKEND)

@app.task
def reverse(my_str):  # 异步任务的功能是将传递的字符串反转
    return my_str[::-1]
    
$ cat main.py
from tasks import reverse

response = reverse.delay("hello world")
print(response)
print(response.get())
  • 启动celery服务
$ celery -A tasks worker --loglevel=info


celery@192.168.0.104 v5.1.2 (sun-harmonics)

Darwin-20.5.0-x86_64-i386-64bit 2021-07-25 09:51:18

[config]
.> app:         __main__:0x7fa82cf043d0
.> transport:   redis://127.0.0.1:6379/0
.> results:     redis://127.0.0.1:6379/1
.> concurrency: 4 (prefork)
.> task events: OFF (enable -E to monitor tasks in this worker)

[queues]
.> celery           exchange=celery(direct) key=celery


[tasks]
  . tasks.reverse

[2021-07-25 09:51:18,496: INFO/MainProcess] Connected to redis://127.0.0.1:6379/0
[2021-07-25 09:51:18,505: INFO/MainProcess] mingle: searching for neighbors
[2021-07-25 09:51:19,531: INFO/MainProcess] mingle: all alone
[2021-07-25 09:51:19,554: INFO/MainProcess] celery@192.168.0.104 ready.
  • 测试脚本
    打开一个新的终端,运行命令 python main.py,在celery 服务端看到如下信息:
[2021-07-25 09:52:15,150: INFO/MainProcess] Task tasks.reverse[b7942a50-8813-4d38-a647-1182c6a300db] received
[2021-07-25 09:52:15,169: INFO/ForkPoolWorker-2] Task tasks.reverse[b7942a50-8813-4d38-a647-1182c6a300db] succeeded in 0.013528297000000578s: 'dlrow olleh'
  • 脚本运行终端输出
    打印的第一个值是任务ID,打印的第二个值是任务执行成功后return的结果
$ python main.py
b7942a50-8813-4d38-a647-1182c6a300db
dlrow olleh

项目应用

celery应用在项目中,通常情况较复杂,涉及到多个异步任务的执行,任务的调度,回调函数,日志,重试机制等

使用配置文件

生产项目一般会将配置信息统一放在配置文件中,以便在配置发生变化的时候能够减少代码的修改

celery_conf.py (celery 4.0版本之后配置项都使用小写代替)

 broker_url = 'redis://127.0.0.1:6379/0'
 result_backend = 'redis://127.0.0.1:6379/1'
 task_serializer = 'json'
 result_serializer = 'json'
 accept_content = ['json']
 timezone = 'Asia/Shanghai'

 task_queues = {
    'my_reverse_queue':{
        'exchange':'reverse_str',
        'exchange_type': 'direct',
        'routing_key': 'reverse_str'
    },
}

task_routes = ({
    'tasks.reverse':{
        'queue': 'my_reverse_queue',
        'routing_key': 'reverse_str',
        'serializer':'json',
    }
},)

修改tasks.py

from celery import Celery
import celery_conf

APP_NAME = 'tasks'
# BROKER_NAME = 'redis://127.0.0.1:6379/0'
# BACKEND = 'redis://127.0.0.1:6379/1'
app = Celery(name=APP_NAME)
app.config_from_object(celery_conf)

@app.task
def reverse(my_str):
    return my_str[::-1]

启动命令修改

celery -A tasks --logleval=info -Q my_reverse_queue

在这里插入图片描述
创建日志目录

tasks 同级目录创建 logs 文件夹,修改服务启动命令
celery -A tasks worker --loglevel=info -Q my_reverse_queue --pidfile=logs/%n.pid --logfile=logs/%n%I.log
运行服务会自动在logs中创建.pid文件及worker log文件,运行python main.py 可以在其中某个日志文件中看到任务的执行结果

关于命令中的%h %I %n 请看如下(内容来自官方文档,笔者认为入门不必特别在意这些)

# Node name replacements
	%p: Full node name.
	%h: Hostname, including domain name.
	%n: Hostname only.
	%d: Domain name only.
	%i: Prefork pool process index or 0 if MainProcess.
%I: Prefork pool process index with separator.

  For example, if the current hostname is george@foo.example.com then these will expand to:
	--logfile=%p.log -> george@foo.example.com.log
	--logfile=%h.log -> foo.example.com.log
	--logfile=%n.log -> george.log
	--logfile=%d.log -> example.com.log

# Prefork pool process index

The prefork pool process index specifiers will expand into a different filename depending on the process that’ll eventually need to open the file.
This can be used to specify one log file per child process.
Note that the numbers will stay within the process limit even if processes exit or if autoscale/maxtasksperchild/time limits are used. That is, the number is the process index not the process count or pid.

%i - Pool process index or 0 if MainProcess.

  Where -n worker1@example.com -c2 -f %n-%i.log will result in three log files:
	worker1-0.log (main process)
	worker1-1.log (pool process 1)
	worker1-2.log (pool process 2)

%I - Pool process index with separator.

  Where -n worker1@example.com -c2 -f %n%I.log will result in three log files:
	worker1.log (main process)
	worker1-1.log (pool process 1)
	worker1-2.log (pool process 2)

编写启动脚本

新建文件 start.sh,内容如下

export AUTHLIB_INSECURE_TRANSPORT=true
celery -A tasks worker --loglevel=info -Q my_reverse_queue --pidfile=logs/%n.pid --logfile=logs/%n%I.log -D
# -D 表示后台运行

使用flower web 监控任务执行

通过日志可以看到任务执行的结果,而图形界面是对新手非常友好的。flower 就是这样一个可以很好与celery集成的监控任务执行情况的插件

安装flower
pip install flower==1.0.0
在启动脚本中追加flower启动命令
nohup celery -A tasks flower --address=127.0.0.1 --port=5566 > logs/flower.log 2>&1 &
nohup 表示后台运行
flower日志文件会存储在logs/flower.log文件中
启动服务
sh start.sh
浏览器访问 http://127.0.0.1:5566/
运行 python3 main.py,在flower的界面 Task 栏查看任务的状态和执行结果

Tips

  1. celery 服务启动后,调试过程如果修改了代码,需要停止之前的服务,通过执行以下命令ps -ef | grep celery | grep -v 'grep' | awk '{print $2}' |xargs kill -9 终止celery服务
    建议进入redis-cli, 执行FLUSHDB命令清除;
  2. 使用task_entry.get()时如果task发生异常,.get()也会抛出异常,为了避免这种情况,可以增加参数.get(propagate=False),然后通过task_entry.traceback 查看异常;
  3. 多任务的情况,并行情况可以通过在配置文件中新增queue和routing,在启动脚本中另增加一条启动命令(指定对应的queue)实现。串行的情况涉及到任务链式操作,可查阅文档

Link

Github source code
Celery 官方文档
Flower 官方文档

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值