消息队列的应用和celery异步化操作
Django中的中间件用更准确的方法应该称为拦截过滤器。消息队列能够解决消息传递的问题,分为两种模式:点到点传递、发布订阅。对于网站的优化的两大定律,第一定律就是使用缓存,通过空间换时间的模式;第二定律就是使用消息队列,主要解决解耦、削峰和异步化的问题。由于队列是先进先出,所以消息队列还能够保证顺序性。比如像电商网站的下订单和受理订单,消息队列就能做到上游节点和下游节点的解耦合。
消息队列产品:对于Redis,并不是专业的消息队列服务器,但是Redis的List类型可以用来实现消息队列服务,通过lpush + rpop
或者rpush + blpop
就能实现将列表改造为队列。RabbitMQ:爱立信;Kafka; RockeMQ;ActiveMQ。
业务背景
在上传文件到七牛云的过程中,可能需要验证文件,生成日志,就需要花费较多的时间,为了不让耗时间的任务堵塞后面的任务,将此任务交给其他进程来处理而当前进程不会被阻塞,当前的线程则可以立马给用户响应。由于耗时间的任务对接可能不稳定的三方平台,所以需要进行异步化处理。在Django中就可以使用Celer来进行异步化的操作。
使用celery
# 这里推荐直接安装celery,而不使用django-celery
pip install celery -i https:pypi.doubanio.com/simple
创建celery对象进行异步化处理
这里我将celery对象直接放在Django项目的__init__
文件中。创建好了celery()
对象中,添加如下参数
import celery
app = celery.Celery('izufang',
broker='',
backend='')
# 发现需要异步化的任务
app.autodiscover_tasks(['common', ])
-
izufang
这个名称是当前celery对象对应的文件的名称,由于将其放在__init__
文件中,所以这里直接传入izufang
,若celery对象创建在izuanfg/foo.py
文件中,这里的第一个参数需要写izufang.foo
。 -
borker
:提供消息队列服务的对象 -
backend
:消息执行结果的持久化地址 -
由于发送短信验证码和上传七牛云的图片都写在
commom
模块下,所以通过app.autodiscover_tasks(['common', ])
找到需要这个包下面需要异步化执行的任务。 -
在需要异步化的任务前面,需要打上装饰器
@app.task
@app.task def send_sms_by_aliyun(tel, code): """发送短信验证码,阿里云网关""" pass @app.task def upload_file_to_qiniu(file_path, filename): """将文件上传到七牛云存储""" pass @app.task def upload_stream_to_qiniu(file_stream, filename, size): """将数据流上传到七牛云存储""" pass
-
在视图函数中,对需要放入消息队列的操作,添加一个delay方法让函数异步化执行
@api_view(('GET', )) def get_code_by_sms(request, tel): """获取短信验证码""" # ... # 通过异步化函数的delay方法让函数异步化执行(放入消息队列) send_sms_by_aliyun.delay(tel, code)
假如发送短信功能有延迟,这样就能够推迟执行,不会阻塞后面的任务。即使下游节点崩溃掉,放入消息队列的任务依然存在。
配置好了上面的操作,当我们重启项目再次请去api/mobile/<tel>
就能够返回响应
但是返回了响应,消息不会立马发送给用户,而是存在了消息队列中,我们在redis服务器中可以查看
127.0.0.1:54321> select 1
OK
127.0.0.1:54321[1]> keys *
1) "celery"
2) "_kombu.binding.celery"
127.0.0.1:54321[1]> type celery
list
127.0.0.1:54321[1]> lrange celery 0 -1
异步化任务的受理
在上面发送了短信之后,发送短信任务已近存入消息队列当中,这是需要受理了这个任务,才能成功发送短信。对于发送任务的机器和受理任务的机器可以是两台不同的机器,若要受理任务,需要先完善__init__
中的代码
import os
import celery
from izufang import settings
# 加载环境
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'izufang.settings')
# 创建celery对象,指定模块、消息队列和持久化方式
app = celery.Celery('izufang',
broker='redis://:5201314@Dcs@121.199.18.215:54321/1',
backend='redis://:5201314@Dcs@121.199.18.215:54321/2')
# 从配置文件中读取Celery相关配置
app.config_from_object('django.conf:settings')
# 发现需要异步化的任务
app.autodiscover_tasks(['common', ])
在终端中可以执行如下代码:
celery -A izufang worker -l debug
就可以完成短信的发送了
感谢大家的阅读,我会持续更新❤❤