Rabbitmq面试题总结,非常详细,杜绝标题党,不详细你打我,下次不写博客了

说明

我为什么要做这么一个总结,虽然我也是个小白,最近也在找工作,但是我们上网看面试题的时候,发现这些所谓的大博主,什么狗屁新星,没一点原创,抄的可怕,标明原创也就算了,还一字不漏的给抄下来,有些一字不漏的复制我理解,因为大伙说法都那样,但是有些说不明白也一顿乱抄,真不知道他们自己看懂了没有,又搬了过去.“我并不反对借鉴,但也得有个度,当你搜索一个面试题发现几页下来都是一模一样,内容一样,标点一样的时候,你会怎么样?”

我也是总结的,非原创,因为知识都是一样,学习过来的,并且我这章内容里也有一些照抄的,那是因为我发现这个说法我已经不需要总结了,已经说的非常好了,我复制过来,并标明出处.但是有一些是我自己看了很多篇总结而来的,或者看视频看过来的,我就不标明出处了.
注意:我和其他博主不同的是,我会标明出处!!希望大家以后抄的时候也要抄个出处,网络的环境是大伙公共维护的.

什么是MQ?

mq是一个消息队列,其主要目的是为了解决传统的消息传输上管理困难,效率不高的问题.
mq有三大优点:解耦,异步,削峰.
解耦: 如果是传统的消息通讯方式,无论是哪一方都要去维护一份供外部通讯的这个一个接口,而且各方处理消息的能力有限,效率上明显跟不上,并且这样子二者之间的耦合度非常高,对于拓展管理方面极不友好,而是要了mq就不一样,发送方只需要将消息发送给mq就可以了,别的不用考虑,接口什么的由mq去维护,接收方也只需要去mq里消费消息就可以了,就需要其他开销,一切由mq中间件来做,达到了解耦操作.
异步: 使用mq,还可以达到异步效果,极大地提升了消息传输的效率.发送方在发送消息后不需要关心消费方是否能消费完成,还可以继续发送其他消息.
削峰:如果是传统的消息通讯,一下子有大量的消息发送给接收方,这样对于接收方的处理压力是很大的,而我们刚好可以利用mq达到一个缓冲操作,一旦流量超出了接收方处理范围,不用担心,只需要慢慢消费即可,像经典的双十一,就很容易会使用到mq这么一个优点.
虽然mq有三大优点,但是我们还是得关心其一些缺点:
因为增加了中间件,系统复杂度肯定大大提高,增加了很多维护的成本,比如我们要保证消息不丢失(一致性)和消息幂等性问题,还要保证mq的高可用等.

MQ有什么缺点?

系统可用性降低

系统引入的外部依赖越多越容易挂掉本来你就是A系统调用BCD三个系统的接口就好了人 ABCD四个系统好好的没啥问题你偏加个MQ进来万一MQ挂了咋整MQ挂了整套系统崩溃了你不就完了么。(可以利用集群解决)

系统复杂性提高
硬生生加个MQ进来你怎么保证消息没有重复消费怎么处理消息丢失的情况怎么保证消息传递的顺序性头大头大问题一大堆痛苦不已。

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

所以消息队列实际是一种非常复杂的架构你引入它有很多好处但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉最好之后你会发现妈呀系统复杂度提升了一个数量级也许是复杂了10倍。但是关键时刻用还是得用的。
————————————————
版权声明本文为CSDN博主「Java小叮当」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/m0_48795607/article/details/116064045

MQ的应用场景

2.1异步处理
场景说明用户注册后需要发注册邮件和注册短信。传统的做法有两种1.串行的方式2.并行方式。

1串行方式将注册信息写入数据库成功后发送注册邮件再发送注册短信。以上三个任务全部完成后返回给客户端。架构KKQ466097527欢迎加入
2并行方式将注册信息写入数据库成功后发送注册邮件的同时发送注册短信。以上三个任务完成后返回给客户端。与串行的差别是并行的方式可以提高处理的时间。

假设三个业务节点每个使用50毫秒钟不考虑网络等其他开销则串行方式的时间是150毫秒并行的时间可能是100毫秒。
因为CPU在单位时间内处理的请求数是一定的假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次1000/150。并行方式处理的请求量是10次1000/100。

小结如以上案例描述传统的方式系统的性能并发量吞吐量响应时间会有瓶颈。如何解决这个问题呢

引入消息队列将不是必须的业务逻辑异步处理。改造后的架构如下
按照以上约定用户的响应时间相当于是注册信息写入数据库的时间也就是50毫秒。注册邮件发送短信写入消息队列后直接返回因此写入消息队列的速度很快基本可以忽略因此用户的响应时间可能是50毫秒。因此架构改变后系统的吞吐量提高到每秒20 QPS。比串行提高了3倍比并行提高了两倍。

2.2应用解耦
场景说明用户下单后订单系统需要通知库存系统。传统的做法是订单系统调用库存系统的接口。如下图架构KKQ466097527欢迎加入

传统模式的缺点
1 假如库存系统无法访问则订单减库存将失败从而导致订单失败
2 订单系统与库存系统耦合

如何解决以上问题呢引入应用消息队列后的方案如下图
image.png
订单系统用户下单后订单系统完成持久化处理将消息写入消息队列返回用户订单下单成功。
库存系统订阅下单的消息采用拉/推的方式获取下单信息库存系统根据下单信息进行库存操作。
假如在下单时库存系统不能正常使用。也不影响正常下单因为下单后订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。

2.3流量削锋
流量削锋也是消息队列中的常用场景一般在秒杀或团抢活动中使用广泛。

应用场景秒杀活动一般会因为流量过大导致流量暴增应用挂掉。为解决这个问题一般需要在应用前端加入消息队列。
可以控制活动的人数
可以缓解短时间内高流量压垮应用

用户的请求服务器接收后首先写入消息队列。假如消息队列长度超过最大数量则直接抛弃用户请求或跳转到错误页面
秒杀业务根据消息队列中的请求信息再做后续处理。

2.4日志处理

日志处理是指将消息队列用在日志处理中比如Kafka的应用解决大量日志传输的问题。架构简化如下
日志采集客户端负责日志数据采集定时写受写入Kafka队列
Kafka消息队列负责日志数据的接收存储和转发
日志处理应用订阅并消费kafka队列中的日志数据

(1)Kafka接收用户日志的消息队列。
(2)Logstash做日志解析统一成JSON输出给Elasticsearch。
(3)Elasticsearch实时日志分析服务的核心技术一个schemaless实时的数据存储服务通过index组织数据兼具强大的搜索和统计功能。
(4)Kibana基于Elasticsearch的数据可视化组件超强的数据可视化能力是众多公司选择ELK stack的重要原因。

2.5消息通讯
消息通讯是指消息队列一般都内置了高效的通信机制因此也可以用在纯的消息通讯。比如实现点对点消息队列或者聊天室等。

点对点通讯
客户端A和客户端B使用同一队列进行消息通讯。

聊天室通讯
客户端A客户端B客户端N订阅同一主题进行消息发布和接收。实现类似聊天室效果。

以上实际是消息队列的两种消息模式点对点或发布订阅模式。模型为示意图供参考。

————————————————
版权声明本文为CSDN博主「许文强」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/qq_16824623/article/details/78901953

Rabbitmq是什么?Rabbitmq的构造

image.png
1生产者Publisher生产消息就是投递消息的一方。消息一般包含两个部分消息体payload和标签Label
2消费者Consumer消费消息也就是接收消息的一方。消费者连接到RabbitMQ服务器并订阅到队列上。消费消息时只消费消息体丢弃标签。
3Broker服务节点表示消息队列服务器实体。一般情况下一个Broker可以看做一个RabbitMQ服务器。
4Queue消息队列用来存放消息。一个消息可投入一个或多个队列多个消费者可以订阅同一队列这时队列中的消息会被平摊轮询给多个消费者进行处理。
5Exchange交换器接受生产者发送的消息根据路由键将消息路由到绑定的队列上。
6Routing Key 路由关键字用于指定这个消息的路由规则需要与交换器类型和绑定键(Binding Key)联合使用才能最终生效。
7Binding绑定通过绑定将交换器和队列关联起来一般会指定一个BindingKey通过BindingKey交换器就知道将消息路由给哪个队列了。
8Connection 网络连接比如一个TCP连接用于连接到具体broker
9Channel 信道AMQP 命令都是在信道中进行的不管是发布消息、订阅队列还是接收消息这些动作都是通过信道完成。因为建立和销毁 TCP 都是非常昂贵的开销所以引入了信道的概念以复用一条 TCP 连接一个TCP连接可以用多个信道。客户端可以建立多个channel每个channel表示一个会话任务。
10Message消息由消息头和消息体组成。消息体是不透明的而消息头则由一系列的可选属性组成这些属性包括routing-key路由键、priority相对于其他消息的优先权、delivery-mode指出该消息可能需要持久性存储等。
11Virtual host虚拟主机用于逻辑隔离表示一批独立的交换器、消息队列和相关对象。一个Virtual host可以有若干个Exchange和Queue同一个Virtual host不能有同名的Exchange或Queue。最重要的是其拥有独立的权限系统可以做到 vhost 范围的用户控制。当然从 RabbitMQ 的全局角度vhost 可以作为不同权限隔离的手段

————————————————
版权声明本文为CSDN博主「张维鹏」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/a745233700/article/details/115060109

vhost 是什么? 起什么作用?

每一个rabbitmq服务器都能创建虚拟的消息服务器我们称之为虚拟主机(virtual host)。简称vhost
特性
每一个vhost本质上是一个小型的独立的rabbitmq服务器拥有自己独立的完整的一套队列、绑定关系、交换器等。同一个服务器上的多个vhost是完全隔离的。队列及交换器等不互通。

所以一个broker可以开设多个vhost用于不同用户的权限分离

如何创建vhost?
1)通过前台页面的admin中创建
2)使用rabbitmqctl add_vhost vhost名称 命令

如何删除vhost?
1)前台删除
2)rabbitmqctl delete_vhost vhost_name
————————————————
版权声明本文为CSDN博主「whale4fly」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/w_zhendefu/article/details/110454102

谈谈你对AMQP的理解

AMQP协议是什么

AMQP协议所谓的高级消息队列协议可以把它理解成一种公认的协议规范就像http协议一样只是这个AMQP协议针对的是消息队列。这个协议使得遵从了它的规范的客户端应用和消息中间件服务器的全功能互操作成为可能。

了解下AMQP协议的基本概念

Broker用于接受信息和分发信息的应用。
Virtual hosts:在一个Broker上面划分出多个隔离的环境这多个环境就可以理解成是Virtual hosts就像使用虚拟机一样每个虚拟机之间都有完整的组件各Virtual hosts下的用户、交换器以及队列等互不影响这样方便不同的业务团队在使用同一个Rabbit server提供的服务时能够划清界限。
Connection消息生产者和消息消费者还有Broker之间的TCP连接如果要断开连接只会在客户端断开而
Broker不会断开连接除非网络出现了故障或者Broker服务出了问题。
Channel通道如果每一次访问消息队列中间件都建立一个TCP连接的话那么系统资源会被大量的占用效率也会降低所以AMQP提供了Channel机制共享同一个TCP连接而一个TCP连接里可以有大量的Channel。假设如果有多个线程访问消息队列中间件服务每个线程通常都会有自己单独的Channel来做通信而每个Channel会有自己的Channel id这样客户端和Broker就能够互相识别Channel所以Channel之间是完全隔离的。
Exchange交换机这是消息到达Broker的第一站由于Exchange和Queues之间有绑定键来确定双方发送消息的匹配规则所以这时Exchange会根据消息的路由键和自己的类型来匹配绑定规则将消息分发到对应的Queues上。
Queue队列消息所到达的最终站消费者从这里拿消息做消费。
Binding可以把它理解成一个虚拟的连接定义了Exchange和Queues之间的匹配规则只有匹配这个规则的交换机里的消息才会被发送到这个队列里不过如果消息没法找到匹配的队列的话那么根据该条消息的属性这个消息要么被丢弃要么返回生产者那里。
Exchange的类型

这里把Exchange和Queues之间的匹配规则称之为绑定键。

类型 说明
direct(直连) 消息的路由键要和绑定键一模一样才能分发到队列
fanout(广播) 无需绑定键只要有和这个交换机做绑定的队列都会收到消息有点类似发布-订阅
topic(主题) 这个类型的交换机要求消息路由键和绑定键要模糊匹配才能分发以.号来分割每个词 #号代表匹配多个词*号代表匹配只一个词
headers(header属性) 这种类型的交换机不再是基于路由键了而是基于消息中的header属性只有消息中header属性的值与绑定键相同时消息才会被分发到相应的队列中
默认交换机 如果不指定上述的交换机类型就会使用默认的direct类型同时绑定键默认是队列名所以消息会分发到与路由键同名的队列里
————————————————
版权声明本文为CSDN博主「绅士jiejie」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/weixin_38106322/article/details/104862947

消息是如何路由的?

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

常用的交换器主要分为一下三种(广播模式)

fanout如果交换器收到消息将会广播到所有绑定的队列上

direct如果路由键完全匹配消息就被投递到相应的队列

topic可以使来自不同源头的消息能够到达同一个队列。 使用 topic 交换器时可以使用通配符
————————————————
版权声明本文为CSDN博主「Java小叮当」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/m0_48795607/article/details/116064045

Rabbitmq里的交换机类型有哪些,都有什么区别?什么是交换机?

1、什么是Exchange
在RabbitMQ中生产者发送消息不会直接将消息投递到队列中而是先将消息投递到交换机中 在由交换机转发到具体的队列 队列再将消息以推送或者拉取方式给消费者进行消费.

2、路由键 ( RoutingKey)
生产者将消息发送给交换机的时候 会指定RoutingKey指定路由规则。

3、绑定键 ( BindingKey)
通过绑定键将交换机与队列关联起来 这样RabbitMQ就知道如何正确地将消息路由到队列。

4、关系
生产者将消息发送给哪个Exchange是需要由RoutingKey决定的生产者需要将Exchange与哪个队列绑定时需要由 BindingKey决定的。

二、交换机类型和区别
1、直连交换机 Direct exchange
直连交换机的路由算法非常简单 将消息推送到binding key与该消息的routing key相同的队列。

image.png

直连交换机X上绑定了两个队列。第一个队列绑定了绑定o键range, 第二个队列有两个绑定键 black和green。

在这种场景下一 个消息在布时指定了路由键为orange将会只被路由到队列Q1 I 路由键为black 和green的消息都将被路由到队列Q2。其他的消息都将被丢失。

同一个绑定键可以绑定到不同的队列上去 可以增加一个交换机X与队列Q2的绑定键在这种清况下直连交换机将会和广播交换机有着相同的行为 将消息推送到所有匹配的队列。一个路由键为black的消息将会同时被推送到队列Q1和Q2。
image.png

2、 主题交换机 Topic exchange
直连交换机的缺点

直连交换机的 routing_key方案非常简单 如果我们希望一 条消息发送给多个队列 那么这个交换机需 要绑定上非常多的 routing_key.

假设每个交换机上都绑定一堆的 routing_key连接到各个队列上。那么消息的管理 就会异常地困难。

主题交换机的特点

发送到主题交换机的 消息不能有任意的 routing key, 必须是由点号分开的一串单词这些单词可以是任意的但通常是与消息相关的一些特征。

如以下是几个有效的routing key:

“stock.usd.nyse”, “nyse.vmw”, “quick.orange.rabb 代”, routing key的单词可以 有很多最大限制是255 bytes。

Topic 交换机的 逻辑与 direct 交换机有点 相似 使用特定路由键发送的消息 将被发送到所有使用匹配绑定键绑定的队列 然而 绑定键有两个特殊的情况

*表示匹配任意一个单词

#表示匹配任意—个或多个单词

image.png

routing key quick.orange.rabbit-> queue Ql, Q2

routing key lazy.orange.elephant-> queue Ql,Q2

延申

当一个队列的绑定键是"#"它将会接收所有的消息而不再考虑所接收消息的路由键。

当一个队列的绑定键没有用到"#"和’*"时它又像 direct 交换一样工作。

2、扇形交换机 Fanout exchange
扇形交换机是最基本的交换机类型它所能做的事清非常简单广播消息。

扇形交换机会把能接收到的消息全部发送给绑定在自己身上的队列。因为广播不需要'思考”所以扇形交换机处理消息的速度也是所有的交换机类型里面最快的。

3、首部交换机 Headers exchange
类似主题交换机但是头交换机使用多个消息属性来代替路由键建立路由规则。通过判断消息头的值能否与指定的绑定相匹配来确立路由规则。
此交换机有个重要参数”x-match”

当”x-match”为“any”时消息头的任意一个值被匹配就可以满足条件
当”x-match”设置为“all”的时候就需要消息头的所有值都匹配成功

————————————————
版权声明<<首部交换机>>为CSDN博主「hry2015」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/hry2015/article/details/79118804

4、默认交换机
实际上是— 个由 RabbitMQ预先声明好的名字为空字符串的直连交换机 (direct exchange) 。

它有一个特殊的属性使得它对于简单应用特别有用处 那就是每个新建队列 (queue) 都会自动绑定到默认交换机上绑定的 路由键(routing key) 名称与队列名称相同。

当你声明了一个名为“hello”的队列RabbitMQ会自动将其绑定到默认交换机上绑定binding的路由键名称也是为“hello”。

当携带着名为“hello”的路由键的信息被发送到默认交换机的时候此消息会被默认交换机路由至名为“hello”的队列中

类似amq.*的名称的交换机这些是RabbitMQ默认创建的交换机。

这些队列名称被预留做RabbitMQ内部使用不能被应用使用否则抛出403错误

5、Dead Letter Exchange(死信交换机)
演示链接https://blog.csdn.net/weixin_60389087/article/details/123167193

RabbitMQ作为一个高级消息中间件提出了死信交换器的概念。

这种交互器专门处理死了的信息被拒绝可以重新投递的信息不能算死的。

消息变成死信一般是以下三种情况

①、消息被拒绝并且设置requeue参数为false。

②、消息过期默认情况下Rabbit中的消息不过期但是可以设置队列的过期时间和信息的过期的效果

③、队列达到最大长度一般当设置了最大队列长度或大小并达到最大值时

当满足上面三种情况时消息会变成死信消息并通过死信交换机投递到相应的队列中。

我们只需要监听相应队列就可以对死信消息进行最后的处理。

订单超时处理

image.png

生产者生产一条1分钟后超时的订单信息到正常交换机exchange-a中消息匹配到队列queue-a但一分钟后仍未消费。
消息会被投递到死信交换机dlx-exchange中并发送到私信队列中。
死信队列dlx-queue的消费者拿到信息后根据消息去查询订单的状态如果仍然是未支付状态将订单状态更新为超时状态。


6.交换机的属性
Name:交换机名称

Type:交换机类型directtopicfanoutheaders

Durability:是否需要持久化如果持久性则RabbitMQ重启后交换机还存在

Auto Delete:当最后一个绑定到Exchange上的队列删除后自动删除该Exchange

Internal:当前Exchange是否用于RabbitMQ内部使用默认为false。

Arguments:扩展参数用于扩展AMQP协议定制使用

————————————————
版权声明本文为CSDN博主「爱嘤斯塔」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/weixin_60389087/article/details/123140651

消息传输的模式有哪些?

1.简单模式
简单模式是最简单的消息模式它包含一个生产者、一个消费者和一个队列。生产者向队列里发送消息消费者从队列中获取消息并消费。
image.png
2.工作模式
工作模式是指向多个互相竞争的消费者发送消息的模式它包含一个生产者、两个消费者和一个队列。两个消费者同时绑定到一个队列上去当消费者获取消息处理耗时任务时空闲的消费者从队列中获取并消费消息。
image.png
3.发布/订阅模式
发布/订阅模式是指同时向多个消费者消费消息的模式类似广播的形式它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去两个队列绑定到交换机上去生产者通过发送消息到交换机所有消费者接收并消费消息。
image.png
4.路由模式
路由模式是可以根据路由键选择性给多个消费者发送消息的模式它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去两个队列通过绑定键绑定到交换机上去生产者发送消息到交换机交换机通过路由键转发到不同队列队列绑定的消费者接收并消费消息
(要求路由键和绑定键相同)image.png
常用的交换器主要分为一下三种
fanout如果交换器收到消息将会广播到所有绑定的队列上
direct如果路由键完全匹配消息就被投递到相应的队列
topic可以使来自不同源头的消息能够到达同一个队列。 使用 topic 交换器时可以使用通配符

5. 通配符模式:就是绑定键是某种泛泛的符号规则,如果传过来的消息路由键与绑定键匹配,就能传递到对应的消息队列上
特殊匹配符号
*只能匹配一个单词
#可以匹配零个或多个单词。
模式示意图
image.png

消息分发策略有哪些?

1、轮询分发
RabbitMQ 分发消息默认采用的轮训分发但是在某种场景下这种策略并不是很好当有两个消费者在处理任务时其中有个消费者 处理任务的速度非常快而另外一个消费者处理速度却很慢这个时候我们还是采用轮训分发就会导致这处理速度快的这个消费者很大一部分时间处于空闲状态。我们可以通过修改消息分发德默认机制来达到优化目的

2、不公平分发
通过设置参数 channel.basicQos(1);实现不公平分发策略使得能者多劳
image.png
通过RabbitMq的Web管理页面可以看到Channels的Prefetch count属性显示为1则表示不公平分发成功
image.png
上面介绍了basicQos如果我们将qos的值设为1那么你想一想会出现什么情况呢信道中只允许传输一条消息那么当这条消息处理完后队列会立马发送下一条消息所以这个时候快的不断处理慢的等待当前处理完再处理下一条。这样就实现了能者多劳。
3、预值分发
当消息被消费者接收后但是没有确认此时这里就存在一个未确认的消息缓冲区用于存储非被确认的消息该缓存区的大小是没有限制的。

预取值 定义通道上允许的未确认消息的最大数量。一旦未确认消息数量达到配置的最大数量RabbitMQ 将停止在通道上传递更多消息除非至少有一个未处理的消息被确认例如假设在通道上有未确认的消息 5、6、78并且通道的预取值计数设置为 4此时 RabbitMQ 将不会在该通道上再传递任何消息除非至少有一个未应答的消息被 ack例如 tag=6 这个消息刚刚被确认 ACK此时RabbitMQ 将会感知这个情况到并再发送一条消息。

如果消费者消费了大量的消息但是没有确认的话就会导致消费者连接节点的内存消耗变大所以找到合适的预取值是一个反复试验的过程不同的负载该值取值也不同 100 到 300 范 围内的值通常可提供最佳的吞吐量。

其实预取值设置就是一个非公平分发策略,我们通过设置qos来设置消息缓冲区允许未确认消息的最大数量,当我们设置为1时,是最保守的,吞吐量也是最低的,而100到300这个范围通常是最佳的.
————————————————
版权声明本文为CSDN博主「一恍过去」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/zhuocailing3390/article/details/122462590

rabbitmq消息处理流程,即生产者生产消息,消费者接收消息过程

生产者消息投递过程

生产者连接到Broker 建立一个连接然后开启一个信道

接着生产者声明一个交换器 并设置相关属性比如交换机类型、是否持久化、是否自动删除、是否内置等

生产者声明一个队列井设置相关属性比如是否排他、是否持久化、是否自动删除、消息最大过期时间、消息最大长度、消息最大字节数等

生产者通过绑定键将交换器和队列绑定起来

生产者发送消息至Broker 发送的消息包含消息体和路由规则(可以理解为路由键)、交换器、优先级、是否持久化、过期时间、延时时间等信息的标签

相应的交换器根据接收到的路由键和与队列的绑定键查找相匹配的队列如果找到 则将从生产者发送过来的消息存入相应的队列中

如果没有找到 则根据生产者配置的属性选择丢弃还是回退给生产者

关闭信道

关闭连接

消费者消费消息过程

消费者连接到Broker 建立一个连接开启一个信道

消费者向 RabbitMQ Broker 请求消费相应队列中的消息在这个过程中可能会设置消费者标签、是否自动确认、是否排他等

等待 RabbitMQ Broker 回应并投递相应队列中的消息 消费者接收消息。

消费者确认接收到的消息

RabbitMQ从队列中删除相应己经被确认的消息

关闭信道

关闭连接。

涉及名词解释

在上方的消息流转过程中涉及了以下几个名词

是否持久化

将数据持久化到磁盘中

是否自动删除

当一个队列或交换机的所有消费者都与之断开连接时则这个队列或交换机就会自动删除

是否内置

客户端程序无法直接发送消息到这个交换器中只能通过交换器路由到交换器这种方式

是否排他

如果一个队列被声明为排他队列该队列仅对首次声明它的连接可见并在连接断开时自动删除。这里需要注意的是

排他队列是基于连接可见的同一个连接的不同信道是可以同时访问同一连接创建的排他队列; "首次"是指如果一个连接己经声明了排他队列其他连接是不允许建立同名的排他队列的这个与普通队列不同:即使该队列是持久化的一旦连接关闭或者客户端退出该排他队列都会被自动删除这种队列适用于一个客户端同时发送和读取消息的应用场景。

自动确认

消费者在订阅队列时可以指定 autoAck 参数当 autoAck 等于 false时 RabbitMQ会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上是先打上删除标记之后再删除)

当 autoAck 等于 true 时 RabbitMQ 会自动把发送出去的消息置为确认然后从内存(或者磁盘)中删除而不管消费者是否真正地消费到了这些消息

采用消息确认机制后只要设置 autoAck 参数为 false 消费者就有足够的时间处理消息不用担心处理消息过程中消费者进程挂掉后消息丢失的问题。因为 RabbitMQ 会一直等待持有消息直到消费者显式确认收到消息
————————————————
版权声明本文为CSDN博主「javaxuexilu」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/javaxuexilu/article/details/100738621

如何保证消息的顺序消费

消息在投入到queue的时候是有顺序如果只是单个消费者来处理对应的单个queue是不会出现消息错乱的问题。但是在消费的时候有可能多个消费者消费同一个queue由于各个消费者处理消息的时间不同导致消息未能按照预期的顺序处理。其实根本的问题就是如何保证消息按照预期的顺序处理完成。

出现消费顺序错乱的情况

为了提高处理效率一个queue存在多个consumer
image.png

一个queue只存在一个consumer但是为了提高处理效率consumer中使用了多线程进行处理
image.png

保证消息顺序性的方法

将原来的一个queue拆分成多个queue每个queue都有一个自己的consumer。该种方案的核心是生产者在投递消息的时候根据业务数据关键值例如订单ID哈希值对订单队列数取模来将需要保证先后顺序的同一类数据同一个订单的数据 发送到同一个queue当中。
image.png

一个queue就一个consumer在consumer中维护多个内存队列根据业务数据关键值例如订单ID哈希值对内存队列数取模将消息加入到不同的内存队列中然后多个真正负责处理消息的线程去各自对应的内存队列当中获取消息进行消费。
image.png

RabbitMQ保证消息顺序性总结
核心思路就是根据业务数据关键值划分成多个消息集合而且每个消息集合中的消息数据都是有序的每个消息集合有自己独立的一个consumer。多个消息集合的存在保证了消息消费的效率每个有序的消息集合对应单个的consumer也保证了消息消费时的有序性。
————————————————
版权声明本文为CSDN博主「vnbear」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/zw791029369/article/details/109561457

消息队列如何保证消息的可靠性传输

消息的可靠性传输分为两个问题,一个是保证消息不被重复消费,另一个是保证消息不丢失.
保证消息不重复被消费,就是保证消息的幂等性问题,消息的幂等性是指一个操作执行任意多次所产生的影响均与一次执行的影响相同,在mq里,也就是消息只能被消费一次,不能被重复消费.
来看看消息丢失的场景:
发送方丢失,可能发送方在发送消息的过程中,出现网络问题等导致mq接收不到消息,导致了消息丢失.
要解决这个问题,首先可以采用事务机制,在发送消息的时候实现事务机制,若是出现发送失败的情况,可以进行回滚,而让消息重新被发送.但是开启了事务,发送方就必须同步等待事务执行完毕或者回滚,导致消息一多,性能会下降.
但是,还有一个更好的办法:可以采用确认机制,发送方在发送消息的时候必须要保证要收到一个确认消息,如果没有收到或者收到失败的确认消息,就说明消息发送失败,要重新进行发送,确认机制是可以采用异步进行的,这样就极大地保证了在保留效率的基础上又能保证消息的不丢失问题.
第二个丢失问题可能是在mq方发生的,如果mq没有进行持久化,出现了宕机关机等情况,消息就会丢失,解决办法无非就是将消息进行持久化,这样在出现问题的时候可以及时对消息进行恢复.
第三个丢失问题可能在消费方发生,这和发送方丢失问题类似,解决这个问题也是采用确认机制,这样一来就可以实现效率上的保证和消息不丢失的保证.
但是解决了这些问题,就会产生下面的幂等性问题:
我们都知道mq是可以进行重发的,且只有在它认为失败的情况会进行重发.什么时候mq会认为它发送给消费者的消息是失败的呢?也就是超出了它等待消费者响应的时间,这是一个超时时间,若是过了这个时间消费者仍然没有响应,说明mq发送失败,就会进行重试,而其实这个时候消费者可能是没有失败的,它只是因为某个原因导致消费超出了mq的等待时间而已,这个时候mq再发送一次消息,消费者就会重复消费.
实现幂等性消费:

① 通过数据库比如处理订单时记录订单ID在消费前去数据库中进行查询该记录是否存在如果存在则直接返回。
② 使用全局唯一ID再配合第三组主键做消费记录比如使用 redis 的 set 结构生产者发送消息时给消息分配一个全局ID在每次消费者开始消费前先去redis中查询有没有消费记录如果消费过则不进行处理如果没消费过则进行处理消费完之后就将这个ID以k-v的形式存入redis中(过期时间根据具体情况设置)。
————————————————
版权声明本引用为CSDN博主「张维鹏」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/a745233700/article/details/115060109

如何处理消息堆积情况?

场景题几千万条数据在MQ里积压了七八个小时。

9.1、出现该问题的原因

消息堆积往往是生产者的生产速度与消费者的消费速度不匹配导致的。有可能就是消费者消费能力弱渐渐地消息就积压了也有可能是因为消息消费失败反复复重试造成的也有可能是消费端出了问题导致不消费了或者消费极其慢。比如消费端每次消费之后要写mysql结果mysql挂了消费端hang住了不动了或者消费者本地依赖的一个东西挂了导致消费者挂了。

所以如果是 bug 则处理 bug如果是因为本身消费能力较弱则优化消费逻辑比如优化前是一条一条消息消费处理的那么就可以批量处理进行优化。

9.2、临时扩容快速处理积压的消息

1先修复 consumer 的问题确保其恢复消费速度然后将现有的 consumer 都停掉

2临时创建原先 N 倍数量的 queue 然后写一个临时分发数据的消费者程序将该程序部署上去消费队列中积压的数据消费之后不做任何耗时处理直接均匀轮询写入临时建立好的 N 倍数量的 queue 中

3接着临时征用 N 倍的机器来部署 consumer每个 consumer 消费一个临时 queue 的数据

4等快速消费完积压数据之后恢复原先部署架构 重新用原先的 consumer 机器消费消息。

这种做法相当于临时将 queue 资源和 consumer 资源扩大 N 倍以正常 N 倍速度消费。

9.4、MQ长时间未处理导致MQ写满的情况如何处理

如果消息积压在MQ里并且长时间都没处理掉导致MQ都快写满了这种情况肯定是临时扩容方案执行太慢这种时候只好采用 “丢弃+批量重导” 的方式来解决了。首先临时写个程序连接到mq里面消费数据消费一个丢弃一个快速消费掉积压的消息降低MQ的压力然后在流量低峰期时去手动查询重导丢失的这部分数据

9.5 短时间内无法扩容或者扩容无法完全解决问题

可以尝试降低一些非核心业务的消息处理,其次可以通过监控排查,优化消费者端的业务代码或者查看是否存在一些消息被重复消息的情况.


————————————————
版权声明本文为CSDN博主「张维鹏」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/a745233700/article/details/115060109

如何保证消息队列的高可用

RabbitMQ 是基于主从非分布式做高可用性的RabbitMQ 有三种模式单机模式、普通集群模式、镜像集群模式

10.1、单机模式一般没人生产用单机模式

10.2、普通集群模式

普通集群模式用于提高系统的吞吐量通过添加节点来线性扩展消息队列的吞吐量。也就是在多台机器上启动多个 RabbitMQ 实例而队列 queue 的消息只会存放在其中一个 RabbitMQ 实例上但是每个实例都同步 queue 的元数据元数据是 queue 的一些配置信息通过元数据可以找到 queue 所在实例。消费的时候如果连接到了另外的实例那么该实例就会从数据实际所在的实例上的queue拉取消息过来就是说让集群中多个节点来服务某个 queue 的读写操作

但普通集群模式的缺点在于无高可用性queue所在的节点宕机了其他实例就无法从那个实例拉取数据RabbitMQ 内部也会产生大量的数据传输。

在这里插入图片描述

10.3、镜像队列集群模式

镜像队列集群是RabbitMQ 真正的高可用模式集群中一般会包含一个主节点master和若干个从节点slave如果master由于某种原因失效那么按照slave加入的时间排序"资历最老"的slave会被提升为新的master。

镜像队列下所有的消息只会向master发送再由master将命令的执行结果广播给slave所以master与slave节点的状态是相同的。比如每次写消息到 queue 时master会自动将消息同步到各个slave实例的queue如果消费者与slave建立连接并进行订阅消费其实质上也是从master上获取消息只不过看似是从slave上消费而已比如消费者与slave建立了TCP连接并执行Basic.Get的操作那么也是由slave将Basic.Get请求发往master再由master准备好数据返回给slave最后由slave投递给消费者。

从上面可以看出队列的元数据和消息会存在于多个实例上也就是说每个 RabbitMQ 节点都有这个 queue 的完整镜像任何一个机器宕机了其它机器节点还包含了这个 queue 的完整数据其他消费者都可以到其它节点上去消费数据。

1缺点

① 性能开销大消息需要同步到所有机器上导致网络带宽压力和消耗很重

② 非分布式没有扩展性如果 queue 的数据量大到这个机器上的容量无法容纳了此时该方案就会出现问题了

2如何开启镜像集群模式呢

在RabbitMQ 的管理控制台Admin页面下新增一个镜像集群模式的策略指定的时候是可以要求数据同步到所有节点的也可以要求同步到指定数量的节点再次创建 queue 的时候应用这个策略就会自动将数据同步到其他的节点上去了。
在这里插入图片描述


————————————————
版权声明本文为CSDN博主「张维鹏」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/a745233700/article/details/115060109

说说你对rabbitmq持久化机制的理解

RabbitMQ 的消息默认存放在内存上面如果不特别声明设置消息不会持久化保存到硬盘上面的如果节点重启或者意外crash掉消息就会丢失。所以就要对消息进行持久化处理。

rabbitmq的持久化分为队列持久化、消息持久化和交换器持久化。

1队列的持久化是在定义队列时的durable参数来决定的当durable为true时才代表队列会持久化。

Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//第二个餐胡设置为true代表队列持久化
channel.queueDeclare("queue.persistent.name", true, false, false, null);
  1. 如果要在重启后保持消息的持久化必须设置消息是持久化的标识。
//通过传入MessageProperties.PERSISTENT_PLAIN就可以实现消息持久化
channel.basicPublish("exchange.persistent", "persistent", MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes());
  1. 上面阐述了队列的持久化和消息的持久化如果不设置exchange的持久化对消息的可靠性来说没有什么影响**但是同样如果exchange不设置持久化那么当broker服务重启之后exchange将不复存在那么既而发送方rabbitmq producer就无法正常发送消息。**这里建议同样设置exchange的持久化。exchange的持久化设置也特别简单.
//durable为true则开启持久化
Exchange.DeclareOk exchangeDeclare(String exchange,String type,boolean durable)throws IOException

所以一般三个持久化设置都要进行.

可以对所有消息都持久化吗?

不可以
持久化的操作是将数据写入磁盘中,效率上肯定比写入内存中要慢很多倍.而我们一般用mq会处理很多业务消息,若是所有消息都持久化,压力无疑是巨大的.所以持久化策略需要综合考虑,以及可能遇到的问题和解决方案,或者我们可以让一些必要数据持久化.

说说你对rabbitmq应答机制的理解

一、消息应答机制
消费者完成一个任务可能需要一段时间如果其中一个消费者处理一个长的任务并仅只完成了部分突然它挂掉由于RabbitMQ 一旦向消费者传递了一条消息便立即将该消息标记为删除。在这种情况下突然有个消费者挂掉了我们将丢失正在处理的消息以及后续发送给该消费者的消息也无法接收到。

为了保证消息在发送过程中不丢失rabbitmq 引入消息应答机制。

消费者在接收到消息并且处理该消息之后告诉 rabbitmq 它已经处理了rabbitmq 可以把该消息删除掉了。

二、自动应答
消息发送后立即被认为已经传送成功这种模式需要在高吞吐量和数据传输安全性方面做权衡,因为这种模式如果消息在接收到之前消费者出现连接或者 channel 关闭那么消息就丢失了,当然另一方面这种模式消费者可以传递过载的消息没有对传递的消息数量进行限制当然这样有可能使得消费者由于接收太多还来不及处理的消息导致这些消息的积压最终使得内存耗尽最终这些消费者线程被操作系统杀死所以这种模式仅适用在消费者可以高效并以某种速率能够处理这些消息的情况下使用。

三、手动消息应答的方法
//用于肯定确认RabbitMQ 已知道该消息并且成功的处理消息可以将其丢弃了
channel.basicAck();

//用于否定确认
channel.basicNack();

//用于否定确认,不处理该消息了直接拒绝可以将其丢弃了
channel.basicReject();

如果消费者由于某些原因失去连接(其通道已关闭连接已关闭或 TCP 连接丢失)导致消息未发送 ACK 确认RabbitMQ 将了解到消息未完全处理并将对其重新排队。如果此时其他消费者可以处理它将很快将其重新分发给另一个消费者。这样即使某个消费者偶尔死亡也可以确保不会丢失任何消息。
————————————————
版权声明本文为CSDN博主「煎丶包」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/qq_39794062/article/details/118112321

说一下Rabbitmq事务机制

1、概述
在使用RabbitMQ的时候我们可以通过消息持久化操作来解决因为服务器的异常奔溃导致的消息丢失除此之外我们还会遇到一个问题当消息的发布者在将消息发送出去之后消息到底有没有正确到达broker代理服务器呢如果不进行特殊配置的话默认情况下发布操作是不会返回任何信息给生产者的也就是默认情况下我们的生产者是不知道消息有没有正确到达broker的如果在消息到达broker之前已经丢失的话持久化操作也解决不了这个问题因为消息根本就没到达代理服务器你怎么进行持久化那么这个问题该怎么解决呢

RabbitMQ为我们提供了两种方式

通过AMQP事务机制实现这也是AMQP协议层面提供的解决方案
通过将channel设置成confirm模式来实现
2、事务机制
这里首先探讨下RabbitMQ事务机制。

RabbitMQ中与事务机制有关的方法有三个txSelect(), txCommit()以及txRollback(), txSelect用于将当前channel设置成transaction模式txCommit用于提交事务txRollback用于回滚事务在通过txSelect开启事务之后我们便可以发布消息给broker代理服务器了如果txCommit提交成功了则消息一定到达了broker了如果在txCommit执行之前broker异常崩溃或者由于其他原因抛出异常这个时候我们便可以捕获异常通过txRollback回滚事务了。

public class P1 {

    private static final String QUEUE_NAME = "test_tx";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtils.getConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME,false,false,true,null);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
        Date date = new Date(System.currentTimeMillis());
        String message = simpleDateFormat.format(date);

        try {
            channel.txSelect();//开始事务
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            channel.txCommit();//提交事务
        }catch (Exception e){
            channel.txRollback();//回滚事务
            System.out.println("send message txRollback");
        }
        channel.close();
        connection.close();


    }
}

————————————————
版权声明本文为CSDN博主「心念W」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/qq_40950803/article/details/106473259

谈谈你对死信队列的理解

概念
当queue消息队列中的消息由于一些原因没办法被消费如果这些消息一直没办法被处理就会从这个正常的消息队列转移到死信消息队列中。

应用场景当用户下单之后如果一直不支付那么用户下单的这条消息就会被存放到死信队列中去。

死信的来源
1.当queue消息队列满的时候再进来的消息就会被放到死信队列中去。

2.在消息应答的时候如果消费者一直没有告诉RabbitMQ有没有成功处理消息那么RabbitMQ消息队列就不清楚自己到底要不要删除这条消息这个时候消息队列中的消息一直没办法处理这样这条消息也会被放到死信队列中去。

3.消息TTL过期什么意思TTL的全拼是Time To Live意思是指存活时间就是消息队列中存放的消息一般都是有一定时间的超过了这个时间这条消息就会被放到死信队列中去。

如何去实现死信队列?
生产者:
发送消息.

普通消费者:
1)在用Map声明普通队列参数的时候,可以先设置死信队列的路由key和交换机,让普通该队列处理不来的消息转到对应的死信队列上.
2)然后声明普通队列,普通交换机,死信队列,死信交换机.
3)之后消费普通队列消息

public class Consumer01 {
    //普通交换机的名称
    public static final String NORMAL_EXCHANGE="normal_exchange";
    //死信交换机的名称
    public static final String DEAD_EXCHANGE="dead_exchange";
    //普通队列的名称
    public static final String NORMAL_QUEUE="normal_queue";
    //死信队列的名称
    public static final String DEAD_QUEUE="dead_queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMQUtil.getChannel();

        //声明死信和普通交换机类型为direct类型
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(DEAD_EXCHANGE,BuiltinExchangeType.DIRECT);

        //声明普通队列
        Map<String,Object> arguments=new HashMap<>();
        arguments.put("x-dead-letter-exchange",DEAD_EXCHANGE);
        arguments.put("x-dead-letter-routing-key","lisi");
        channel.queueDeclare(NORMAL_QUEUE,false,false,false,arguments);

        //声明死信队列
        channel.queueDeclare(DEAD_QUEUE,false,false,false,null);

        //绑定普通的交换机与普通的队列
        channel.queueBind(NORMAL_QUEUE,NORMAL_EXCHANGE,"zhangsan");

        //绑定死信的交换机与死信的队列
        channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"lisi");

        //如果能成功接收到消息会调用的回调函数
        DeliverCallback deliverCallback=(consumerTag, message)->{
            System.out.println("Consumer01接收者接收到的消息:"+new String(message.getBody()));
        };

        //如果取消从消息队列中获取消息时会调用的回调函数
        CancelCallback cancelCallback= consumerTag->{
            System.out.println("消息消费被中断");
        };

        channel.basicConsume(NORMAL_QUEUE,true,deliverCallback,cancelCallback);
    }
}

死信消费者:
1)消费死信队列即可,消费过程和普通队列一样.

————————————————
版权声明本文为CSDN博主「杀手不太冷」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/qq_45950109/article/details/121292437

说一下消息确认机制和返回机制,有什么区别?

为了保证 RabbitMQ 中消息的可靠性投递以及消息在发生特定异常时的补偿策略,RabbitMQ诞生了消息确认和返回机制.

消息确认机制(也叫应答机制)

消息确认机制是保障消息与 RabbitMQ消息之间可靠传输消息一种保障机制
其主要内容就是用来监听RabbitMQ消息队列收到消息之后返回给生产端的ack确认消息
消息确认机制描述了一种消息是否已经被发送到 RabbitMQ消息队列中以及 RabbitMQ消息队列是否以及接收到生产端发送的消息。

消息确认机制的作用
监听生产者的消息是否已经发送到了 RabbitMQ消息队列中
如果消息没有被发送到 RabbitMQ消息队列中则消息确认机制不会给生产端返回任何确认应答也就是没有发送成功
相反如果消息被成功发送到了 RabbitMQ消息队列中则消息确认机制会给生产端返回一个确认应答
以通知生产者消息已经发送到了 RabbitMQ消息队列

消息返回机制

描述不可达的消息与生产者之间的一种保障策略
其主要是用来监听RabbitMQ消息队列中是否存在不可达的消息并根据监听结果返回给生产端的一种监听机制
消息返回机制描述了一种 RabbitMQ消息队列中的不可达消息与生产端的关系

什么是不可达的消息
消息在被成功发送到RabbitMQ消息队列中之后如果消息在经过当前配置的 exchangeName 或 routingKey 没有找到指定的交换机或没有匹配到对应的消息队列
那么这个消息就被称为不可达的消息如果此时配置了消息返回机制那么此时RabbitMQ消息队列会返回给生产者一个信号信号中包括消息不可达的原因以及消息本身的内容。

消息确认机制的作用
监听生产端发动到RabbitMQ消息队列中的消息是否可达
如果消息不可达则返回一个信号通知生产端相反如果消息可达则不会返回任何信号

channel.addReturnListener(new ReturnListener() {
    @Override
    public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("return relyCode: " + replyCode);    // 状态码
        System.out.println("return replyText: " + replyText);   // 结果信息
        System.out.println("return exchange: " + exchange);
        System.out.println("return routingKey: " + routingKey);
        System.out.println("return properties: " + properties);
        System.out.println("return body: " + new String(body));

    }
});
————————————————
版权声明本文为CSDN博主「b15735105314」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/b15735105314/article/details/114810261

————————————————
版权声明本文为CSDN博主「一江溪水」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
原文链接https://blog.csdn.net/upstream480/article/details/119325064

让你来设计一个消息队列你会怎么设计

比如说这个消息队列系统我们从以下几个角度来考虑一下
首先这个 mq 得支持可伸缩性吧就是需要的时候快速扩容就可以增加吞吐量和容量那怎么
搞设计个分布式的系统呗参照一下 kafka 的设计理念broker -> topic -> partition每个
partition 放一个机器就存一部分数据。如果现在资源不够了简单啊给 topic 增加 partition
然后做数据迁移增加机器不就可以存放更多数据提供更高的吞吐量了
其次你得考虑一下这个 mq 的数据要不要落地磁盘吧那肯定要了落磁盘才能保证别进程挂了数
据就丢了。那落磁盘的时候怎么落啊顺序写这样就没有磁盘随机读写的寻址开销磁盘顺序读
写的性能是很高的这就是 kafka 的思路。
其次你考虑一下你的 mq 的可用性啊这个事儿具体参考之前可用性那个环节讲解的 kafka 的高
可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。
能不能支持数据 0 丢失啊可以的参考我们之前说的那个 kafka 数据零丢失方案。
————————————————
版权声明本文来自小安资料,好像是图灵学院的。

SpringBoot如何整合Rabbitmq

这种低级的题目在工作了几年的程序员估计闻不到,但是想我们这种刚出来的小白估计会问到

  1. 导入spring-boot-starter-amqp的包
  2. 编写config配置类,配置相关交换机,队列,绑定键
  3. 利用@RabbitListener(要绑定的队列)+ @RabbitHandler 比如前一个注解标注在类上,后一个注解标注在方法上,用来监听某一个队列后,一旦队列有消息就做出相应操作
  4. 注入RabbitmqTemplate组件,然后利用相应的api进行发送消息,比如convertAndSend方法
  5. 在处理订单超时这种情况便是如上方案: 先配置好队列的过期时间,一旦生成订单的消息在消息队列里没有被消费,那么这个时候就会被放入到死信队列里面,这个时候,我们就可以监听这个死信队列,一旦死信队列里面产生了消息,就执行dao的方法将相应的订单消息删除.
  6. 其次,如果你想保证消息的可靠性传输,可以设置应答机制和返回机制,利用rabbtemplate里的setConfirmCallback和setReturnCallback方法,前者是在消息成功到达之后会返回一个回调,后者是消息没有成功到达会返回一个回调,最后利用@PostConstruct让这两个机制发生在容器初始化的时候被调用就可以了.
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: RabbitMQ