python操作——RabbitMQ
Posted 明王不动心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python操作——RabbitMQ相关的知识,希望对你有一定的参考价值。
RabbitMQ是一个在AMQP基础上完整的,可服用的企业消息系统。他遵循Mozilla Public License开源协议。
MQ全称为Message Queue,消息队列(MQ)是一种应用程序对应用程序的通信方法。
应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。
消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。
队列的使用除去了接收和发送应用程序同时执行的要求。
RabbitMQ安装
安装配置epel源 $ rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm 安装erlang $ yum -y install erlang 安装RabbitMQ $ yum -y install rabbitmq-server
注意:service rabbitmq-server start/stop
安装API
pip install pika or easy_install pika or 源码 https://pypi.python.org/pypi/pika
使用API操作RabbitMQ
基于Queue实现生产者消费者模型
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import Queue 4 import threading 5 6 7 message = Queue.Queue(10) 8 9 10 def producer(i): 11 while True: 12 message.put(i) 13 14 15 def consumer(i): 16 while True: 17 msg = message.get() 18 19 20 for i in range(12): 21 t = threading.Thread(target=producer, args=(i,)) 22 t.start() 23 24 for i in range(10): 25 t = threading.Thread(target=consumer, args=(i,)) 26 t.start()
对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。
生产者:
1 #!/usr/bin/env python 2 import pika 3 4 # ######################### 生产者 ######################### 5 6 connection = pika.BlockingConnection(pika.ConnectionParameters( 7 host=\'localhost\')) 8 channel = connection.channel() 9 10 channel.queue_declare(queue=\'hello\') 11 12 channel.basic_publish(exchange=\'\', 13 routing_key=\'hello\', 14 body=\'Hello World!\') 15 print(" [x] Sent \'Hello World!\'") 16 connection.close()
消费者:
1 #!/usr/bin/env python 2 import pika 3 4 # ########################## 消费者 ########################## 5 6 connection = pika.BlockingConnection(pika.ConnectionParameters( 7 host=\'localhost\')) 8 channel = connection.channel() 9 10 channel.queue_declare(queue=\'hello\') 11 12 def callback(ch, method, properties, body): 13 print(" [x] Received %r" % body) 14 15 channel.basic_consume(callback, 16 queue=\'hello\', 17 no_ack=True) 18 19 print(\' [*] Waiting for messages. To exit press CTRL+C\') 20 channel.start_consuming()
1.acknowledgment消息不丢失
no-ack = False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( host=\'10.211.55.4\')) channel = connection.channel() channel.queue_declare(queue=\'hello\') def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time 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()
2.durable消息不丢失
#!/usr/bin/env python import pika 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()
#!/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host=\'10.211.55.4\')) channel = connection.channel() # make message persistent channel.queue_declare(queue=\'hello\', durable=True) def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time 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()
3.消费获取顺序
默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。
channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
#!/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host=\'10.211.55.4\')) channel = connection.channel() # make message persistent channel.queue_declare(queue=\'hello\') def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time 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()
4.发布订阅
发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。
所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
exchange type = fanout
#!/usr/bin/env python import pika import sys 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()
#!/usr/bin/env python import pika 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\') def callback(ch, method, properties, body): print(" [x] %r" % body) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming()
5.关键字发送
exchange type = direct
之前事例,发送消息时明确指定某个队列并向其中发送消息,RabbitMQ还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列。
1 #!/usr/bin/env python 2 import pika 3 import sys 4 5 connection = pika.BlockingConnection(pika.ConnectionParameters( 6 host=\'localhost\')) 7 channel = connection.channel() 8 9 channel.exchange_declare(exchange=\'direct_logs\', 10 type=\'direct\') 11 12 result = channel.queue_declare(exclusive=True) 13 queue_name = result.method.queue 14 15 severities = sys.argv[1:] 16 if not severities: 17 sys.stderr.write("Usage: %s [info] [warning] [error]\\n" % sys.argv[0]) 18 sys.exit(1) 19 20 for severity in severities: 21 channel.queue_bind(exchange=\'direct_logs\', 22 queue=queue_name, 23 routing_key=severity) 24 25 print(\' [*] Waiting for logs. To exit press CTRL+C\') 26 27 def callback(ch, method, properties, body): 28 print(" [x] %r:%r" % (method.routing_key, body)) 29 30 channel.basic_consume(callback, 31 queue=queue_name, 32 no_ack=True) 33 34 channel.start_consuming()
1 #!/usr/bin/env python 2 import pika 3 import sys 4 5 connection = pika.BlockingConnection(pika.ConnectionParameters( 6 host=\'localhost\')) 7 channel = connection.channel() 8 9 channel.exchange_declare(exchange=\'direct_logs\', 10 type=\'direct\') 11 12 severity = sys.argv[1] if len(sys.argv) > 1 else \'info\' 13 message = \' \'.join(sys.argv[2:]) or \'Hello World!\' 14 channel.basic_publish(exchange=\'direct_logs\', 15 routing_key=severity, 16 body=message) 17 print(" [x] Sent %r:%r" % (severity, message)) 18 connection.close()
6.模糊匹配
exchange type = topic
在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配,匹配成功,则将数据发送到指定队列。
- # 表示可以匹配 0 个 或 多个 单词
- * 表示只能匹配 一个 单词
1 发送者路由值 队列中 2 old.boy.python old.* -- 不匹配 3 old.boy.python old.# -- 匹配
1 #!/usr/bin/env python 2 import pika 3 import sys 4 5 connection = pika.BlockingConnection(pika.ConnectionParameters( 6 host=\'localhost\')) 7 channel = connection.channel() 8 9 channel.exchange_declare(exchange=\'topic_logs\', 10 type=\'topic\') 11 12 result = channel.queue_declare(exclusive=True) 13 queue_name = result.method.queue 14 15 binding_keys = sys.argv[1:] 16 if not binding_keys: 17 sys.stderr.write("Usage: %s [binding_key]...\\n" % sys.argv[0]) 18 sys.exit(1) 19 20 for binding_key in binding_keys: 21 channel.queue_bind(exchange=\'topic_logs\', 22 queue=queue_name, 23 routing_key=binding_key) 24 25 print(\' [*] Waiting for logs. To exit press CTRL+C\') 26 27 def callback(ch, method, properties, body): 28 print(" [x] %r:%r" % (method.routing_key, body)) 29 30 channel.basic_consume(callback, 31 queue=queue_name, 32 no_ack=True) 33 34 channel.start_consuming()
1 #!/usr/bin/env python 2 import pika 3 import sys 4 5 connection = pika.BlockingConnection(pika.ConnectionParameters( 6 host=\'localhost\')) 7 channel = connection.channel() 8 9 channel.exchange_declare(exchange=\'topic_logs\', 10 type=\'topic\') 11 12 routing_key = sys.argv[1] if len(sys.argv) > 1 else \'anonymous.info\' 13 message = \' \'.join(sys.argv[2:]) or \'Hello World!\' 14 channel.basic_publish(exchange=\'topic_logs\', 15 routing_key=routing_key, 16 body=message) 17 print(" [x] Sent %r:%r" % (routing_key, message)) 18 connection.close()
1 sudo rabbitmqctl add_user alex 123 2 # 设置用户为administrator角色 3 sudo rabbitmqctl set_user_tags alex administrator 4 # 设置权限 5 sudo rabbitmqctl set_permissions -p "/" alex \'.\'\'.\'\'.\' 6 7 # 然后重启rabbiMQ服务 8 sudo /etc/init.d/rabbitmq-server restart 9 10 # 然后可以使用刚才的用户远程连接rabbitmq server了。 11 12 13 ------------------------------ 14 credentials = pika.PlainCredentials("alex","123") 15 16 connection = pika.BlockingConnection(pika.ConnectionParameters(\'192.168.14.47\',credentials=credentials))
以上是关于python操作——RabbitMQ的主要内容,如果未能解决你的问题,请参考以下文章