rabbimq 常用架构
exchange 3种模式
direct: 一对一 ,一个生产者 一个消费者,标准队列
fanout:一对多,一个生产者多个消费者,并行多处理时常用
topic:多对一,多个交换机到一个队列上,配合routting_key,可将指定类型发送到指定队列
信道(建立通道)、交换机(选择连接类型,选择队列)、路由键routing_key、队列放在一起用
Rabbitmq 支持持久化 队列要先注册进路由器 队列要先注册进路由器
A 可以开启消息事务,半消息。对于消费者不可见,可以回退。分布式的事务管理
实时性不搞的情况下,尽量等一会
B 生产者发的消息 消费者要确认,可通过序号检查的方式可以知道消息丢失了
C 至多一次的策略。消息最多呗送达一次。至少一次,保证消息呗接收一次。恰好一次,
解决方案:幂等性-, db非重复行,主键唯一约束
示例代码
# demo1 # publisher #!/usr/bin/env python # -*- coding:utf-8 -*- import pika # 生产者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.queue_declare(queue='direct_demo', durable=False) # exchange指定交换机,routing_key指定队列名 channel.basic_publish(exchange='', routing_key='direct_demo', body='send message to rabbitmq') # 关闭与rabbitmq server的连接 connection.close() # subscribe #!/usr/bin/env python # -*- coding:utf-8 -*- import pika # 消费者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.queue_declare(queue='direct_demo', durable=False) # 定义一个回调函数来处理消息队列中的消息 def callback(ch, method, properties, body): # 手动发送消息 ch.basic_ack(delivery_tag=method.delivery_tag) print(body.decode()) # 消费者使用队列和回调函数处理消息 channel.basic_consume('direct_demo', on_message_callback=callback) # 开始接受消息,进入阻塞状态 channel.start_consuming() ## demo2 publisher #!/usr/bin/env python # -*- coding:utf-8 -*- import pika # 生产者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.queue_declare(queue='task_queue', durable=True) # exchange指定交换机,routing_key指定队列名 message = 'send message to task_queue' channel.basic_publish(exchange='', routing_key='task_queue', body=message, properties=pika.BasicProperties( delivery_mode = 2, # 消息持久化 )) # 关闭与rabbitmq server的连接 connection.close() # sub #!/usr/bin/env python # -*- coding:utf-8 -*- import pika import time # 消费者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.queue_declare(queue='task_queue', durable=True) # 定义一个回调函数来处理消息队列中的消息 def callback(ch, method, properties, body): time.sleep(1) # 手动发送消息 ch.basic_ack(delivery_tag=method.delivery_tag) print(body.decode()) ch.basic_ack(delivery_tag=method.delivery_tag) # 如果该消费者的channel上未确认的消息数叨叨了prefetch_count数,则不向该消费者发送消息 channel.basic_qos(prefetch_count=1) # 消费者使用队列和回调函数处理消息 channel.basic_consume('task_queue', callback) # 开始接受消息,进入阻塞状态 channel.start_consuming() # demo3 publisher #!/usr/bin/env python # -*- coding:utf-8 -*- import pika # 生产者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.exchange_declare(exchange='logs', exchange_type='fanout') # 默认是derict # exchange指定交换机,routing_key指定队列名 message = 'send message to task_queue' channel.basic_publish(exchange='logs', routing_key='', body=message, ) # 关闭与rabbitmq server的连接 connection.close() # sub #!/usr/bin/env python # -*- coding:utf-8 -*- import pika import time # 消费者 # 用户名密码, 不同业务分配不同的账号密码 credential = pika.PlainCredentials('guest', 'guest') # 虚拟队列需指定参数virtual_host, parameters = pika.ConnectionParameters(host='192.168.56.33', port=5672, virtual_host='/', credentials=credential) # 阻塞方法 connection = pika.BlockingConnection(parameters) # 建立信道 channel = connection.channel() # 建立队列,若不存在会自动创建, durable=True 时队列有持久化功能 channel.exchange_declare(exchange='logs', exchange_type='fanout') # 声明消息队列 # exclusive 当与消费者断开连接的时候,队列被立即删除 result = channel.queue_declare(queue='', exclusive=True) # queue=‘’ 系统产生随机队列 queue_name = result.method.queue # 通过bind实现exchange将message发送到指定queue channel.queue_bind(exchange='logs', queue=queue_name) # 定义一个回调函数来处理消息队列中的消息 def callback(ch, method, properties, body): time.sleep(1) # 手动发送消息 ch.basic_ack(delivery_tag=method.delivery_tag) print(body.decode()) # ch.basic_ack(delivery_tag=method.delivery_tag) # 如果该消费者的channel上未确认的消息数叨叨了prefetch_count数,则不向该消费者发送消息 channel.basic_qos(prefetch_count=1) # 消费者使用队列和回调函数处理消息 channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) # 开始接受消息,进入阻塞状态 channel.start_consuming()