发布网友 发布时间:2022-04-22 09:46
共1个回答
热心网友 时间:2023-10-09 02:32
MQ全程为message queue,即消息队列。是一种跨进程、异步通信机制、用于上下游传递消息。RabbitMQ是由Erlang语言开发,基于 AMQP 协议(Advanced Message Queuing Protocol 高级消息队列协议)实现的消息队列,它是一种应用程序之间的通信方法,消息队列在实际开发应用中有着非常广泛的使用。下面主要介绍RabbitMQ的基础、架构以及在开发过程中遇到的一些常用问题,还有在面试过程中一些长问的问题。
RabbitMQ官网: https://www.rabbitmq.com
2007年Rabbit公司基于AMQP标准协议开发的RabbitMQ1.0发布。AMQP的主要特性是面向消息、队列、路由、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性有着很高的要求场景,对性能和吞吐量的要求在其次。
RabbitMQ基础架构如下图:
来介绍下上图中一些名词相关的概念:
RabbitMQ内置了几种常用的exchange,包含direct、topic、fanout、headers,下面主要介绍几种常用的exchange类型。
直连交换机,完全匹配路由key,所有发送到direct exchange的消息会被转发到routeKey中指定的queue中。消息传递时,routeKey必须要完全匹配才会被队列接手,否则消息会被抛弃。
主题交换机,根据匹配路由规则来分发消息, # 匹配一个或多个词, * 匹配不多不少一个词。比如“log.#”能够匹配到“log.info.test”,“log.*”能够匹配到“log.err”。
广播交换机,不处理路由,只需要将队列绑定到交换机上,发送到交换机的消息会被转发到与该交换机绑定的所有的队列上。
RabbitMQ提供了三种模式,分别为单机模式、普通集群模式、镜像集群模式,下面分别介绍下这三种模式。
这个就是demo级别的,即单机情况不做集群,一般也就是你本地启动玩玩写写测试用的,没有人在生产用这种模式的。
多台机器上启动多个RabbitMQ实例,以两个节点(node-1,node-2)为例来进行说明。对于queue来说,消息实体只存在于其中一个节点node-1或者node-2,node-1和node-2两个节点仅有相同的元数据(即队列相关的结构)。当消息进入node-1后,consumer从node-2节点消费时,RabbitMQ会临时在node-1、node-2间进行消息传输,把A中的消息取出来并经过B在发送给consumer,所以consumer以ing改尽量连接每一个节点,从中获取消息。负责无论consumer连接node-1或者node-2,出口总在node-1,会产生瓶颈,如果当node-1节点故障后,node-2无法获取node-1的消息。如果做了持久化,那么必须要等到node-1恢复后,才能继续消费,如果消息没有做持久化,就会出小消息丢失的情况。
一般配合HAProxy配置为高可用集群,把需要的队列做成镜像队列,存在与多个节点属于 RabbitMQ的HA方案。该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。
完成镜像队列设置之后,每各队列会被复制到各个节点,各个节点状态保持一致。因为 RabbitMQ本身不提供负载均衡,需要搭建负载均衡器来提供负载转发,可以选择HAProxy 和Nginx。
采用 AMQP 高级消息队列协议的一种消息队列技术,最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦。
消息持久化,当然前提是队列必须持久化。
在消息生产时,MQ内部针对每条生产者发送的消息生成一个 inner-msg-id ,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个 bizId (对于同一业务全局唯一,如支付 ID、订单 ID、帖子 ID 等)作为去重的依据,避免同一条消息被重复消费。
将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。
一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。
如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。
发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。
消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。
这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证数据的最终一致性;
下面列举几种特殊情况:
所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,最好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了10倍。但是关键时刻,用,还是得用的。最后希望这篇能给大家带来收获,喜欢加关注,后续持续更新!