python3使用RabbitMQ

简介

AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦。

作用:

  • 解耦
  • 异步
  • 削峰

使用

简单模式(直接使用队列不用交换机)

python3使用RabbitMQ

生产者:

import pika
import json
import time

credentials = pika.PlainCredentials('guest', 'guest')  # mq用户名和密码
# 虚拟队列需要指定参数 virtual_host,如果是默认的可以不填。
connection = pika.BlockingConnection(pika.ConnectionParameters(host = '127.0.0.1',port = 5672,virtual_host = '/',credentials = credentials))
channel=connection.channel()
# 声明消息队列,消息将在这个队列传递,如不存在,则创建
result = channel.queue_declare(queue = 'python-test')
result = channel.queue_declare(queue = 'python-test1')
# 声明exchange,由exchange指定消息在哪个队列传递,如不存在,则创建。durable = True 代表exchange持久化存储,False 非持久化存储
# channel.exchange_declare(exchange = '',durable = True, exchange_type='fanout')

for i in range(100):
    message=json.dumps({'OrderId':"1000%s"%i})
# 向队列插入数值 routing_key是队列名
    channel.basic_publish(exchange='', routing_key='python-test', body=message)
    channel.basic_publish(exchange='', routing_key='python-test1', body=message)
    print(message)
    time.sleep(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()
# 申明消息队列,消息在这个队列传递,如果不存在,则创建队列
channel.queue_declare(queue = 'python-test', durable = False)
# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())

# 告诉rabbitmq,用callback来接收消息
channel.basic_consume('python-test',callback)
# 开始接收信息,并进入阻塞状态,队列里有信息才会调用callback进行处理
channel.start_consuming()

使用exchange

fanout模式

python3使用RabbitMQ

生产者

import pika
import json
import time

credentials = pika.PlainCredentials('guest', 'guest')  # mq用户名和密码
# 虚拟队列需要指定参数 virtual_host,如果是默认的可以不填。
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel=connection.channel()
channel.exchange_declare(exchange='test1', exchange_type='fanout')

for i in range(100):
    message=json.dumps({'OrderId':"1000%s"%i})
    # 当使用交换机的时候直接把消息交给交换机就好了
    channel.basic_publish(exchange='test1', routing_key='', body=message)
    body=message)
    print(message)
    time.sleep(2)
#connection.close()

消费者

import pika
import time

credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel = connection.channel()
# 绑定交换机
channel.exchange_declare(exchange='test1', exchange_type='fanout')
# 不指定queue名字,rabbit会随机分配一个名字
# exclusive=True会在使用此queue的消费者断开后,自动将queue删除
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
print(queue_name)
# 将exchange与queue绑定
channel.queue_bind(exchange='test1', queue=queue_name)

# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    #ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())
    #time.sleep(0)

# 告诉rabbitmq,用callback来接收对应queue的消息
channel.basic_consume(queue_name, callback)
# 开始接收信息,并进入阻塞状态,队列里有信息才会调用callback进行处理
channel.start_consuming()

direct模式

生产者

import pika
import json
import time

credentials = pika.PlainCredentials('guest', 'guest')  # mq用户名和密码
# 虚拟队列需要指定参数 virtual_host,如果是默认的可以不填。
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel=connection.channel()
channel.exchange_declare(exchange='test_direct', exchange_type='direct')

for i in range(100):
    message=json.dumps({'OrderId':"1000%s"%i})
    # 当使用交换机的时候直接把消息交给交换机,并指定发布到哪个queue
    channel.basic_publish(exchange='test_direct', routing_key='con2', body=message)
    print(message)
    time.sleep(2)
#connection.close()

消费者

import pika
import time

credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel = connection.channel()
# 绑定交换机
channel.exchange_declare(exchange='test_direct', exchange_type='direct')
# 不指定queue名字,rabbit会随机分配一个名字
# exclusive=True会在使用此queue的消费者断开后,自动将queue删除
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
print(queue_name)
# 将exchange与queue绑定
channel.queue_bind(exchange='test_direct', queue=queue_name, routing_key='con1')
channel.queue_bind(exchange='test_direct', queue=queue_name, routing_key='con2')

# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    #ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())
    #time.sleep(0)

# 告诉rabbitmq,用callback来接收对应queue的消息
channel.basic_consume(queue_name, callback)
# 开始接收信息,并进入阻塞状态,队列里有信息才会调用callback进行处理
channel.start_consuming()

topic模式

星号(*):匹配一个单词
井号(#):匹配0个或多个单词

direct与topic都是通过消费者指定routing_key来实现绑定
python3使用RabbitMQ

当产生routing_key为con1的消息时,路由到python-test中
当产生routing_key为con1.xxx的消息时,路由到python-test1中
当产生routing_key为con2的消息时,路由到python-test1中
当产生routing_key为con2.xxx的消息时,路由到python-test1中
当产生routing_key为con2.xxx.xxxx的消息时,路由到python-test1中

import pika
import json
import time

credentials = pika.PlainCredentials('guest', 'guest')  # mq用户名和密码
# 虚拟队列需要指定参数 virtual_host,如果是默认的可以不填。
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel=connection.channel()
channel.exchange_declare(exchange='test_topic', exchange_type='topic')

for i in range(100):
    message=json.dumps({'OrderId':"1000%s"%i})
    # 当使用交换机的时候直接把消息交给交换机,并指定发布到哪个queue
    channel.basic_publish(exchange='test_topic', routing_key='con2', body=message)
    print(message)
    time.sleep(2)
#connection.close()
import pika
import time

credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters(host='127.0.0.1', port=5672, virtual_host='/', credentials=credentials))
channel = connection.channel()
# 绑定交换机
channel.exchange_declare(exchange='test_topic', exchange_type='topic')
# 不指定queue名字,rabbit会随机分配一个名字
# exclusive=True会在使用此queue的消费者断开后,自动将queue删除
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
print(queue_name)
# 将exchange与queue绑定
channel.queue_bind(exchange='test_topic', queue=queue_name, routing_key='con1.*')
channel.queue_bind(exchange='test_topic', queue=queue_name, routing_key='con2.#')

# 定义一个回调函数来处理消息队列中的消息,这里是打印出来
def callback(ch, method, properties, body):
    #ch.basic_ack(delivery_tag = method.delivery_tag)
    print(body.decode())
    #time.sleep(0)

# 告诉rabbitmq,用callback来接收对应queue的消息
channel.basic_consume(queue_name, callback)
# 开始接收信息,并进入阻塞状态,队列里有信息才会调用callback进行处理
channel.start_consuming()

存在问题

数据的重复消费

数据丢失

相关内容可以参考大佬的这篇文章https://www.jianshu.com/p/5ade5bf0dcd9

上一篇:leetcode-322、leetcode-279


下一篇:每日一题12005-奖学金