概要

今天开始学习消息中间件,根据项目需求,目前选择的消息中间件是RabbitMQ。让我们一起来认识下RabbitMQ吧。

AMQP 的简介

在说RabbitMQ之前我们先简单的认识一下AMQP 协议,AMQP(Advanced Message Queuing Protocol) 直译为高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
AMQP 的主要特征是是面向对象,队列,路由(包括点对点的发布/订阅)、可靠性,安全。

RabbitMQ 的简介

RabbitMQ 是一个开源的AMQP 实现,服务器端用Erlang 语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。 同时其有消息确认机制和持久化机制,可靠性高。

RabbitMQ 组件概念

  • ConnectionFactory、Connection、Channel
    Connection 是RabbitMQ的socket 链接,它封装了socket协议相关部分逻辑,ConnectionFactory是Connection的制造工厂,Channel 是我们 信息管道。我们的大部分业务操作都是在Channel 接口中完成,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。
  • Broker
    消息队列服务器的实体
  • Exchange
    消息交换机,它指定消息按什么规则,路由到哪个队列。
  • Queue
    消息队列的载体,每个消息都会被投入到一个或多个队列。可以看成是一个有序的数组,
  • Binding
    绑定,是一个操作,它的作用就是把exchange和queue按照路由规则绑定起来。RabbitMQ中通过绑定,以路由键作为桥梁将Exchange与Queue 关联起来(Exchange---->Routing Key---->Queue) ,这样RabbitMQ 就知道如何正确地将消息路由到指定的队列了,通过queueBind方法将Exchange、Routing Key 与Queue绑定起来。
  • Routing Key
    路由关键字,exchange 根据这个关键字进行消息投递,Routing Key 需要与Exchange Type 及Binding Key 联合使用才能最终生效。 RabbitMQ为Routing Key设定的长度限制为255 bytes。
  • vhost
    虚拟主机,一个broker 里可以开设多个vhost,用作不同用户的权限分离。
  • producer
    消息生产者,就是投递消息的程序。
  • consumer
    消息消费者,就是接受消息的程序
  • channel
    消息通道,在客户端的每个连接里,可建立多个channel,每个channel 代表一个会话任务。

五种队列模式

简单队列

简单队列就是 生产者和消费者一对一
RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_RabbitMQ

工作队列

工作队列就是一个生产者、2个消费者。但是在MQ中一个消息不能被两个消费者同时消费,要么被C1消费,要么被C2消费。这种模式类似于集群,能者多劳,性能好的可以安排多消费,性能低的可以安排低消费。
默认分发方式: 轮询分发
其他分发方式:公平分发
使用公平分发,必须关闭自动应答,改为手动应答。
消费者端添加代码:channel.basicQos(1);
RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_伪代码_02
----------------------------------完美的分割线------------------------------------
一般在实际应用场景中,我们基本上不会将消息直接投递到队列里,而是投递到Exchange(交换器,下图中的x)里, 由Exchange 将消息路由到一个或多个Queue 中。

发布订阅模式

这种模式可以满足消费者发布一个消息,多个消费者消费同一个消息的需求。广播给所有的接收者。
RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_伪代码_03
如上图所示,生产者(P)发送到Exchange(X)的所有消息都会路由到图中的两个Queue,并最终被两个消费者(C1与C2)消费。

  1. 一个生产者,多个消费者。通过交换器将消息投递到不同的队列里。
  2. 每个消费者都有自己的队列
  3. 生产者没有把消息发送到队列,而是发送到交换器Exchange里,Exchange 没有持久化功能,所以必须要与队列绑定
  4. 每个队列都绑定到交换器
  5. 生产者发送的消息经过交换器,路由到队列就能实现一个消息被多个消费者消费。

发布订阅模式代码讲解

伪代码—生产者

  1. 创建mq连接,通道
  2. 声明交换器–fanout 模式,把消息发送到交换器上(注意:交换器没有存储信息功能,不能持久化信息,因此,如果交换器没有绑定队列,那么消息就会丢失)
    伪代码—消费者
  3. 创建mq连接,通道
  4. 声明队列
  5. 把队列绑定上交换器
  6. 消费者监听该队列的通道

路由器模式Routing

路由模式是在订阅模式基础上的完善,可以在生产消息的时候加入key 值,与key 值匹配的消费者消费信息。
RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_伪代码_04
以上图为例:我们以RoutingKey=“error” 发送消息到Exchange,则消息会路由到 Queue1(amqp.gen-S9b…,这是由RabbitMQ自动生成的Queue名称)和Queue2(amqp.gen-Agl…);如果我们以RoutingKey="info"或RoutingKey="warning"来发送消息,则消息只会路由到Queue2。如果我们以其他的RoutingKey来发送消息,则消息不会路由到这两个Queue中。

路由器模式代码讲解

伪代码–生产者

  1. 创建mq链接、通道
  2. 声明交换机–direct模式,把消息发送到交换机上,并指定routingKey,(注意:交换机没有存储信息功能,不能持久化消息,因此,如果交换机没有绑定队列,那么消息就丢失了)
    伪代码–消费者
  3. 创建mq链接、通道
  4. 声明队列
  5. 把对列绑定到上交换机,并指定routingKey,多个就绑定多个routingKey
    消费者监听该队列的通道

通配符模式–Topic 模式

通配符模式是在路由模式的升级,它允许key模糊匹配,* 代表一个或者多个词,通过通配符模式我们可以将C1对应的一个key准确定为item.add。而C2 我们就不需要一个个写出key值,而是用item.# 代替即可。

  • 表示匹配一个。

表示匹配一个或多个。

RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_持久化_05
如上图所示,我们以RoutingKey=“xx.orange.rabbit” 发送消息到Exchange,则消息会路由到Q1和Q2。RoutingKey=“lazy.orange.rabbit” 的消息会路由到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

通配符模式代码讲解

伪代码–生产者

  1. 创建mq链接、通道
  2. 声明交换机–topic模式,把消息发送到交换机上,并指定routingKey(注意:交换机没有存储信息功能,不能持久化消息,因此,如果交换机没有绑定队列,那么消息就丢失了)
    伪代码–消费者
  3. 创建mq链接、通道
  4. 声明队列
  5. 把对列绑定到上交换机,并指定routingKey(可以用*和#来进行模糊匹配)
    消费者监听该队列的通道

RPC 模式

MQ 本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败。
在实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后在进行下一步的处理,这相当于RPC(Remote Procedure Call, 远程过程调用)。在RabbitMQ中也支持RPC
RabbitMQ学习笔记(一)----RabbitMQ的基本概念以及5种队列模式_持久化_06

源代码

​https://github.com/XWxiaowei/90-Java-demo-2/tree/master/course-24-rabbitmq/rabbitmq-demo​