RabbitMQ是基于AMQP协议实现的
AMQP协议
AMQP:(全称:Advanced Message Queuing Protocol) 是高级消息队列协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。
特性:
1:分布式事务支持。
2:消息的持久化支持。
3:高性能和高可靠的消息处理优势。
rabbitMQ工作模式
一、使用示例
生产者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
channel.basic_publish(exchange='',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
消费者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
channel.basic_consume(queue='hello',
auto_ack=True,
on_message_callback=callback)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
参数说明
应答参数
def callback(ch, method, properties, body):
print(" [x] Received %r" % body)
ch.basic_ack(delivery_tag=method.delivery_tag)
channel.basic_consume(queue='hello',
auto_ack=False, # 关闭消息自动确认,改为手动确认
on_message_callback=callback)
持久化参数
#声明queue
channel.queue_declare(queue='hello2', durable=True) # hello队列已存在,这里使用第二队列
channel.basic_publish(exchange='',
routing_key='hello2',
body='Hello World!',
properties=pika.BasicProperties(delivery_mode=2))
分发参数
有两个消费者同时监听一个的队列。其中一个线程sleep2秒,另一个消费者线程sleep1秒,但是处理的消息是一样多。这种方式叫轮询分发(round-robin)不管谁忙,都不会多给消息,总是你一个我一个。想要做到公平分发(fair dispatch),必须关闭自动应答ack,改成手动应答。
使用 basicQos(perfetch=1) 限制每次只发送不超过1条消息到同一个消费者,消费者收到消息后必须手动反馈告知队列,才会发送下一个。
channel.basic_qos(prefetch_count=1)
二、发布订购模式Fanout
发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。
生产者指定交换机模式,和交换机名称
消费者声明队列,并将队列绑定交换机
channel.queue_bind(exchange='logs', queue=queue_name)
生产者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs',
exchange_type='fanout') #指定交换机模式
message = "info: Hello World!"
channel.basic_publish(exchange='logs', #指定交换机名称
routing_key='',
body=message)
print(" [x] Sent %r" % message)
connection.close()
消费者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs',
exchange_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(queue=queue_name,
auto_ack=True,
on_message_callback=callback)
channel.start_consuming()
注意发布消息时与简单模式的区别
简单模式: exchange=‘’, routing_key=‘队列名’
交换机fanout: exchange=‘交换机名’,routing_key=‘’
三、关键字模式Direct
根据消息携带的路由键routing key将消息投递给对应的队列,队列在绑定交互机时,指定路由键routing key
生产者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs2',
exchange_type='direct')
message = "info: Hello Yuan!"
channel.basic_publish(exchange='logs2',
routing_key='info',
body=message)
print(" [x] Sent %r" % message)
connection.close()
消费者
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs2',
exchange_type='direct')
result = channel.queue_declare("",exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='logs2',
queue=queue_name,
routing_key='info')
channel.queue_bind(exchange='logs2',
queue=queue_name,
routing_key='warnning')
channel.queue_bind(exchange='logs2',
queue=queue_name,
routing_key='error')
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] %r" % body)
channel.basic_consume(queue=queue_name,
auto_ack=True,
on_message_callback=callback)
channel.start_consuming()
四、通配符模式Topics
“通配符交换机”(Topic Exchange)将路由键和某模式进行匹配。此时队列需要绑定在一个模式上。符号“#”匹配一个或多个词,符号“*”仅匹配一个词(与正则相反)
因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*”只会匹配到“audit.irs”。
生产者
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs3',
exchange_type='topic')
message = "info: Hello ERU!"
channel.basic_publish(exchange='logs3',
routing_key='europe.weather',
body=message)
print(" [x] Sent %r" % message)
connection.close()
消费者
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs3',
exchange_type='topic')
result = channel.queue_declare("",exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='logs3',
queue=queue_name,
routing_key="#.news")
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] %r" % body)
channel.basic_consume(queue=queue_name,
auto_ack=True,
on_message_callback=callback)
channel.start_consuming()