rabbitMq的组件与原理,exchange四种方式,重复消费、顺序错乱_消费者的exchange和生产者的exchange是一个吗-程序员宅基地

技术标签: mq  面试题  rabbitmq  原理  组件  

rabbitMq系统架构

系统架构图如下:

几个概念说明: 
Producer:消息生产者,就是投递消息的程序.
Consumer:消息消费者,就是接受消息的程序. 
message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输 

Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:存放message的对列,每个消息都会被投到一个或多个队列。 

Broker:接收和分发消息的应用,一个RabbitmqServer就是一个broker。
vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。 
Channel:消息通道,在客户端的每个tcp连接里,可建立多个channel,为了节省tcp连接。

Binding:绑定,将Exchange和Queue绑定的时候会指定一个绑定键(BindingKey),因为exchange可以和多个queue绑定,那么消息到达exchange时会带有Routingkey,exchange就根据routingkey和bindingkey是否匹配决定将message路由到一个或多个queue。
BindingKey:绑定键,将Exchange和Queue绑定的时候会指定一个绑定键(BindingKey)
RoutingKey:消息路由键,Producer发送消息给Exchange时会指定RoutingKey,当该消息的RoutingKey和BindinggKey 相匹配时,消息会被路由到对应的队列中

消息生产者并没有直接将消息发送给消息队列,而是通过建立与Exchange的Channel,将消息发送给Exchange,Exchange根据规则,将消息转发给指定的消息队列。消费者通过建立与消息队列相连的Channel,从消息队列中获取消息。

这里谈到的Channel可以理解为建立在生产者/消费者和RabbitMQ服务器之间的TCP连接上的虚拟连接,一个TCP连接上可以建立多个Channel。 RabbitMQ服务器的Exchange对象可以理解为生产者发送消息的邮局,消息队列可以理解为消费者的邮箱。Exchange对象根据它定义的规则和消息包含的routing key以及header信息将消息转发到消息队列。

根据转发消息的规则不同,RabbitMQ服务器中使用的Exchange对象有四种,Direct Exchange, Fanout Exchange, Topic Exchange, Header Exchange,如果定义Exchange时没有指定类型和名称, RabbitMQ将会为每个消息队列设定一个Default Exchange,它的Routing Key是消息队列名称。

消息的路由:
消息提供方->路由->一至多个队列
消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。
通过队列路由键,可以把队列绑定到交换器上。
消息到达交换器后,RabbitMQ会将消息的路由键与队列的绑定键进行匹配(针对不同的交换器有不同的路由规则);

exchange的四种类型

1、Direct Exchange
一个 Exchange 和多个 Queue 绑定,会把消息路由到 BindingKey 和 RoutingKey 完全匹配的队列中

2、Fanout Exchange
一个 Exchange 和多个 Queue 绑定,会把消息路由到所有与该 Exchange 绑定的 Queue,此时routingKey不发挥作用

3、Topic Exchange
和 Direct Exchange 相似,也是将消息路由到 BindingKey 和 RoutingKey 匹配的 Queue,匹配规则如下:
RoutingKey 为一个由 “.” 分隔的字符串(被“.”分隔开的每一段成为一个单词)
BindingKey 也为一个由 “.” 分隔的字符串
BindingKey 中可以存在两种特殊的字符串 “*” 和 “#”,其中 “*” 用于匹配一个单词,“#”用于匹配 0 个或者多个单词

4、Header Exchange
性能很差,不实用

exchange类型选择

1、publish 一次 consume 一次 :采用 Direct Exchange
2、publish 一次 consume 多次 :采用 Fanout ,也可以采用direct,绑定多个queue使用相同的routingkey.但fanout更佳
2、publish 一次 consume 次数不定 :采用 Topic Exchange

持久化

一个好的消息队列当然需要消息持久化功能,服务宕机,未消费消息不丢失,RabbitMQ持久化分为Exchange、Queue、Message。Exchange 和 Queue 持久化 指持久化Exchange、Queue 元数据,持久化的是自身,服务宕机,Exchange 和 Queue 自身就没有了。Message 持久化 顾名思义 把每一条消息体持久化,服务宕机,消息不丢失

    Durable 持久、Transient 临时,Queue新建类似

原文:https://blog.csdn.net/aa1215018028/article/details/80932242 

rabbitMq消息确认、重复、缺点等问题

1如何确保消息正确地发送至RabbitMQ? 如何确保消息接收方消费了消息?

发送方确认模式:ack+nack:

将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。
一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一ID)。
如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条nack(not acknowledged,未确认)消息。
发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。

消费者确认模式:ack+默认断开重发

为了保证数据不被丢失,RabbitMQ支持消息确认机制,为了保证数据能被正确处理而不仅仅是被Consumer收到,那么我们不能采用no-ack,而应该是在处理完数据之后发送ack. 
在处理完数据之后发送ack,就是告诉RabbitMQ数据已经被接收,处理完成,RabbitMQ可以安全的删除它了. 
如果Consumer退出了但是没有发送ack,那么RabbitMQ就会把这个Message发送到下一个Consumer,这样就保证在Consumer异常退出情况下数据也不会丢失. 
RabbitMQ它没有用到超时机制.RabbitMQ仅仅通过Consumer的连接中断来确认该Message并没有正确处理,也就是说RabbitMQ给了Consumer足够长的时间做数据处理。 
如果忘记ack,那么当Consumer退出时,Mesage会重新分发,然后RabbitMQ会占用越来越多的内存.
下面罗列几种特殊情况:
如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重)
如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多的消息。

2.如何避免消息重复投递、消息的幂等性、消息的顺序?
在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重的依据(消息投递失败并重传),避免重复的消息进入队列;      笔者问题:怎么保证消息相同时inner-msg-id一样,消息不同时inner-msg-id不一样?

消息重复消费的幂等性
1 业务自身具有幂等性或者处理的幂等性,此时消息重复消费没有问题
2 每个消息均有唯一的id,消费消息的时候成功的同时记录该id到库或者redis中,每次消费前进行验证

消息的顺序性
正常订单状态:1订单创建 2订单确认 3待收货 4订单完成 5退货完成
场景:自提商品,为了保证流程完整性,直接走完订单确认、收货、订单完成
每个状态对应一个消息,那么可能出现的问题是234三个消息几乎同时进入mq,但是放到了不同的server上,
假设server3上累积10000条消息,状态3对应的消息存入了server3;server4上累积10条消息,状态4对应的消息存入了server4
因为server4上消息少,所以消费的时候,先消费 订单完成 的消息,然后再消费 待收货 对应的消息,那么最后订单状态变成了待收货,其实已经完成了,有问题。

有两种方案:
1 调整业务处理逻辑,消费消息的逻辑应该是订单的状态只能正向走,不能逆向走,那么即使获取到的消息顺序有问题,订单状态最后也是正常的。
2 将同一个系列相关的消息放到同一个redis的queue中,那么消息就会是顺序的

3.消息基于什么传输?
由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。
信道和tcp连接的区别
信道的原理是一条线程一条信道,多条线程多条信道共同使用一条TCP连接。一条TCP连接可以容纳无限的信道,即使每秒成千上万的请求也不会造成性能瓶颈

4.消息如何分发?
若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。
通过exchange的fanout模式可实现多消费的功能

5.如何确保消息不丢失?
消息持久化,当然前提是队列必须持久化
RabbitMQ确保持久性消息能从服务器重启中恢复的方式是,将它们写入磁盘上的一个持久化日志文件,当发布一条持久性消息到持久交换器上时,Rabbit会在消息提交到日志文件后才发送响应。
一旦消费者从持久队列中消费了一条持久化消息,RabbitMQ会在持久化日志中把这条消息标记为等待垃圾收集。如果持久化消息在被消费之前RabbitMQ重启,那么Rabbit会自动重建交换器和队列(以及绑定),并重新发布持久化日志文件中的消息到合适的队列。

6.rabbitmq的集群
镜像集群模式
你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。
好处在于,你任何一个机器宕机了,没事儿,别的机器都可以用。坏处在于,第一,这个性能开销也太大了吧,消息同步所有机器,导致网络带宽压力和消耗很重!第二,这么玩儿,就没有扩展性可言了,如果某个queue负载很重,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue

7.mq的缺点
引入mq增加系统的复杂性和不稳定性
系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ挂了咋整?MQ挂了,整套系统崩溃了。
系统复杂性提高:
硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已

一致性问题:
A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。

借鉴:https://blog.csdn.net/qq_42629110/article/details/84965084 
https://blog.csdn.net/maihilton/article/details/80928661

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/h2604396739/article/details/89028385

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search