rabbitmq python高性能开发_python 全栈开发,Day140(RabbitMQ,基于scrapy-redis实现分布式爬虫)...

rabbitMQ是一款基于AMQP协议的消息中间件,它能够在应用之间提供可靠的消息传输。在易用性,扩展性,高可用性上表现优秀。使用消息中间件利于应用之间的解耦,生产者(客户端)无需知道消费者(服务端)的存在。而且两端可以使用不同的语言编写,大大提供了灵活性。

1341090-20181010152210469-1337110037.jpg

官方文档:

中文文档:

rabbitMQ安装

linux平台

ContractedBlock.gif

ExpandedBlockStart.gif

1.安装配置epel源

rpm-ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm2.安装erlang

yum-y install erlang3.安装RabbitMQ

yum-y install rabbitmq-server4.启动服务

centos6:

service rabbitmq-server start

centos7:

systemctl start rabbitmq-server5.启动web管理插件

rabbitmq-plugins enable rabbitmq_management6.重启rabbitmq生效web插件

centos6:

service rabbitmq-server restart

centos7:

systemctl restart rabbitmq-server

访问页面: http://ip地址:15672

#添加账户

rabbitmqctl add_user admin 123456

#设置为超级管理员

rabbitmqctl set_user_tags admin administrator

View Code

mac

bogon:~yuan$ brew install rabbitmq

bogon:~ yuan$ export PATH=$PATH:/usr/local/sbin

bogon:~ yuan$ rabbitmq-server

windows

ContractedBlock.gif

ExpandedBlockStart.gif

1.安装erlang

双击运行opt_win64_21.1.exe2.安装rabbitmq

双击运行 rabbitmq-server-3.7.8

3.添加windows环境变量

Path=%ERLANG_HOME%\bin;%RABBITMQ_SERVER%\sbin4.检测rabbitmq状态

rabbitmqctl status5.启动web管理插件

rabbitmq-plugins enable rabbitmq_management6.登录web管理界面,账号密码默认都是guest,guest

http://127.0.0.1:15672/rabbitmq5672 是提供客户端连接的端口, 15672是提供web管理的端口

View Code

rabbitMQ工作模型

简单模式

1341090-20181010211355455-457602908.png

安装pkia

pip3 install pika

示例

注意:本环境的RabbitMQ是安装在Centos 7 x64系统上面的,IP地址为:192.168.142.128,默认端口5672

生产者

producer.py

ContractedBlock.gif

ExpandedBlockStart.gif

importpika#基于socket连接中间服务器上的rabbitmq

connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.142.128'))#创建对象

channel =connection.channel()#声明一个名为hello的队列

channel.queue_declare(queue='hello')#插数据

channel.basic_publish(exchange='', #交换机

routing_key='hello', #指定的队列名称

body='Hello Yuan!') #值

print("[x] Sent 'Hello Yuan!'")

connection.close()

View Code

注意:在简单模式中,是没有交换机的。所以exchange参数的值为空

消费者

consumer.py

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection= pika.BlockingConnection(pika.ConnectionParameters(host='192.168.142.128'))

channel=connection.channel()#声明一个名为hello的队列

channel.queue_declare(queue='hello')#确定回调函数

defcallback(ch, method, properties, body):print("Received %r" %body)

channel.basic_consume(callback,

queue='hello',

no_ack=True)print('[*] Waiting for messages. To exit press CTRL+C')

channel.start_consuming()

View Code

先执行producer.py,输出:

[x] Sent 'Hello Yuan!'

再执行consumer.py,输出:

[*] Waiting for messages. To exit press CTRL+C

Received b'Hello Yuan!'

消费者接收到了 Hello Yuan!

为什么消费者要声明一个名为hello的队列呢?生产者,不是明明已经声明了队列了吗?

注意:

如果生产者先运行,那么就会创建hello队列。那么消费者运行时,就不会创建hello队列。这句代码,不会执行!

channel.queue_declare(queue='hello')

如果消费者先执行,那么这里就会创建。假设没有创建hello队列,执行就会报错!

其实生产者和消费者,谁来创建,都无所谓。只要保证队列存在就可以了!

相关参数

(1) no-ack = False

如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。

回调函数中的ch.basic_ack(delivery_tag=method.delivery_tag)

basic_comsume中的no_ack=False

消息接收端应该这么写:

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection=pika.BlockingConnection(pika.ConnectionParameters(

host='10.211.55.4'))

channel=connection.channel()

channel.queue_declare(queue='hello')defcallback(ch, method, properties, body):print("[x] Received %r" %body)importtime

time.sleep(10)print 'ok'ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(callback,

queue='hello',

no_ack=False)print('[*] Waiting for messages. To exit press CTRL+C')

channel.start_consuming()

View Code

(2) durable :消息不丢失

生产者

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection= pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))

channel=connection.channel()#make message persistent

channel.queue_declare(queue='hello', durable=True)

channel.basic_publish(exchange='',

routing_key='hello',

body='Hello World!',

properties=pika.BasicProperties(

delivery_mode=2, #make message persistent

))print("[x] Sent 'Hello World!'")

connection.close()

View Code

消费者

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection= pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))

channel=connection.channel()#make message persistent

channel.queue_declare(queue='hello', durable=True)defcallback(ch, method, properties, body):print("[x] Received %r" %body)importtime

time.sleep(10)print 'ok'ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(callback,

queue='hello',

no_ack=False)print('[*] Waiting for messages. To exit press CTRL+C')

channel.start_consuming()

View Code

(3) 消息获取顺序

默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。

channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection= pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4'))

channel=connection.channel()#make message persistent

channel.queue_declare(queue='hello')defcallback(ch, method, properties, body):print("[x] Received %r" %body)importtime

time.sleep(10)print 'ok'ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_qos(prefetch_count=1)

channel.basic_consume(callback,

queue='hello',

no_ack=False)print('[*] Waiting for messages. To exit press CTRL+C')

channel.start_consuming()

View Code

exchange模型

3.1 发布订阅

1341090-20181010153340745-2036856797.png

发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。

关键参数:

exchange type = fanout

生产者

ContractedBlock.gif

ExpandedBlockStart.gif

importpikaimportsys

connection=pika.BlockingConnection(pika.ConnectionParameters(

host='localhost'))

channel=connection.channel()

channel.exchange_declare(exchange='logs',

type='fanout')

message= ' '.join(sys.argv[1:]) or "info: Hello World!"channel.basic_publish(exchange='logs',

routing_key='',

body=message)print("[x] Sent %r" %message)

connection.close()

View Code

消费者

ContractedBlock.gif

ExpandedBlockStart.gif

importpika

connection=pika.BlockingConnection(pika.ConnectionParameters(

host='localhost'))

channel=connection.channel()

channel.exchange_declare(exchange='logs',

type='fanout')

result= channel.queue_declare(exclusive=True)

queue_name=result.method.queue

channel.queue_bind(exchange='logs',

queue=queue_name)print('[*] Waiting for logs. To exit press CTRL+C')defcallback(ch, method, properties, body):print("[x] %r" %body)

channel.basic_consume(callback,

queue=queue_name,

no_ack=True)

channel.start_consuming()

View Code

3.2 关键字发送

1341090-20181010153614011-1524802879.png

关键参数

exchange type = direct

之前事例,发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。

ContractedBlock.gif

ExpandedBlockStart.gif

importpikaimportsys

connection=pika.BlockingConnection(pika.ConnectionParameters(

host='localhost'))

channel=connection.channel()

channel.exchange_declare(exchange='direct_logs',

type='direct')

result= channel.queue_declare(exclusive=True)

queue_name=result.method.queue

severities= sys.argv[1:]if notseverities:

sys.stderr.write("Usage: %s [info] [warning] [error]\n" %sys.argv[0])

sys.exit(1)for severity inseverities:

channel.queue_bind(exchange='direct_logs',

queue=queue_name,

routing_key=severity)print('[*] Waiting for logs. To exit press CTRL+C')defcallback(ch, method, properties, body):print("[x] %r:%r" %(method.routing_key, body))

channel.basic_consume(callback,

queue=queue_name,

no_ack=True)

channel.start_consuming()

View Code

3.3 模糊匹配

1341090-20181010153953154-519346735.png

关键参数

exchange type =topic

发送者路由值 队列中

old.boy.python old.* --不匹配

old.boy.python old.#-- 匹配

在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。

# 表示可以匹配 0 个 或 多个 单词

* 表示只能匹配 一个 单词

示例:

ContractedBlock.gif

ExpandedBlockStart.gif

importpikaimportsys

connection=pika.BlockingConnection(pika.ConnectionParameters(

host='localhost'))

channel=connection.channel()

channel.exchange_declare(exchange='topic_logs',

type='topic')

result= channel.queue_declare(exclusive=True)

queue_name=result.method.queue

binding_keys= sys.argv[1:]if notbinding_keys:

sys.stderr.write("Usage: %s [binding_key]...\n" %sys.argv[0])

sys.exit(1)for binding_key inbinding_keys:

channel.queue_bind(exchange='topic_logs',

queue=queue_name,

routing_key=binding_key)print('[*] Waiting for logs. To exit press CTRL+C')defcallback(ch, method, properties, body):print("[x] %r:%r" %(method.routing_key, body))

channel.basic_consume(callback,

queue=queue_name,

no_ack=True)

channel.start_consuming()

View Code

由于时间关系,详细过程略...

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值