使用python连接rabbitmq的时候,需要第三方库 pika
pika 的安装
......@ubunut: ~$ sudo pip3 install pika
此处,创建两个py文件
- send.py
#!/usr/bin/python3
# send.py
import pika
# 创建连接
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
# 声明消息队列 队列名称为‘hello’
channel.queue_declare(queue='hello')
# 消息的生产者,exchange指定交换器, routing_key指定消息队列, body要发送的消息
channel.basic_publish(exchange='', routing_key='hello', body='Hello World')
print(" [x] sent 'Hello World'")
# 关闭连接
con.close()
- receive.py
#!/usr/bin/python3
# receive.py
import pika
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
# 多次使用queue_declare创建消息队列的时候,如果消息队列已经存在,则不创建新的
channel.queue_declare(queue='hello')
print("[*] Wating for messages To exit press Ctrl+C")
def callback(ch, method, properties, body):
print('[x] Received {}'.format(body))
# 参数一: 消息队列的名称
# 参数二: 消息处理的回调函数
channel.basic_consume('hello', callback, auto_ack = True)
# 开始消费
channel.start_consuming()
如何保证消息队列消息不丢失
- 如果消费者在处理的时候出现异常,我们希望消息会自动转发给其他消费者,在rabbitmq中有效确认机制,auto_ack参数(最近版本的pika,以前的版本是no_ack),默认是False。表示消息需要确认,这样其中有消费者当机了,那就可以把这个消息,转发给其他消费者.
消费者收到消息,正常处理后,此时才通知队列可以将消息从队列里面删除;如果消费者挂掉,与server的链接通道会关闭或者tcp连接丢失,这时候server知道了这个情况,就会自动重发消息
#!/usr/bin/python3
# receive.py
import pika
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
# 多次使用queue_declare创建消息队列的时候,如果消息队列已经存在,则不创建新的
channel.queue_declare(queue='hello')
print("[*] Wating for messages To exit press Ctrl+C")
def callback(ch, method, properties, body):
print('[x] Received {}'.format(body))
# 参数一: 消息队列的名称
# 参数二: 消息处理的回调函数
channel.basic_consume('hello', callback)
# 开始消费
channel.start_consuming()
- 防止Server挂掉了: 1、将队列保存;2、将消息持久化
在声明队列的时候,durable = True,这样Server挂掉,队列还在
# 要保证生产者和消费者生命的队列一样,都为True或者同时为False。durable(耐用)
channel.queue_declare(queue=‘hello‘,durable=True)
在声明交换机的时候,将消息进行持久化:delivery_mode = 2 (发送模式),这样Server挂掉,消息还在
properties(属性)
channel.basic_publish(exchange=‘‘,routing_key=‘hello‘,body=‘Hello World!‘,properties=pika.BasicProperties(delivery_mode=2,))
exchange 交换机的选择
- fanout 这种模式下,传递到 exchange 的消息将会转发到所有与其绑定的 queue 上
- direct 这种工作模式的原理是 消息发送至 exchange,exchange 根据 路由键(routing_key)转发到相对应的 queue 上
- topic 前面提到的direct规则是严格意义上的匹配,换言之Routing Key必须与Binding Key相匹配的时候才将消息传送给Queue,那么topic这个规则就是模糊匹配,可以通过通配符满足一部分规则就可以传送
fanout 模式
- 不需要指定 routing_key ,即使指定了也是无效。
- 需要提前将 exchange 和 queue 绑定,一个 exchange 可以绑定多个 queue,一个queue可以绑定多个exchange。
- 需要先启动 订阅者,此模式下的队列是 consumer 随机生成的,发布者 仅仅发布消息到 exchange ,由 exchange 转发消息至 queue。
#!/usr/bin/python3
# send.py
import pika
import json
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
channel.exchange_declare(exchange='python-test', durable=True, exchange_type='fanout')
for i in range(20):
message = json.dumps({'OrdersId': '1000{}'.format(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))
print(message)
con.close()
#!/usr/bin/python3
# receive.py
import pika
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
# 创建临时队列,consumer关闭后,队列自动删除
result = channel.queue_declare(exclusive=True, queue='')
channel.exchange_declare(exchange='python-test', durable=True, exchange_type='fanout')
# 绑定exchange和队列 exchange 使我们能够确切地指定消息应该到哪个队列去
channel.queue_bind(exchange = 'python-test', queue=result.method.queue)
print("[*] Wating for messages To exit press Ctrl+C")
def callback(ch, method, properties, body):
ch.basic_ack(delivery_tag = method.delivery_tag)
print(body.decode())
# 设置成 False,在调用callback函数时,未收到确认标识,消息会重回队列。True,无论调用callback成功与否,消息都被消费掉
channel.basic_consume(result.method.queue, callback, auto_ack=False)
channel.start_consuming()
direct 模式
- 可以使用默认 exchange =’ ’ ,也可以自定义 exchange
- 这种模式下不需要将 exchange 和 任何进行绑定,当然绑定也是可以的。可以将 exchange 和 queue ,routing_key 和 queue 进行绑定
- 传递或接受消息时 需要 指定 routing_key
- 需要先启动 订阅者,此模式下的队列是 consumer 随机生成的,发布者 仅仅发布消息到 exchange ,由 exchange 转发消息至 queue。
#!/usr/bin/python3
# send.py
import pika
import json
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
channel.exchange_declare(exchange='python-test-2', durable=True, exchange_type='direct')
for i in range(20):
message = json.dumps({'OrdersId': '1000{}'.format(i)})
# 指定 routing_key。delivery_mode = 2 声明消息在队列中持久化,delivery_mod = 1 消息非持久化
channel.basic_publish(exchange='python-test-2', routing_key='OrderId', body=message)
print(message)
con.close()
#!/usr/bin/python3
# receive.py
import pika
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
result = channel.queue_declare(exclusive=True, queue='')
channel.exchange_declare(exchange='python-test-2', durable=True, exchange_type='direct')
channel.queue_bind(exchange = 'python-test-2', queue=result.method.queue, routing_key='OrderId')
print("[*] Wating for messages To exit press Ctrl+C")
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()
topic
python3 receive.py OrdersId OrderIds
python3 send.py
-
这种模式和第二种模式差不多,exchange 也是通过 路由键 routing_key 来转发消息到指定的 queue 。 不同点是 routing_key 使用正则表达式支持模糊匹配,但匹配规则又与常规的正则表达式不同,比如‘’#‘’是匹配全部,“*”是匹配一个词。
-
举例:routing_key =“#orderid#”,意思是将消息转发至所有 routing_key 包含 “orderid” 字符的队列中
# !/usr/bin/python3
# send.py
import pika
import json
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
channel.exchange_declare(exchange='python-test-3', durable=True, exchange_type='topic')
for i in range(20):
message = json.dumps({'OrdersId': '1000{}'.format(i)})
channel.basic_publish(exchange='python-test-3', routing_key='OrdersId', body=message)
print(message)
con.close()
# !/usr/bin/python3
# receive.py
import pika
import sys
con = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = con.channel()
result = channel.queue_declare(exclusive=True, queue='')
channel.exchange_declare(exchange='python-test-3', durable=True, exchange_type='topic')
binding_keys = sys.argv[1:]
print('-->',binding_keys)
if not binding_keys:
print('------>')
sys.exit(1)
for i in binding_keys:
channel.queue_bind(exchange = 'python-test-3', queue=result.method.queue, routing_key=i)
print("[*] Wating for messages To exit press Ctrl+C")
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()