异步方案——RabbitMQ+Celery
1、RabbitMQ介绍和使用
1.1、生产者消费者设计模式
最常用的解耦方式之一,寻找中间人(broker)搭桥,保证两个业务没有直接关联。
生产者生成消息,缓存到消息队列中,消费者读取消息队列中的消息并执行。
1.2. RabbitMQ介绍
-
消息队列是消息在传输的过程中保存消息的容器。
-
现在主流消息队列有:RabbitMQ、ActiveMQ、Kafka等等。
-
RabbitMQ和ActiveMQ比较
系统吞吐量:RabbitMQ好于ActiveMQ
持久化消息:RabbitMQ和ActiveMQ都支持
高并发和可靠性:RabbitMQ好于ActiveMQ -
RabbitMQ和Kafka:
系统吞吐量:RabbitMQ弱于Kafka
可靠性和稳定性:RabbitMQ好于Kafka比较
设计初衷:Kafka是处理日志的,是日志系统,所以并没有具备一个成熟MQ应该具备的特性。
1.3、安装RabbitMQ(centos7)
单机部署
1、创建erlang.repo库
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash
2、安装erlang
yum install erlang
3、创建rabbitmq-server.repo库
curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bash
4、安装rabbitmq-server
yum install rabbitmq-server
5、设置开机启动
chkconfig rabbitmq-server on
6、启动rabbitmq节点
service rabbitmq-server start
其他命令和用法。。
1.4、Python访问RabbitMQ
RabbitMQ提供默认的administrator账户。
用户名和密码:guest、guest
协议:amqp
地址:localhost
端口:5672
查看队列中的消息:sudo rabbitctl list_queues
Python3虚拟环境下,安装pika
pip install pika
生产者代码:rabbitmq_producer.py
import pika
# 链接到RabbitMQ服务器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
#创建频道
channel = connection.channel()
# 声明消息队列
channel.queue_declare(queue='zxc')
# routing_key是队列名 body是要插入的内容
channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("开始向 'zxc' 队列中发布消息 'Hello RabbitMQ!'")
# 关闭链接
connection.close()
消费者代码:rabbitmq_customer.py
import pika
# 链接到rabbitmq服务器
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
# 创建频道,声明消息队列
channel = connection.channel()
channel.queue_declare(queue='zxc')
# 定义接受消息的回调函数
def callback(ch, method, properties, body):
print(body)
# 告诉RabbitMQ使用callback来接收信息
channel.basic_consume(callback, queue='zxc', no_ack=True)
# 开始接收信息
channel.start_consuming()
其他用法
2、Celery介绍和使用
2.1、Celery介绍:
一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。
单个 Celery 进程每分钟可处理数以百万计的任务。
通过消息进行通信,使用消息队列(broker)在客户端和消费者之间进行协调。
2.2、安装Celery:
pip install -U Celery
2.2、 创建Celery实例并加载配置
celery_tasks.main.py
# -*- coding: utf-8 -*-
from celery import Celery
# 创建celery对象
app = Celery('my_celery')
# 加载配置
app.config_from_object('celery_tasks.config')
# 加载可用的任务
app.autodiscover_tasks([
'celery_tasks.my_task',
])
celery_tasks.config.py
# -*- coding: utf-8 -*-
# 指定rabbitmq作为celery的队列,可以改成redis等
broker_url = 'amqp://guest:guest@localhost:5672'
2.3、定义异步任务
定义任务:celery_tasks.my_task.tasks.py
# -*- coding: utf-8 -*-
import time
import requests
from celery_tasks.main import app
@app.task(bind=True, name='spider_task', retry_backoff=3)
def spider_task(self, url):
# 将耗时的代码封装在一个方法中
ret = requests.get(url=url).status_code
if ret != 200:
raise self.retry(exc=Exception('异步失败'), max_retries=3)
time.sleep(1) # 测试耗时
return ret
2.4、启动Celery服务
celery -A celery_tasks.main worker --pool=solo -l info
-A指对应的应用程序, 其参数是项目中 Celery实例的位置。
worker指这里要启动的worker。
-l指日志等级,比如info等级。
celery最新版本需要添加:–pool=solo。
3、测试异步爬虫请求
celery_tasks.usage.py
# -*- coding: utf-8 -*-
from celery_tasks.my_task.tasks import spider_task
url = 'https://www.baidu.com/'
for i in range(10):
print(spider_task.delay(url))
运行usage.py,立即返回全部任务id,同时celery窗口开始运行耗时的任务,完美。
4、扩展
4.1、celery协程工作模式
默认是进程池方式,进程数以当前机器的CPU核数为参考,每个CPU开四个进程。
如何自己指定进程数:celery worker -A proj --concurrency=4
如何改变进程池方式为协程方式:celery worker -A proj --concurrency=1000 -P eventlet -c 1000
# 安装eventlet模块
$ pip install eventlet
# 启用 Eventlet 池
$ celery -A celery_tasks.main worker -l info -P eventlet -c 1000
4.2、docker安装RabbitMQ
下载RabbitMQ最小镜像:
docker pull rabbitmq:alpine
启动RabbitMQ容器:
docker run -d --hostname my-rabbit -p 5672:5672 --name some-rabbit rabbitmq:alpine
记得防火墙和安全组开放5672端口。