携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
一、RabbitMQ的路由模式和应⽤场景
1)什么是rabbitmq的路由模式
- ⽂档:www.rabbitmq.com/tutorials/t…
- 交换机类型是Direct
- 队列和交换机绑定,需要指定⼀个路由key( 也叫 Bingding Key)
- 消息⽣产者发送消息给交换机,需要指定routingKey
- 交换机根据消息的路由key,转发给对应的队列
- 例⼦:⽇志采集系统 ELK
- ⼀个队列收集error信息 => 紧急处理
- ⼀个队列收集全部信息 =>⽇常使⽤
二、RabbitMQ路由模式代码实战_python
模拟日志采集系统
1)生产消息:send.py
import pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_direct'
exchange_type = 'direct'
"""
声明exchange交换机
exchange:交换机名称
exchange_type:交换机类型,默认是direct
passive=False:检查交换机是否存在
durable=False:是否持久化
auto_delete=False:最后一个队列解绑则删除
internal=False:否设置为值接收从其他交换机发送过来的消息,不接收生产者的消息
arguments=None:自定义键值对参数,类型是字典
"""
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
error_log = '我是error日志'
info_log = '我是info日志'
debug_log = '我是debug日志'
channel.basic_publish(exchange=exchange_name, routing_key='errorRoutingKey', body=error_log)
channel.basic_publish(exchange=exchange_name, routing_key='infoRoutingKey', body=info_log)
channel.basic_publish(exchange=exchange_name, routing_key='debugRoutingKey', body=debug_log)
print('direct消息发送成功')
channel.close()
2)消费者_消费error消息
import pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_direct'
exchange_type = 'direct'
# 声明交换机
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
"""
绑定交换机
queue:队列的名字
exchange:交换机的名字
routing_key=None:路由key的规则,当为None时,默认使用queue的名字作为路由key规则
arguments=None
"""
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='errorRoutingKey')
def callback(ch, method, properties, body):
print(body.decode())
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
3)消费者_消费所有消息类型
import pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_direct'
exchange_type = 'direct'
# 声明交换机
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
"""
绑定交换机
queue:队列的名字
exchange:交换机的名字
routing_key=None:路由key的规则,当为None时,默认使用queue的名字作为路由key规则
arguments=None
"""
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='errorRoutingKey')
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='infoRoutingKey')
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='debugRoutingKey')
def callback(ch, method, properties, body):
print(body.decode())
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
4)执行
三、RabbitMQ的topic主题通配符模式
【使用最多】
1)背景
- 如果业务很多路由key,怎么维护??
- topic交换机,⽀持通配符匹配模式,更加强⼤
- ⼯作基本都是⽤这个topic模式
2)什么是rabbitmq的topic主题模式
- ⽂档
- 交换机是 topic, 可以实现发布订阅模式fanout和路由模 式Direct 的功能,更加灵活,⽀持模式匹配,通配符等
- 交换机同过通配符进⾏转发到对应的队列,* 代表⼀个
词,#代表1个或多个词,⼀般⽤#作为通配符居多
- ⽐
如
#.order, 会匹配info.order 、sys.error.order - ⽽
*.order,只会匹配info.order, 之间是使⽤.进⾏分 割多个词的 - 如果是
., 则info.order、error.order都 会匹配
- ⽐
如
- 注意
- 交换机和队列绑定时⽤的binding使⽤通配符的路由 健
- ⽣产者发送消息时需要使⽤具体的路由健
- 例子(存在如图所示的topic交换机和不同routingkey的队列,不同的通配符能进入什么队列中)
- quick.orange.rabbit 只会匹配 .orange. 和 ..rabbit ,进到Q1和Q2
- lazy.orange.elephant 只会匹配 .orange. 和 lazy.#,进到Q1和Q2
- quick.orange.fox 只会匹配 .orange.,进⼊Q1
- lazy.brown.fox 只会匹配azy.#,进⼊Q2
- lazy.pink.rabbit 只会匹配 lazy.#和*.*.rabbit ,同 个队列进⼊Q2(消息只会发⼀次)
- quick.brown.fox 没有匹配,默认会被丢弃,可以通过回调 监听⼆次处理
- lazy.orange.male.rabbit,只会匹配 lazy.#,进⼊Q2
- 例⼦:⽇志采集系统
- ⼀个队列收集订单系统的全部⽇志信息:
order.log.# - ⼀个队列收集全部系统的全部⽇志信息:
#.log
- ⼀个队列收集订单系统的全部⽇志信息:
四、topic主题模式实战_python
1)生产者
mport pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_topic'
exchange_type = 'topic'
"""
声明exchange交换机
exchange:交换机名称
exchange_type:交换机类型,默认是direct
passive=False:检查交换机是否存在
durable=False:是否持久化
auto_delete=False:最后一个队列解绑则删除
internal=False:否设置为值接收从其他交换机发送过来的消息,不接收生产者的消息
arguments=None:自定义键值对参数,类型是字典
"""
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
channel.confirm_delivery()
# error_log = '我是订单服务的error日志'
# info_log = '我是订单服务的info日志'
debug_log = '我是订单服务的debug日志'
# channel.basic_publish(exchange=exchange_name, routing_key='order.log.error', body=error_log)
# channel.basic_publish(exchange=exchange_name, routing_key='order.log.info', body=info_log)
ack = channel.basic_publish(exchange=exchange_name, routing_key='order.log.debug', body=debug_log,
properties=pika.BasicProperties(delivery_mode=2))
print(ack)
print('topic消息发送成功')
channel.close()
2)消费者_消费error消息
import pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_topic'
exchange_type = 'topic'
# 声明交换机
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
"""
绑定交换机
queue:队列的名字
exchange:交换机的名字
routing_key=None:路由key的规则,当为None时,默认使用queue的名字作为路由key规则
arguments=None
"""
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='order.log.error')
channel.basic_ack()
def callback(ch, method, properties, body):
print(body.decode())
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
3)消费者_消费所有消息
import pika
# 连接mq的信息
host = 'xxx' # mq服务所在ip
port = xxx # amqp端口
virtualhost = '/xxx' # 需要连接的环境
credentials = pika.PlainCredentials('xxx', 'xxx')
connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
channel = connection.channel()
exchange_name = 'work_topic'
exchange_type = 'topic'
# 声明交换机
channel.exchange_declare(exchange=exchange_name, exchange_type=exchange_type)
# 消费者声明随机的消息队列名称
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
"""
绑定交换机
queue:队列的名字
exchange:交换机的名字
routing_key=None:路由key的规则,当为None时,默认使用queue的名字作为路由key规则
arguments=None
"""
channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='*.log.*')
def callback(ch, method, properties, body):
print(body.decode())
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()