celery+rabbitmq消息队列使用笔记

安装

rabbitmq安装
celery安装

pip install celery

使用

基本组件

Queue(队列)用于存储消息,多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
Exchange(交换机),分为Direct(默认是这个,通过routingkey来判断被哪个队列接收,Topic,匹配方式,Fanout广播方式
worker(消费者),由一堆task组成,从queue中取数据然后执行

celery 发送消息的三种方式

1: delay(*args, **kwargs), 简便方法

task.delay(arg1, arg2, kwarg1='x', kwarg2='y')

2: apply_async(args[, kwargs[, …]]),有更多的配置选项

task.apply_async(args=[arg1, arg2], kwargs={'kwarg1': 'x', 'kwarg2': 'y'})

3: app.send_task(name, args=None, kwargs=None,… )和Task.apply_async() 参数相同,name是task名字,比如用@app.task(name=xxx)设置或默认task.add

app.send_task('tasks name', args=[1,2], queue="queue name")
tasks装饰器配置,只列出常用的
from .models import User
@app.task
def create_user(username, password):
    User.objects.create(username=username, password=password)
   
@app.task(serializer='json')
def create_user(username, password):
    User.objects.create(username=username, password=password)

绑定 tasks, 如果绑定,task实例会作为参数传递到任务方法中(第一个参数为self),可以访问task实例的所有属性。

logger = get_task_logger(__name__)

@task(bind=True)
def add(self, x, y):
    logger.info(self.request.id)

定义任务的基类,可以以此来定义回调函数,默认是Task类,我们也可以定义自己的Task类

import celery
class MyTask(celery.Task):
	def on_success(self, retval, task_id, args, kwargs):
        print(f'success,task id为:{task_id}')
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        print('{0!r} failed: {1!r}'.format(task_id, exc))

@task(base=MyTask)
def add(x, y):
    raise KeyError()

任务名称,默认是本函数的路径+名字

>>> @app.task(name='sum-of-two-numbers')
>>> def add(x, y):
...     return x + y

>>> add.name
'sum-of-two-numbers'

celery配置

常用配置

# celeryconfig.py
# 可接收数据类型白名单,除设置的以外将被抛弃
accept_content = ['json']

# 默认是开启的
enable_utc = True
# 时区
timezone = 'Asia/Shanghai'

# 默认结果格式化方式,默认是json
result_serializer = 'json'

broker_url = 'amqp://{user}:{password}@{host}:{port}/{vhost}'.format(
    user='xx',
    password='123',
    host='127.0.0.1',
    port='5672',
    vhost='x'
)

include = ['mqworker.tasks']
worker_concurrency = 2
一个简单例子
mqworker
-- __init__.py
-- celery.py
-- task.py

# __init__.py
# 如果引用目录没有当前的话,这里加一下
import os
import sys
HOME = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(HOME)
sys.path.append(os.path.join(HOME, 'config'))

#celery.py
from celery import Celery
import celeryconfig

mq_worker = Celery('celery')
mq_worker.config_from_object(celeryconfig)

#task.py
from celery import Task

from mqworker.celery import mq_worker

class BaseTask(Task):
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        print('task failed, id:{task_id}')

    def on_success(self, retval, task_id, args, kwargs):
        print(f'task success, id:{task_id}')

# name默认是“mqworker.tasks.mq_test1”
# bind为True后,可以使用self
@mq_worker.task(name="mq_test1", bind=True, base=BaseTask)
def mq_test1(self, x, y):
    print('test1--', x, y)
一些心得
  • 发送消息方式我常用send_task,只需使用task名称,无需import task的函数,方便不同系统间调用。
  • 如果发消息不指定queue,app.send_task(‘tasks name’, args=[1,2]),则会通过task_routes(task和queue的关联)和task_queues(queue和交换机的关联以及和routes的那个key的绑定)的配置放到对应的队列中,如果相应的队列没有worker取,则在队列中存着。
  • 如果一个worker有多个task,每个task绑定的队列(task_routes)不同,比如绑定关系:task1=queue1,task2=queue2。worker启动celery -A mqworker worker -l info -Q queue1,只指定接收queue1的数据,但是因为worker里同时有task1和task2,这时将task2的请求指定到queue1里面,同样是可以完成task2执行的;如果指定的queue是queue2,这时因为没有worker取queue2的数据,则无法执行,如果再启动一个worker,指定celery -A mqworker worker -l info -Q queue2,就会消费掉这个消息。queue只是通道,消息是否能消费掉,主要是看发送消息指定的那个taskname是否在接收这个queue的worker里,也就是说消息分发主要是靠发消息时指定queue分发,不指定则走配置,只要queue绑定的worker有对应的task就能消费掉。
  • 如果不配置task_queues,使用celery -A mqworker worker -l info -Q test1,test2,push,test1会自动配置为test1 exchange=test1(direct) key=test1,这样每个队列会独享一个交换机,如果队列数大于cpu数,效率会降低,在配置文件里设置一>下,则可以人为控制哪些队列共享一个交换机
  • 系统通过队列分流,虽然系统前期流量不大,但还是按照这个分流的做,worker可以同时绑定所有的队列,后期流量上来,可以将woker分散到不同的机器,每个worker绑定不同的队列,消费不同的消息
  • 如果指定queue发消息的话,那一定要知道接收这个queue的worker里有对应的task,不然就失败了
  • 接入某个queue的话,必须具备这个queue所有的处理方法,否则worker都会取出来,然后找不到这个方法的话就会报KeyError

参考

https://docs.celeryproject.org/en/stable/index.html
https://www.celerycn.io

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值