MQ全称Message Queue,消息队列(MQ)是一种应用程序对应用程序的通信方法。
1. 简单队列
对于RabbitMQ而言,生产与消费不再针对内存里的一个queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列
# -*- coding:utf-8 -*-
import pika
# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(
host="localhost"
)) # 封装socket逻辑部分
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello world!')
print "[x] Sent 'Hello World!'"
connection.close()
# -*- coding:utf-8 -*-
import pika
# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'
))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print "[x] Received %r" % body
channel.basic_consume(callback,
queue='hello',
no_ack=True)
print "[*] Waiting for messages. To exit press CTRL+C"
channel.start_consuming()
1)acknowlegement消息不丢失
no-ack = False,如果消费者遇到情况挂掉了,那么RabbitMQ会重新将该任务添加到队列中
2)durable消息不丢失
# -*- coding:utf-8 -*-
import pika
# 生产者
connection = pika.BlockingConnection(pika.ConnectionParameters(
host="localhost"
))
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()
3)消息获取顺序
默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1去队列中获取奇数序列的任务,消费者1去队列中获取偶数序列的任务。
channel.basic_pos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列
# -*- coding:utf-8 -*-
import pika
# 消费者
connection = pika.BlockingConnection(pika.ConnectionParameters(
host="localhost"
))
channel = connection.channel()
# Make message persistent
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print "[x] sent 'Hello World!"
channel.basic_qos(prefetch_count=1)
channel.basic_consume(callback,
queue='hello',
no_ack=False)
print "[x] sent 'Hello World!"
channel.start_consuming()
2. 发布订阅
发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
exchange type=fanout
# -*- coding:utf-8 -*-
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()
# -*- coding:utf-8 -*-
import pika
import sys
# 订阅者
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 "[x] 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()
3. 关键字发送
队列绑定关键字,发送者将数据根据关键字发送到消息
exchange根据关键字判定应该将数据发送至指定队列
# -*- coding:utf-8 -*-
import pika
import sys
# 订阅者
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
servrities = sys.argv[1:]
if not servrities:
sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
sys.exit()
for severity in servrities:
channel.queue_bind(exchange='direct_logs',
queue=queue_name,
routing_key=severity)
print "[x] Waiting for logs. To exit press CTRL+C"
def callback(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()
# -*- coding:utf-8 -*-
import pika
import sys
# 发布者
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'
))
channel = connection.channel()
channel.exchange_declare(exchange='direct_logs',
type='direct')
severity = sys.argv[1] if len(sys.argv) > 1 else 'info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='direct_logs',
routing_key=severity,
body=message)
print "[x] Sent %r:%r" % (severity, message)
connection.close()
4. topic模糊匹配
在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入"路由值"和“关键字”进行匹配,匹配成功,则将数据发送到指定队列。
# 表示可以匹配0个或多个单词
* 表示只能匹配一个单词
使用时将type改为topic即可