消息中间件---RabbitMQ
- 1 消息中间件的作用
- 2. 常用的消息中间件
- 3 消息中间件RabbitMQ
- 3.1 RabbitMQ介绍
- 3.3 RabbitMQ的队列模式
- 3.3 RabbitMQ的工作模式
- 4 RabbitMQ集群
- 4.1 节点类型
- 4.2 普通集群
- 4.3 镜像模式
- 4,4 远程模式(shovel)
- 4.5 多活模式
- 5 Rabbitmq的确认机制
1 消息中间件的作用
消息中间件作用有三个:异步处理消息、降低耦合度、流量削峰。
2. 常用的消息中间件
当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ等,而部分数据库如Redis、MySQL以及phxsql也可实现消息队列的功能
3 消息中间件RabbitMQ
3.1 RabbitMQ介绍
RabbitMQ是采用erlang语言开发的,必须有erlang环境才可以运行。RabbitMQ是一个遵循AMQP协议的消息中间件,它从生产者接收消息并递送给消费者,在这个过程中,根据规则进行路由,缓存与持久化。
3.2 RabbitMQ的基本介绍
-
producer:消息生产者,就是投递消息的程序;
-
Message:由生产者通过RabbitMQ发送给消费者的信息(路由键(Routing Key)是供交换机查看并根据键来决定如何分发消息到列队的一个键。路由键可以说是消息的目的地址);
-
连接(Connection):连接RabbitMQ和应用服务器的TCP连接;
-
信道(Channel):消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务;
为什么不通过TCP直接发送命令: 创建和销毁TCP会话是非常昂贵的开销,信道的原理是一条线程一条信道,多条线程多条信道共同使用一条TCP连接,每个信道的ID唯一;
-
绑定(Binding):绑定是队列和交换机的一个关联连接;
-
Exchange:通过routingkey和队列绑定在一起的,如果消息拥有的“路由键”跟队列和交换器的“路由键”匹配,那么消息就会被路由到该绑定的队列当中去;
Exchange的类型:
(1)fanout:消息会被转发到所有与交换机绑定队列;
(2)direct:精确匹配Routing key和routing key;
(3)topic:模糊匹配Routing key和routing key
-
队列(Queue):存储消息的缓存;
-
Consumer:处理消息;
消费模式:
(1)pull:消费者主动拉取消息
优点:客户端可以依据自己的消费能力进行消费 ;传输失败时不需要重试,反正数据还在服务端。
缺点:消息的实时性难以实现;
场景:服务端生产消息数据比较大时,而消费端处理比较复杂,消费能力相对较低。
(2)push:服务端主动推送消息给客户端
优点:服务端主动推送给客户端,实时性很高;
缺点:当客户端消费能力远低于服务端生产能力,那么一旦服务端推送大量消息到 客户端时,就会导致客户端消息堆积,处理缓慢,甚至服务崩溃;
服务端需要维护每次传输状态,以防消息传递失败进行重试。
场景:适合用于数据实时性要求高的场景
3.3 RabbitMQ的队列模式
- 普通队列
非持久化消息:消息存储在内存之中;持久化的消息:存储在磁盘中;
适用场景:消息量不是很大的情况 - 镜像队列
消息发送到队列时,如果队列是镜像队列,会将队列镜像到cluster中其他的节点之上;
对于持久化的消息,会在内存和磁盘中各存一份。
缺点:镜像队列不能实现负载均衡;对exclusive队列设置镜像并不会有任何作用。
队列结构:是一个特殊的BackingQueue,它内部包裹了一个普通的BackingQueue做本地消息持久化处理,增加了将消息和ack复制到所有镜像的功能。所有对mirror_queue_master的操作,会通过组播GM的方式同步到各slave节点。GM负责消息的广播,mirror_queue_slave负责回调处理,而master上的回调处理是由coordinator负责完成。mirror_queue_slave中包含了普通的BackingQueue进行消息的存储,master节点中BackingQueue包含在mirror_queue_master中由AMQQueue进行调用。
-
exclusive队列
只对首次声明它的连接可见;
会在其连接断开的时候自动删除;
-
lazy队列
优点:尽可能的将消息存储到磁盘中,在消费者消费到相应的消息时才会被加载到内存中,占用内存少;
缺点:存在队列的单点故障;
使用场景:发送端过快或消费端宕机,导致消息大量积压,在消息大爆发的时候,MQ服务器会撑不住,影响其他队列的消息收发。
-
死信队列
死信消息如何形成的:
(1)消息被否定确认;
(2)消息在队列的存活时间超过设置的TTL时间;
(3)消息队列的消息数量已经超过最大队列长度。
死信队列:如果配置了死信队列信息,那么该消息将会被丢进死信队列中;如果没有配置,则该消息将会被丢弃。
场景:故障发生时,让未正确处理的消息存放到死信队列中,待后续排查清楚问题后,处理死信消息。
-
延迟队列
场景:实现定时任务
实现方式:
(1)延迟插件;
(2)ttl+死信队列:消息过期时间/队列过期时间,如果同时设置队列和消息过期时间,较小的生效。
3.3 RabbitMQ的工作模式
- 简单模式:一个生产者,一个消费者,一个队列。
- 工作模式:一个生产者对应多个消费者,但是一条消息只能被一个消费者获取。
- 发布订阅模式:一个消费者将消息首先发送到交换器,交换器绑定到多个队列,然后被监听该队列的消费者所接收并消费。
- 路由模式:使用的是type为direct的交换机,让消费者有选择性的接收消息。
- 主题模式:使用type为topic的交换机
4 RabbitMQ集群
4.1 节点类型
磁盘节点:配置信息和元信息存储在磁盘上,至少一个磁盘节点。如果唯一磁盘的磁盘节点崩溃,集群是可以保持运行的,但不能更改任何东西,集群中最好设置两个磁盘节点。
内存节点:配置信息和元信息存储在内存中, 性能好;
4.2 普通集群
默认普通队列,集群仅采用元数据同步。仅同步元数据的原因:存储空间和性能。
特点:
(1)master存储队列的元数据信息和消息;
(2)slave只同步队列元数据信息,不会同步存储消息;
(3)master(读写),slave(不提供读写)作为路由节点起到转发作用;
缺点:master节点故障后,slave节点无法取到master节点中还未消费的消息实体。如果做了消息持久化,等master节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象;
4.3 镜像模式
-
把需要的队列做成镜像队列,master会将队列镜像到cluster中其他的slave节点之上。逻辑上的master和slave,相对于主队列而言。
-
特点:
(1)消息的发布与消费都是通过master节点完成,master通过 mirror 队列把消息数据同步到其他的 slave 节点,对于持久化的消息会在磁盘和内存中各存一份;
(2)除publish外所有动作都只会向master发送,然后由master将命令执行的结果广播给slave;
(3)master节点故障后,集群中最老的slave被提升为master;slave节点故障后,仅仅是相邻节点感知,然后重新调整邻居节点信息。
-
镜像队列 gm:
通过将所有 gm 进程形成一个循环链表,每个 gm 都会监控位于自己左右两边的 gm,当有 gm 新增时,相邻的 gm 保证当前广播的消息会通知到新的 gm 上;当有 gm 失效时,相邻的 gm 会接管保证本次广播消息会通知到所有 gm。
-
镜像队列的消息广播流程:
(1)Master 节点发出消息,顺着镜像队列循环列表发送;
(2)所有 Slave 节点收到消息会对消息进行缓存(Slave 节点缓存消息用于在广播过程中,有节点失效或者新增节点,这样左侧节点感知变化后会重新将消息推送给右侧节点);
(3)当 Master 节点收到自己发送的消息后意味着所有节点都收到了消息,会再次广播 Ack 消息;
(4)Ack 消息同样会顺着循环列表经过所有 Slave 节点,通知 Slave 节点可以清除缓存消息;
(5)当 Ack 消息回到 Master 节点,对应消息的广播结束。
-
优点:(1)保证 100% 数据不丢失; (2)消除普通模式中队列消息单点带来的风险;
-
缺点:降低系统性能,集群内部的同步通讯会占用大量的网络带宽
4,4 远程模式(shovel)
远程模式可以实现双活的一种模式,简称 shovel 模式,所谓的 shovel 就是把消息进行不同数据中心的复制工作,可以跨地域的让两个 MQ 集群互联,远距离通信和复制。
Shovel 把消息进行数据中心的复制工作,可以跨地域的让两个 MQ 集群互联。
原理:使用shovel插件实现,通过定义RabbitMQ上一个队列和另外一个RabbitMQ上的交换机之间的复制关系来实现远程复制。它会在主服务上建立一个队列来监听交换机,所有到交换机的消息会投递到该队列,并且在从服务中订阅这个队列,使队列中的消息复制到从服务的交换机中。优点:异地的 MQ 集群,近端同步确认,远端异步确认;缺点:配置比较复杂
4.5 多活模式
federation 插件是一个不需要构建 cluster ,而在 brokers 之间传输消息的高性能插件,federation 插件可以在 brokers 或者 cluster 之间传输消息,连接的双方可以使用不同的 users 和 virtual hosts,双方也可以使用不同版本的 rabbitMQ 和 erlang。federation 插件使用 AMQP 协议通信,可以接受不连续的传输。
federation 插件实现,只配置两个集群中两个单点队列之间的复制,每个集群内部自己会完成多节点的同步(镜像队列来完成)。
优点:Federation插件可以在Brokers或者Cluster之间传输消息,连接双方可以使用不同的users和vistual hosts; 双方也可以使用版本不同的RabbitMQ和Erlang。
5 Rabbitmq的确认机制
rabbitmq发出消息后会等待consumer端应答,只有收到ack确定信息后才会将消息在rabbitmq清除掉。
5.1 自动ack
(1)autoAck=true;
(2)消息一旦被接收,消费者自动发送ACK;
对于自动确认来说,当方法没有异常执行完毕后,会对MQ发出ACK;若方法出现异常,会对MQ发出nack,消息会重回队列。
场景:消息不太重要,丢失也没有影响
5.2 手动ack
保证数据不被重复消费,同时数据也不能少,也就是数据一致性。
(1)关闭自动ack:autoAck=false;
(2)消息接收后,不会自动发送ACK,需要手动调用
场景:消息非常重要,异常发生不会丢数据。
如果重复ack(自动ack的同时开启手动ack)会造成造成消息丢失