消息总线RabbitMQ

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件,也称为面向消息的中间件,是一个在AMQP基础上完整的,可复用的企业消息系统。它可以用于大型软件系统各个模块之间的高效通信,支持高并发,支持可扩展。

AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计,它定义了以下这些特性:
消息方向
消息队列
消息路由
可靠性
安全性
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

基本概念

在开始之前,我们先了解一下有关MQ的基本概念,为后续demo做一些必要的铺垫

  • Broker:消息对俄服务器的实体,它是一个人中间件应用,负责接收消息生产者的消息,然后将这些消发送到消息接收者或者其他的Broker。消息
  • Queue:消息队列,消息通过发送和路由之后最终达到的地方,到达Queue的消息及进入了逻辑上等待消息消费的状态,每个消息都会被发送到一个或者多个队列,它是RabbitMQ的内部对象,用于存储消息,用下图表示:

    RabbitMQ中的消息都只能存储在Queue中,生产者(下图中的P)生产消息并最终投递到Queue中,消费者(下图中的C)可以从Queue中获取消息并消费。

    多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,
    从这里我们看到生产者将消息投递到Queue中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。下面我们讲解有关Exchange的内容

  • Exchange:消息交换机,是消息第一个达到的地方,消息通过它指定的路由规则,下发到不同的消息队列中区。如下图所示,实际在使用MQ的时候都是生产者将消息发送到Exchange(交换器),由Exchange将消息路由到一个或多个Queue中(或者丢弃)。

    Exchange是按照什么逻辑将消息路由到Queue的?这就需要介绍Binding相关的知识了

  • Binding:绑定,他的作用是把Exchange和Queue按照路由规则绑定起来,也就是Exchange和Queue之间的虚拟连接。

  • Binding key:在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key;消费者将消息发送给Exchange时,一般会指定一个routing key;当binding key与routing key相匹配时,消息将会被路由到对应的Queue中。这个将在Exchange Types章节会列举实际的例子加以说明。
    在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。
    binding key 并不是在所有情况下都生效,它依赖于Exchange Type,比如fanout类型的Exchange就会无视binding key,而是将消息路由到所有绑定到该Exchange的Queue。

  • Routing key:路由关键字,Exchange根据这个关键字进行消息投递。
    生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。
    在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪里。
    RabbitMQ为routing key设定的长度限制为255 bytes。

  • Connection:连接,代表生产者、消费者、Broker之间进行通讯的物理网络。

  • Channel:消息通道,用于连接生产者和消费者的逻辑结构。在客户端的每个连接里,可以建立多个channel,每个channel代表一个会话任务,通过channel可以隔离同一个连接中的不同交互内容。
  • Producer:消息生产着,制造消息发送消息的程序
  • Consumer:消息消费者,接收消息并处理的程序

消息投递过程

消息投递到多队列的整个过程大致如下:

  1. 客户端连接到消息队列服务器,打开一个channel
  2. 客户端声明一个Exchange,并设置相关属性
  3. 客户端声明一个Queue,并设置相关属性
  4. 客户端使用Routing key,在Exchange和Queue之间建立好绑定关系
  5. 客户端投递消息到Exchange
  6. Exchange接收到消息后,根据消息的Key和已经设置横扫的Binding,进行消息路由,将消息投递到一个或者多个Queue中

Exchange有三种类型:

  1. Direct交换机:完全根据Key进行匹配,它会把消息路由到那些binding key与routing key完全匹配的Queue中:

    以上图的配置为例,我们以routingKey=”error”发送消息到Exchange,则消息会路由到Queue1(amqp.gen-S9b…,这是由RabbitMQ自动生成的Queue名称)和Queue2(amqp.gen-Agl…);如果我们以routingKey=”info”或routingKey=”warning”来发送消息,则消息只会路由到Queue2。如果我们以其他routingKey发送消息,则消息不会路由到这两个Queue中。

  2. Topic交换机:对key进行模式匹配后进行投递,可以使用符号#匹配一个或者多个词,符号*匹配正好一个词。
    它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:

    • routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
    • binding key与routing key一样也是句点号“. ”分隔的字符串
    • binding key中可以存在两种特殊字符“”与“#”,用于做模糊匹配,其中“”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)

      以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1与Q2,routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。
  3. Fanout交换机:不需要任何的Key他采用广播的方式,一个消息进来时,投递到与改交换机绑定的所有队列

快速入门

新建一个Spring Boot工程在pom.xml中引入如下依赖内容,其中spring-boot-starter-amqp用于支持RabbitMQ。

parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>1.5.6.RELEASEversion>
    <relativePath/>
parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-amqpartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
dependencies>

配置好Mq相关的连接属性:

spring.application.name=rabbitmq-hello

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.password: "guest",
spring.rabbitmq.username: "guest",

创建消息生产者Sender。通过注入AmqpTemplate接口的实例来实现消息的发送

@Component
public class Message {

  @Autowired
  RabbitMessagingTemplate rabbitSendTemplate;

 public void send(String... params) throws BusinessAccessException {
    rabbitSendTemplate.convertAndSend("demo.listener.exchange", "demo.listener.key",params);
  }

}

创建消息消费者Receiver:


@Component
public class Listener {


@RabbitListener(bindings = @QueueBinding(
    // 1.value:队列名,2.durable:是否长期有效,3.false:是否自动删除
    value = @Queue(value = "demo.listener.key", durable = "true", autoDelete = "false"),
    // 1.value交换器名称,2.durable:是否长期有效,3.type:类型是topic
    exchange = @Exchange(value = "demo.listener.exchange", durable = "true"),
    // test2.send:路由的名称,ProducerConfig 里面 绑定的路由名称(xxxx.to(exchange).with("test2.send")))
    key = "demo.listener.key"))
  public void receive(String... params) {
        System.out.println("Receiver : " + params);
}

}

你可能感兴趣的:(微服务,消息队列,rabbitmq)