Celery异步框架学习与理解

生产者与消费者模式

在学习celery之前,我们先了解下生产者与消费者模式。
Celery异步框架学习与理解_第1张图片

  • 在实际开发中,经常会遇到某个api负责生产数据,这些数据由另一个api处理,生产数据的为生产者,处理数据的为消费者。
  • 我举个例子来简单解释下这个设计模式吧。例如:一个母亲正在蒸包子,然后把蒸好的包子放在了客厅桌子上,这时姐姐就过来把包子吃了,然后母亲又整了一笼包子放在了客厅的桌子上,这时候你又把包子吃了。
  • 在上面例子中,母亲是个生产者,客厅的桌子时缓冲区,你和姐姐都是消费者。

优点:

  • 解耦 完整性 独立性
    假设生产者和消费者分别是两个类。如果让生产者直接区调用消费者的某个方法,那么生产者就会依赖消费者(也就是耦合)。将来如果消费者代码发生改变,可能会影响到生产者。如果两者都依赖某个缓冲区,两者就没直接关系了,耦合度就降低了。

支持并发

  • 生产者直接调用消费者,还有一个弊端,就是阻塞,在消费者被调用时,一直没有返回数据,生产者只好一直等在那边,浪费资源。
  • 使用了生产者与消费者模式之后,生产者和消费者两个独立的并发主体。生产者直接生产数据直接扔到缓存区,就可一直接生产下一个数据,不用等待消费者处理。

中间人broker
可以由redis,RabbitMQ,mongoDB等等,建议RabitMQ稳定性极好。

Celery基本介绍

  • celery介绍:
    1.一个简单灵活、处理大量消息的分布式系统,可以在一台或者多台机器上运行。
    2.celery是一个功能完备即插即用的任务队列。
    3.单个celery进程每分钟可以处理以百万计的任务。
    4.通过消息进行通讯,使用生产者与消费者之间进行协调。

任务队列
任务队列是一种在线程或机器间分发任务的机制。

消息队列
消息队列的输入是一个工作的单元,独立的(职程)Worker进程持续监视队列中是否由需要处理的新任务。
Celery异步框架学习与理解_第2张图片

celery的架构

celery架构由三部分组成:消息中间件(broker),任务执行单元(worker),任务执行结果储存(task store)。

  • 消息中间件
    celery本身不提供消息服务,但是可以方便的和第三方提的消息中间件集成,redis,mongodb,rabbitMq。
  • 任务执行单元
    worker是celery提供的任务执行单元,worker并发的运行在分布式的系统节点中。
  • 任务储存结果
    task store用来存储worker执行的任务结果,celery支持以不同的方式存储任务的结果,redis,django orm,mongodb。

接下来介绍celery和rebbitMQ的使用

  • 安装celery
    pip install celery

  • 安装rabbitMQ
    pip install redbbitmq-server

  • docker安装 默认5672端口
    sudo docker pull rabbitmq:3-management sudo docker run -d --name rabbit --hostname rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management

  • 配置rabbitMQ
    sudo rabbitmqctl add_user myuser mypassword sudo rabbitmqctl add_vhost myvhost sudo rabbitmqctl set_user_tags myuser mytag sudo rabbitmqctl set_permissions -p myvhost myuser ".*" ".*" ".*"

  • 使用rabbitMQ的优势

    1.从社区活跃度
    按照目前网络上的资料,RabbitMQ 、activeM 、ZeroMQ 三者中,综合来看,RabbitMQ 是首选。
    2.持久化消息比较
    ZeroMq 不支持,ActiveMq 和RabbitMq 都支持。持久化消息主要是指我们机器在不可抗力因素等情况下挂掉了,消息不会丢失的机制。
    3.综合技术实现
    可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等等。
    4.高并发
    毋庸置疑,RabbitMQ 最高,原因是它的实现语言是天生具备高并发高可用的erlang 语言。
    5.比较关注的比较, RabbitMQ 和 Kafka
    RabbitMq 比Kafka 成熟,在可用性上,稳定性上,可靠性上, RabbitMq 胜于 Kafka (理论上)。

Name Status Monitoring Remote
RabbitMQ Stable Yes Yes
Redis Stable Yes Yes
Zookeeper Experimental No No

celery在Django中的使用
1.在项目工程文件夹中创建celery文件
Celery异步框架学习与理解_第3张图片
2.在celery中编写代码

# 导入新的绝对路径包和文件夹
from __future__ import absolute_import,unicode_literals
import os

# 导入celery框架
from celery import Celery

# 为celery设置django配置文件进行配置
os.environ.setdefault('DJANGO_SETTINGS_MODULE','pro_demo.settings')

# 实例化Celery对象 指定文件
app = Celery('pro_demo')

# 使用这个配置不需要序列化
# 配置子进程对象
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix. 配置必须以 “CELERY_ ”开头
app.config_from_object('django.conf:settings',namespace='CELERY')

# 从django所有应用配置中加载任务模块
app.autodiscover_tasks()

# 开启debug模式
@app.task(bind=True)
def debug_task(self):
    print('Request:{}'.format(self.request))

3.在__init__文件中编写代码,这样便于django启动程序时便于加载

from __future__ import absolute_import,unicode_literals

# 这样配置可以保证每次导入模块不出错
# 每次开启celery任务时必须使用shared_task装饰器
from .celery import app as celery_app

# 公开接口 可以是元祖  最好选择列表 在这里我们选择元祖因为官方这么干的
__all__ = ('celery_app',)

这样celery就配置好了 下面写个任务实现一下程序的效果:
1.建立一个demo应用

Celery异步框架学习与理解_第4张图片
2.在demo_app中创建一个tasks.py的文件

from __future__ import absolute_import,unicode_literals

from celery import shared_task

from demo_app.models import UserInfo

@shared_task
def add(x,y):

    return x + y

@shared_task
def mul(x,y):

    return x * y

@shared_task
def count_userinfo():

    return UserInfo.objects.count()

@shared_task
def rename_userinfo(user_id,name):

    ret = UserInfo.objects.get(id=user_id)
    ret.name = name
    ret.save()

启动celery
celery -A pro_demo worker -l info
以上demo适合django版本在1.8及更新版本。
在程序中实际应用
例如发送邮件,因为在用户频繁发起邮件请求时,多用户同时请求,容易阻塞,或者服务器宕机,容易让客户体验效果极差。
1.在demo_app中创建tasks.py文件编写发送邮件逻辑
Celery异步框架学习与理解_第5张图片
2.编写tasks.py

from __future__ import absolute_import,unicode_literals

from celery import shared_task

from django.core.mail import send_mail

from pro_demo import settings


@shared_task
def send_active_email(email):

    subject = "邮件标题"
    message = ""
    email_list = [email]
    from_email = settings.EMAIL_FROM
    html_msg = '

这是个异步发送测试

'
try: send_mail(subject=subject, message=message, from_email=from_email, recipient_list=email_list, html_message=html_msg) except Exception as e: print(e)

3.编写视图
Celery异步框架学习与理解_第6张图片

import json

from django import http
from django.shortcuts import render

# Create your views here.
from django.views import View

from app.demo_app.tasks import send_active_email

class SendEmailDemo(View):

    def get(self,request):
		# 获取邮箱
        data = json.loads(request.body.decode())
        email = data.get('email')
		# 异步发送邮件
        send_active_email.delay(email)

        return http.HttpResponse("ok")

4.路由编写

Celery异步框架学习与理解_第7张图片

from django.conf.urls import url

from app.demo_app import views

urlpatterns = [

    url('^emails/send/',views.SendEmailDemo.as_view())
]

5.工程项目路由编写
Celery异步框架学习与理解_第8张图片

"""pro_demo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r'^',include('app.email_demo.urls')),
    url(r'^',include('app.demo_app.urls'))
]

6.celery中加载文件
Celery异步框架学习与理解_第9张图片

# 导入新的绝对路径包与编码包
from __future__ import absolute_import,unicode_literals

import os

# 导入celery框架
from celery import Celery

# 为celery设置django配置文件进行配置
os.environ.setdefault('DJANGO_SETTINGS_MODULE','pro_demo.settings')

# 实例化Celery对象 指定文件
app = Celery('pro_demo')

# 使用这个配置不需要序列化
# 配置子进程对象
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings',namespace='CELERY')

# 从django所有应用配置中加载任务模块
app.autodiscover_tasks(['app.demo_app'])


@app.task(bind=True)
def debug_task(self):
    print('Request:{}'.format(self.request))

7.在settings中编写邮箱配置文件
Celery异步框架学习与理解_第10张图片

# 指定邮件发送后端
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 邮件服务器
EMAIL_HOST = 'smtp.163.com'
# smtp 默认端口号是 25
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = '你自己的@163.com'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'xxxxxx'

#收件人看到的发件人
EMAIL_FROM = 'ItCAST邮件测试<你自己的@163.com>'

8.开启celery
celery -A pro_demo worker -l info

Celery异步框架学习与理解_第11张图片
9.postman测试
Celery异步框架学习与理解_第12张图片
成功接收
Celery异步框架学习与理解_第13张图片
觉得有用记得点赞哦!!!

你可能感兴趣的:(python)