RabbitMQ的路由模式和应⽤场景

119 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

一、RabbitMQ的路由模式和应⽤场景

1)什么是rabbitmq的路由模式

  • ⽂档:www.rabbitmq.com/tutorials/t…
  • 交换机类型是Direct
  • 队列和交换机绑定,需要指定⼀个路由key( 也叫 Bingding Key)
  • 消息⽣产者发送消息给交换机,需要指定routingKey
  • 交换机根据消息的路由key,转发给对应的队列
  • 例⼦:⽇志采集系统 ELK
    • ⼀个队列收集error信息 => 紧急处理
    • ⼀个队列收集全部信息 =>⽇常使⽤

image.png

二、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)执行

image.png image.png

三、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的队列,不同的通配符能进入什么队列中)

image.png

  • 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()