RabbitMQ的Exchange交换机介绍

109 阅读4分钟

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

一、RabbitMQ的常⻅Exchange交换机介

1)RabbitMQ交换机介绍

  • ⽣产者将消息发送到Exchange/交换机,交换器将消息路由到 ⼀个或者多个队列中

  • 交换机有多个类型,队列和交换 机是多对多的关系。

  • 交换机只负责转发消息,不具备存储消息的能⼒,如果 没有队列和exchange绑定,或者没有符合的路由规则,则消息会被丢失

  • RabbitMQ交换机有4种类型

    • Direct exchange
    • Fanout exchange
    • Topic exchange
    • Headers exchange(基本不用)

2)RabbitMQ的4种类型交换机

  • Direct exchange 定向

    • 将一个队列绑定到direct交换机上,要求该消息与⼀个特 定的路由键完全匹配
    • 例⼦:如果⼀个队列绑定到该交换机上要求路由键 “aabb”,则只有被标记为“aabb”的消息才被转发, 不会转发aabb.cc,也不会转发gg.aabb,只会转发 aabb
    • 会处理路由健
  • Fanout exchange 广播

    • 只需要简单的将队列绑定到交换机上,⼀个发送到 交换机的消息都会被转发到与该交换机绑定的所有队列上。很像⼦⽹⼴播,每台⼦⽹内的主机都获得了⼀份复制的消息
    • Fanout交换机转发消息是最快的,⽤于发布订阅, ⼴播形式,中⽂是扇形
    • 不处理路由健
  • Topic exchange 通配符

    • 主题交换机是⼀种发布/订阅的模式,结合了直连交 换机与扇形交换机的特点 将路由键和某模式进⾏匹配。此时队列需要绑定要 ⼀个模式上
    • 符号“#”匹配⼀个或多个词,符号“*”匹配不多不少⼀ 个词
    • 路由键中的单词之间,用符号“.”隔开
    • 例⼦:因此“abc.#”能够匹配到“abc.def.ghi”,但是 “abc.*” 只会匹配到“abc.def”。
  • Headers exchange(很少用)

    • 根据发送的消息内容中的headers属性进⾏匹配,,在 绑定Queue与Exchange时指定⼀组键值对
    • 当消息发送到RabbitMQ时会取到该消息的headers 与Exchange绑定时指定的键值对进⾏匹配
    • 如果完全匹配则消息会路由到该队列,否则不会路 由到该队列
    • 不处理路由键

二、RabbitMQ的发布订阅消息模型介绍

1)什么是rabbitmq的发布订阅模式

  • 发布-订阅模型中,消息⽣产者不再是直接⾯对 queue(队列名称),⽽是直⾯exchange,都需要经过 exchange来进⾏消息的发送,,所有发往同⼀个fanout交 换机的消息都会被所有监听这个交换机的消费者接收到
  • 发布订阅-消息模型引⼊fanout交换机
  • ⽂档:www.rabbitmq.com/tutorials/t…

2)发布订阅模型应⽤场景

  • 微信公众号订阅后,订阅消息的发送和接收
  • 新浪微博关注,动态的发送和接收

3)RabbitMQ的发布订阅模型

  • 通过把消息发送给交换机,交互机转发给对应绑定的队 列
  • 交换机绑定的队列是排它独占队列,⾃动删除

交换机image.png

交换机image2.png

三、 RabbitMQ的发布订阅消息模型_python

1)发送消息:send.py

注意,订阅消息模型下,绑定的是交换机,并不是队列

 import pika
 ​
 # 连接mq的信息
 host = 'xxxx'  # mq服务所在ip
 port = xxxx  # amqp端口
 virtualhost = '/xxx'  # 需要连接的环境
 credentials = pika.PlainCredentials('xxx', 'xxxx')
 ​
 connection = pika.BlockingConnection(pika.ConnectionParameters(host, port, virtualhost, credentials))
 channel = connection.channel()
 ​
 exchange_name = 'work_rr'
 exchange_type = 'fanout'
 """
 声明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)
 ​
 for i in range(0, 10):
     message = f'hello word + {i}'
     channel.basic_publish(exchange=exchange_name, routing_key='', body=message)
     print(f'生产:hello word + {i}')
 channel.close()

2)消费消息 recv1.py和recv2.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 = 'boreak'
 exchange_type = 'fanout'
 ​
 # 声明交换机
 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:路由key的规则,默认为None
    arguments=None
 """
 channel.queue_bind(exchange=exchange_name, queue=queue_name)
 ​
 ​
 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)执行

  • 先运行消费者,再运行生产者

执行结果image1.png

执行结果image2.png