RabbitMQ下载配置参考网络:
Python调用RabbitMQ服务:
可以使用现成的类库pika、txAMQP或者py-amqplib,本例选择pika
pip install pika
import pika
# 证书认证,默认账密(guest,guest)
credentials = pika.PlainCredentials('guest', 'guest')
# 建立连接,虚拟主机需要指定参数`virtual_host`,默认`\`
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672))
# 实例化消息队列
channel = connection.channel()
# 声明消息队列,消息将在创建的队列中传递,不存在则创建,`durable=True`表示消息队列持久化存储,False非持久化存储
channel.queue_declare(queue='queue_test', durable=True)
# 消息入队,`routing_key`为队列名,`body`为消息体
# delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化,消息持久化可以将消息从内存转存到硬盘,保证rabbitmq重启后,消息不会丢失
channel.basic_publish(exchange='',
routing_key='queue_test',
body="this is a message",
properties=pika.BasicProperties(delivery_mode=1)
)
# 关闭连接
connection.close()
import pika
# 证书认证,默认账密(guest,guest)
credentials = pika.PlainCredentials('guest', 'guest')
# 建立连接,虚拟主机需要指定参数`virtual_host`,默认`\`
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672))
# 实例化消息队列
channel = connection.channel()
# 声明消息队列,消息将在创建的队列中传递,不存在则创建
channel.queue_declare(queue='queue_test', durable=True)
def callback(ch, method, properties, body):
""" 定义回调方法,处理消息队列中的消息 """
# 需要发送确认消息
ch.basic_ack(delivery_tag=method.delivery_tag)
print("Received %s" % body)
# 绑定回调函数及消息队列
channel.basic_consume(on_message_callback=callback,
queue='queue_test',
auto_ack=False
)
"""
`no_ack=True`:表示没有返回消息,即无论调用callback成功与否,消息都被消费掉;
False时,在调用callback函数时,未收到确认标识,消息会重回队列。
`auto_ack=True`:表示RabbitMQ认定消息一旦分发,就认为接收成功,不会等待消息回复,立即将缓存中的该消息删除,在消费端异常时会导致该消息丢失;
False时,表示消费者拿到消息后等待自动回复,成功则会删除该消息
"""
# 开始监听,并进入阻塞状态,队列中有消息就会调用回调方法进行处理
channel.start_consuming()
队列声明持久化
# `durable = True`代表消息队列持久化存储,反之非持久化存储。
result = channel.queue_declare(queue='queue-test',durable=True)
交换机声明持久化
# `durable = True`代表交换机持久化存储,反之非持久化存储
channel.exchange_declare(exchange='exchange-test',durable=True)
注意:如果已存在一个非持久化的
queue
或exchange
,durable=True
会报错,因为当前状态不能更改queue
或exchange
存储属性,需要删除重建。如果
queue
或exchange
中一个声明了持久化,另一个没有声明持久化,则不允许绑定。
消息持久化
虽然 queue
和 exchange
都申明了持久化,但如果消息只存在内存里,rabbitmq 重启后,内存里的消息还是会丢失。所以必须声明消息也是持久化,从内存转存到硬盘。
# `delivery_mode=2` 声明消息在队列中持久化,`delivery_mod=1`表示消息非持久化
channel.basic_publish(exchange='',
routing_key='queue-test',
body='test',
properties=pika.BasicProperties(delivery_mode=2)
)
acknowledgement
消息不丢失(异常反馈,消息重发)
消费者(consumer)调用callback函数时,会存在处理消息失败的风险,如果处理失败,则消息丢失。但是也可以选择消费者处理失败时,将消息回退给RabbitMQ,重新再被消费者消费
"""
`no_ack=True`:表示没有返回消息,即无论调用callback成功与否,消息都被消费掉;
False时,在调用callback函数时,未收到确认标识,消息会重回队列。
`auto_ack=True`:表示RabbitMQ认定消息一旦分发,就认为接收成功,不会等待消息回复,立即将缓存中的该消息删除,在消费端异常时会导致该消息丢失;
False时,表示消费者拿到消息后等待自动回复,成功则会删除该消息
"""
channel.basic_consume(callback,
queue = 'python-test',
no_ack = False
)
RabbitMQ的发布与订阅要借助交换机(Exchange)实现。
共三种工作模式:
fanout
、direct
、topicd
fanout
模式这种模式下,传递到 exchange 的消息将会转发到所有与其绑定的 queue 上。
- 不需要指定 routing_key ,即使指定了也是无效。
- 需要提前将 exchange 和 queue 绑定,一个 exchange 可以绑定多个 queue,一个queue可以绑定多个exchange。
- 需要先启动 订阅者,此模式下的队列是 consumer 随机生成的,发布者 仅仅发布消息到 exchange ,由 exchange 转发消息至 queue。
生产者
import pika
import json
credentials = pika.PlainCredentials('guest', 'guest')
# 虚拟队列需要指定参数 virtual_host,如果是默认的可以不填。
connection = pika.BlockingConnection(pika.ConnectionParameters(host = '127.0.0.1',port = 5672,virtual_host = '/',credentials = credentials))
channel=connection.channel()
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='fanout')for i in range(10):
message=json.dumps({'OrderId':"1000%s"%i})
# 向队列插入数值 routing_key是队列名。delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化。routing_key 不需要配置
channel.basic_publish(exchange='python-test',
routing_key='',
body = message,
properties=pika.BasicProperties(delivery_mode=2)
)
connection.close()
消费者
import pika
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host = '127.0.0.1',port = 5672,virtual_host = '/',credentials = credentials))
channel = connection.channel()
# 创建临时队列,队列名传空字符,consumer关闭后,队列自动删除
result = channel.queue_declare('',exclusive=True)
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='fanout')
# 绑定exchange和队列 exchange 能够确切地指定消息应该到哪个队列去
channel.queue_bind(exchange = 'python-test',queue = result.method.queue)
# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
ch.basic_ack(delivery_tag = method.delivery_tag)
print(body.decode())
channel.basic_consume(result.method.queue,callback,auto_ack = False)
channel.start_consuming()
direct
模式这种工作模式的原理是 消息发送至 exchange,exchange 根据 **路由键(routing_key)**转发到相对应的 queue 上。
- 可以使用默认 exchange =’ ’ ,也可以自定义 exchange
- 这种模式下不需要将 exchange 和 任何进行绑定,当然绑定也是可以的。可以将 exchange 和 queue ,routing_key 和 queue 进行绑定
- 传递或接受消息时 需要 指定 routing_key
- 需要先启动 订阅者,此模式下的队列是 consumer 随机生成的,发布者 仅仅发布消息到 exchange ,由 exchange 转发消息至 queue。
生产者
import pika
import json
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host = '127.0.0.1',port = 5672,virtual_host = '/',credentials = credentials))
channel=connection.channel()
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='direct')
for i in range(10):
message=json.dumps({'OrderId':"1000%s"%i})
# 指定 routing_key。delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化
channel.basic_publish(exchange='python-test',
routing_key='OrderId',
body = message,
properties=pika.BasicProperties(delivery_mode = 2)
)
connection.close()
消费者
import pika
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host = '127.0.0.1',port = 5672,virtual_host = '/',credentials = credentials))
channel = connection.channel()
# 创建临时队列,队列名传空字符,consumer关闭后,队列自动删除
result = channel.queue_declare('',exclusive=True)
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange = 'python-test',durable = True, exchange_type='direct')
# 绑定exchange和队列 exchange 使我们能够确切地指定消息应该到哪个队列去
channel.queue_bind(exchange = 'python-test',queue = result.method.queue,routing_key='OrderId')
# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
ch.basic_ack(delivery_tag = method.delivery_tag)
print(body.decode())
#channel.basic_qos(prefetch_count=1)
channel.basic_consume(result.method.queue,callback, auto_ack = False)
channel.start_consuming()
topicd
模式这种模式类似
direct
模式,exchange 也是通过 路由键 routing_key 来转发消息到指定的 queue 。 不同点是 routing_key 使用正则表达式支持模糊匹配,但匹配规则又与常规的正则表达式不同,比如“#”是匹配全部,“*”是匹配一个词。.ex:
routing_key = "#demo#"
,即将消息转发至所有 routing_key 包含 “demo” 字符的队列中。