RabbitMQ详解(版本2.3.2.RELEASE)
RabbitMQ是实现了AMQP协议的一个消息中间件。抵抗高并发的根本是来自于Erlang语言
特点
- 可靠性:可以使用持久化、传输确认及发布确认来实现。
- 灵活性:路由可以实现不同的消息绑定到路由中分发给不同的Queue。
- 扩展性:可以通过集群来配置更多的节点
- 高可用:可以通过配置镜像节点来实现数据的冗余,使得主节点出了问题,依旧可以使用
- 管理页面:可以通过点点点的方式进行管理。
- 令插件机制 : RabbitMQ 提供了许多插件 , 以实现从多方面进行扩展,当然也可以编写自 己的插件。
AMQP是什么
也就是制定了必须有交换机,交换机类型,绑定,队列,路由键
使用场景
异步处理、服务解耦、流量控制(削峰)。
死信队列
DLX,全称为 Dead-Letter-Exchange,死信交换器,死信邮箱。当消息在一个队列中变成死信 (dead message) 之后,它能被重新被发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称之为死信队列。
为什么为产生死信队列:
- 消息长时间未被消费导致TTL
- 消息被拒绝接收(Basic.Reject /Basic.Nack)并且 requeue=false
- 队列满了呗
死信队列的应用场景
可以通过死信队列中的消息放到延迟队列,延迟队列再去进行处理
比如订单超时后的一系列处理。
RabbitMQ中消息的4种状态
alpha: 消息内容(包括消息体、属性和 headers) 和消息索引都存储在内存中 。
beta: 消息内容保存在磁盘中,消息索引保存在内存中。
gamma: 消息内容保存在磁盘中,消息索引在磁盘和内存中都有 。
delta: 消息内容和索引都在磁盘中 。
底层流转过程
- 当客户端与Broker建立连接的时候,客户端会向Broker发送一个Protocol Header 0-9-1的报文头,以此通知Broker本次交互才采用的是AMQP 0-9-1协议。
- 紧接着Broker返回Connection.Start来建立连接,在连接的过程中涉及Connection.Start/.Start-OK、Connection. Tune/. Tune-OK、Connection.Open/.Open-OK这6个命令的交互。
- 连接建立以后需要创建通道,会使用到Channel.Open , Channel.Open-OK命令,在进行交换机声明的时候需要使用到Exchange.Declare以及Exchange.Declare-OK的命令。以此类推,在声明队列以及完成队列和交换机的绑定的时候都会使用到指定的命令来完成。
- 在进行消息发送的时候会使用到Basic.Publish命令完成,这个命令还包含了Conetent-Header和Content-Body。Content Header里面包含的是消息体的属性,Content-Body包含了消息体本身。
以上从消息发送者到MQ中了,接下来消费者怎么消费消息
- 消费者消费消息的时候,所涉及到的命令和生成者大部分都是相同的。在原有的基础之上,多个几个命令:Basic.Qos/.Qos-OK以及Basic.Consume和Basic.Consume-OK。
- 其中Basic.Qos/.Qos-OK这两个命令主要用来确认消费者最大能保持的未确认的消息数时使用。Basic.Consume和Basic.Consume-OK这两个命令主要用来进行消息消费确认。
如何保证可靠消息最终一致性?
保证上游服务发送成功(可靠消息)
可以通过在配置文件中配置confirm模式,发送时在Mysql中的LocalMessage表中加入数据关键字段比如id,statu等进行标记,然后通过定时任务扫描其中未被发送的消息,我们可以通过实现confirm接口然后重写他的confirm()方法,在其参数中判断是否已经发送成功,如果发送成功修改表中的状态。
保证MQ不会丢失消息
本身MQ默认的是临时节点,可以给Queue进行设置持久化,包括交换机和消息本身。如果MQ宕机,还可以通过配置镜像节点来实现高可用,甚至使用集群降低MQ的压力,变相的实现高可用。
保证下游服务一定能够确认消息
首先在配置文件中设置手动确认消息,如果下游服务已经成功消费消息,但是确认不了,所以需要在消费前就进行判断该条消息是否已经被消费,通过幂等的方式进行去重,防止多次消费同一条消息。如果再消费过程中出现异常回滚,消息依旧躺在MQ中等待被消费。
需要注意的点:
- 可靠性的增强就意味着性能的下降。因为在RAM中和Disc中的速度相差太多,所以可以通过使用SSD来提高读写速度,或者仅对必须消息设置持久化。
- 不要忘记手动ACK,最好的方式就是通过finnal块来进行手动ACK
- 能者多劳机制