RabbitMQ——镜像队列的数据流
【概述】
rabbitmq采用了镜像队列的方式实现队列的高可用,镜像队列的使用、配置、内部实现原理网上有很多文章都有介绍,自己很久之前也曾总结过相关内容。但回过头再来看镜像队列,仍然有新的发现,本文分析总结了镜像队列生产消费的数据流以及节点流量,以便更好的使用镜像队列。
【生产消费的数据流】
分析镜像队列之前,我们还是先一步步从单机情况下,集群情况下看看生产消费的数据流走向是怎样的,最后再分析镜像队列的场景。
- 单机场景:
如上图所示,生产者,消费者连接到rabbitmq后,在rabbitmq内部会创建对应的connection,channel进程。connection进程从socket上接收生产者发送消息后投递到channel进程;在channel进程中,根据消息发送的exchange与消息的routing-key,在内部数据库的路由表中,查找所有匹配的队列的进程PID,然后将消息投递到这些队列的进程中。
同样,队列进程收到消息后,找到消费者对应的channel进程PID,然后将消息投递给该进程,channel进程再发送给对应的connection进程,然后通过socket发送给消费者。
从上面可以看出,一条消息从生产到消费,rabbitmq的节点上会有1进1出的流量。
补充说明下:在rabbitmq内部会为每个tcp链接创建多个进程,其中包括专门用于数据接收的rabbit_reader进程,专门用于数据发送的rabbit_writer进程,本文为了方便表达,统一使用connection进程进行socket数据的收发。所以上面提到的connection进程可以理解为包括了rabbit_reader,rabbit_writer进程。
- 集群场景
我们都知道,每个队列都有一个唯一的master进程,所有生产消费的消息都是由master进程负责处理的。
在集群场景中,生产者消费者连接到集群中的任意节点都可以正确将消息投递到队列和正确从队列消费消息。如果生产者消费者连接的节点恰好是队列master所在的节点,那么这种情况下和单机场景是一样的。但更多的时候会存在这样的情况:生产者、消费者连接的rabbitmq节点并不是队列master进程所在的节点,那么生产消费的消息数据就会在集群的这两个节点上传输。
如上图所示,生产消费的流程其实和单机场景一模一样,在channel进程中查数据库找到匹配的队列的进程PID,然后将消息投递到这个队列进程中。
但是,这里的队列进程是在另外一个节点上,rabbitmq会自动识别这一点,然后通过与对端节点的分布式端口(默认为25672)通信,将消息发送到对端节点的进程中。也就是说,消息在集群中进行了传输。
同样,队列收到消息后,找到消费者对应的channel进程PID,并将消息发送到这个进程中,这里也会进行一次集群通信,用于消息的传输。
在这种场景下,一条消息从生产到消费,上图中node1节点是2进2出的流量,node2节点是1进1出的流量。
因此,尽可能的让生产者、消费者与队列master进程位于同一个节点上,可以减少集群间的网络交互。
- 镜像队列
先来看下生产者、消费者连接的节点就是队列master进程所在节点的情况,如下图所示:
流程还是和之前一样,但是不同的地方有两点:
1) 在channel进程中,查数据库找匹配的队列的进程。对于镜像队列而言,除了所有匹配的队列的master进程外,还包括所有的slave进程。也就是说,channel进程除了将消息发送给队列的master进程外,还会将消息发送给队列所有的slave进程,而slave进程肯定都是在远端节点上,因此这里就多了一次集群间的网络交互。
2)镜像队列的master进程收到后,需要负责将消息同步给所有的slave进程,rabbitmq采用的GM算法实现中,镜像队列中的master和所有slave都会发送一次消息和接收一次消息,同时还会发送一次对消息的ack,和接收一次消息的ack。(镜像队列的同步实现原理,这里不展开详细说明,可参考文章https://my.oschina.net/hncscwc/blog/186350)
综上所述,生产者发送一条消息,队列master进程所在节点会收到两次:一次是生产者发送的,一次是队列slave进程发送的;同样也会将消息对外发送两次:一次是生产者对应的channel进程将消息发送给队列的slave进程;一次是队列的master进程进行广播同步将消息发送给slave进程。此外,镜像队列的GM算法实现 ,每条消息还会有额外的确认消息在集群间进行发送。
再结合图中的情况,一条消息从生产者到消费,Node1节点是2进3出的流量,Node2节点是2进1出的流量。
和集群中的场景一样,如果生产者消费者连接的节点不是镜像队列master进程所在的队列,一条消息从生产到消费,生产者消费者连接的节点是3进3出,队列master进程所在的节点是2进2出。
【总结】
从前面的分析不难看出,镜像队列在集群中所增加的网络通信是较大的,尤其是出现跨节点通信的情况,因此,队列数量不多,并且队列的消息量不大的情况下,可以考虑使用;而在队列数量较多,并且队列都有较大的消息量的情况下使用镜像队列,需要在高可用,高性能之间进行权衡,因为集群间的网络流量可能会是非常大的,实际测试时通过netstat发现rabbitmq的分布式端口,其发送和接收队列都有大量的数据堆积,导致性能出现瓶颈。
另外,镜像队列可以调整的参数不多,官方也在3.8.0版本中推出了新的队列模式(quorum queue)用来替代镜像队列的方案。有兴趣的朋友可以尝鲜研究下。
相关文章
- 【说站】java RabbitMQ消息队列是什么
- 畅购第十四天rabbitmq 延时队列
- rabbitmq优先级队列_rabbitmq主从模式
- 【SpringBoot】43、SpringBoot中整合RabbitMQ实现延时队列(延时插件篇)「建议收藏」
- RabbitMQ——队列索引文件格式
- RabbitMQ 延迟队列
- RabbitMQ之延迟队列
- 15-RabbitMQ高级特性-死信队列
- RabbitMQ、RocketMQ、Kafka延迟队列实现
- RabbitMQ之延迟队列(整合SpringBoot)
- #栈和队列相关oj
- MQ发送消息到队列的Java代码详解编程语言
- MQ接收队列到本地文件的Java代码详解编程语言
- java 线程池线程忙碌且阻塞队列也满了时给一个拒接的详细报告详解编程语言
- RabbitMQ 高可用实现镜像队列
- 实现延迟队列的Redis简易教程(redis实现延迟队列)
- Linux 卸载RabbitMQ的经验分享(linux卸载rabbitmq)
- Redis:高效、可靠的消息队列实现方案(redis作为消息队列)
- Redis秒杀队列抢购不再捉襟见肘(秒杀 redis 队列)
- 探究Redis中全部队列信息(查看redis所有队列)
- 消息队列之父Redis极致性能海量支持(消息队列种类redis)
- Redis消息队列加锁,保护数据安全(消息队列redis加锁)
- 任务调度使用多线程从Redis读取队列数据(多线程读redis队列)
- 多线程智能化管理Redis队列(多线程redis队列)
- Redis集群队列模式实现分布式任务管理(redis集群 队列模式)
- 利用Redis队列编写视频教程(redis队列 视频教程)
- Redis队列缓存更好地收集日志信息(redis队列缓存日志)
- Redis队列状态精准监测,保障数据流畅传输(redis队列检测)
- 化构建异步任务系统采用Redis队列实现串行化(redis 队列技术串行)
- 多ajax请求的各类解决方案(同步,队列,cancel请求)
- php中使用redis队列操作实例代码
- PHP队列用法实例