消息队列中间件(RabbitMQ)
说明
这篇文章是自己 Rabbitmq 的入门学习的记录。
预备知识
栈(Stack)
是只允许在一端进行插入或删除的线性表。栈又称为后进先出(Last In First Out)的线性表。
队列(Queue)
记住,FIFO 先入先出就好了。
服务端雪崩
服务的雪崩效应是一种因服务提供者不可用导致服务调用者不可用,并将不可用逐渐放大的过程。
微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况。
限流 是对服务的保护,避免因瞬间高并发流量而导致服务故障,进而避免雪崩。是一种 预防 措施。
超时处理、线程隔离、降级熔断 是在部分服务故障时,将故障控制在一定范围,避免雪崩。是一种 补救 措施。
消息中间件
简介
消息本质上是一种特定结构的数据(对象也可以看做是一种特殊的消息),它包含消费者与服务双方都能识别的数据,这些数据需要在不同的进程(机器/系统)之间进行传递,并可能会被多个完全不同的客户端消费。
消息中间件的作用就是,帮助应用开发者在他们应用的分布式组件上自由的传递数据、通知消息,构建松耦合系统(消息的发送者无需知道消息使用者的存在,反之亦然)。对系统最直接的影响就是提升系统性能、系统间解耦、大流量削峰等。
消息中间件(MQ)其实就是一个开发好的系统,可以被独立部署。业务系统通过它来发消息和收消息,以达到异步调用的效果。
消息中间件可以被看作一个用来暂时存储数据的容器,它还是平衡低速系统和高速系统处理任务时间差的工具(限流,流量削峰)。
同步与异步
不同系统之间的交互方式有同步方式,也有异步方式。对于不需要及时响应结果的交互,一般都采用异步方式,否则采用同步方式。
- 同步:在发出一个调用后没有得到结果之前,该调用不返回,即调用者主动等待这个调用的结果。
- 异步:与同步相反,在调用发出后直接返回结果,即在一个异步调用发出后,调用者立即返回去做其他事情。在调用结果发出之后,被调用者通过
状态
、通知
、回调
这三种方式,通知调用者。使用哪一种方式依赖于被调用者的业务实现,一般不受调用者控制。- 如果被调用者使用
状态
来通知,那么调用这个需要每隔一定时间检查一次,效率很低。 - 如果被调用者使用
通知
或者回调
来通知,这效率很高,因为被调名者几乎不需要做额外的工作。
- 如果被调用者使用
回调通知的方式,往往是被调用方定义输入参数(消息格式),调用方提供回调方法或回调URL地址即可(一遍完成时被通知到即被调用)。
提升系统性能
对于一个业务功能,需要多个逻辑或步骤依次处理,比如步骤abcd来处理。若步骤A和B供耗时40毫秒,C和D分别耗时120毫秒,则完成这个功能共需要40+280=320毫秒。
如果引入中间件,在前两步骤处理完后的消息放入MQ,然后直接返回给用户,AB也不用关系后续两个步骤何时去处理(达到异步的效果),那么用户感知到的响应时间就是40毫秒,提升了性能。
通常就是一个用户操作(比如下单),只对重要的步骤同步操作,然后直接返回成功,同时将消息放入MQ,其它次要处理通过MQ的推送来进行后续处理。以此达到提升响应速度的目的。
系统间解耦
还是上面那ABCD的处理,假如ABCD是分别在四个系统中处理,那么AB处理完后,CD如何处理消息,完全不影响AB系统,即使CD宕机。他们都是只关心消息中间件,所以达到应用间解耦的效果,且彼此互不影响。
还有比如一核心系统的数据,在其它相关系统要用到,那核心系统每增加一个数据,以往来说,都要通过编码的方式给各相关系统通知(或子系统轮询核心系统接口获取数据),每新增一个相关系统,可能核心系统都要修改逻辑重新部署发布。
引入消息中间件,就能解决上述问题,其实就是发布订阅模式。核心系统往消息中间件发布消息(数据)、消息中间件往相关系统推送消息,当然,相关系统只需订阅相关消息即可。
基于消息的分布式架构
基于消息的分布式架构总是围绕着消息来做文章。例如可以将消息封装为对象,或者指定消息的规范例如SOAP,或者对实体对象的序列化与反序列化。这些方式的目的只有一个,就是将消息设计为生产者和消费者都能够明白的数据格式,并能通过消息通道进行传递。
大流量削峰
现在假设公司在做大型促销活动,在线系统A面临超过1万的QPS。而后端数据系统B比每秒只能处理5000左右的并发流量。这时如果将并发流量全部发送到b系统,则它很可能会宕机,促销活动会失败。可以引入MQ,将超过1万的并发流量先打到MQ中,然后B系统按照其每秒5000左右的处理能力,从mq中获取消息,这样就实现了大流量削峰。
再举个例子,如果订单系统最多能处理一万次订单,这个处理能力应付正常时段的下单时绰绰有余,正常时段我们下单一秒后就能返回结果。但是在高峰期,如果有两万次下单操作系统是处理不了的,只能限制订单超过一万后不允许用户下单。若使用消息队列做缓冲,我们可以取消这个限制,把短时间内大量的下单请求先放到消息中间件,然后按系统能力逐个消费这些消息即可,这时有些用户可能在下单十几秒后才能收到下单成功的操作,但是比不能下单的体验要好。
简单来说: 就是在访问量剧增的情况下,但是应用仍然不能停,比如“双十一”下单的人多,但是淘宝这个应用仍然要运行,所以就可以使用消息中间件采用队列的形式减少突然访问的压力。又比如在某些电商平台的一些秒杀活动中,合理使用消息队列可以抵御活动刚开始大量请求涌入对系统的冲击。
目前主流的消息中间件产品有四种
ActiveMQ:
一款比较早的Apache产品,完全支持JMS规范,API丰富,但是性能太低,适用于中小企业,对并发性能没有过多要求。
Kafka:
一款分布式发布-订阅消息中间件,追求高吞吐量,性能很高缺点是有可能丢失数据,对事务支持也不好。一般用于做用户行为日志收集。
RocketMQ:
一款阿里的开源消息中间件,Java语言开发,对于高并发、高可用、消息传递的可靠性、事务等都做了优化,而且性能很好。但是商业版部分功能是收费的,另外文档不是很详细。适合公司是Java技术栈,且有特别大的秒杀活动需求场景。
RabbitMQ:
一款完全开源免费的基于ErLang语言编写的软件,依赖AMQP协议,而且功能和性能都很不错,适用于各种规模企业,多种业务场景的使用。
性能比较
Kafka ≈ RocketMQ > RabbitMQ > ActiveMQ
引入消息中间件需注意的问题
需要保证消息中间件的高可用
不能消息中间件服务挂掉了,导致整个应用挂掉了。主要是靠集群部署,而不是单一节点。集群还能更好的避免数据大量丢失。
注意rabbitmq集群,是主从模式,保证了一个节点挂掉,不会让系统崩掉,因为新入一个消息会同步到其它节点,因此其它节点仍有一样的数据,但整体来看,数据并不是分布式存储的,所以扩展性不是最佳。
kafka倒是分布式存储的,保证高可用性,和扩展性。
需要保证消息不被重复消费
通常都是从业务角度出发,只要保证即使消费者重复消费了信息,重复消费的最终结果只和消费一次的结果是一样的即可。
消息生成过程中的幂等性
消息中间件服务端可以这样做。给每个生产者定义一个唯一的ID。给生产的每一条消息定义一个唯一的ID。消息中间键服务端在存储消息时存储生产者的ID和最后一条消息ID的映射。嗯如果新过来的消息的消息ID和记录中的最新的ID不一样,就插入消息,否则视为重复发送消息不误插入。//这个如何做?在消息生产者里写?貌似不行,但要是在中间件server中实现,那要改源码吗??
消费过程中的密等性
- 消息有唯一ID,每次消费处理后记录,在处理新消息时,先检查该ID是否处理过。
- 使用乐观锁,即给数据加版本号字段,版本号不一致停止处理。
- SQL数据库插入数据,可借助唯一键约束。
不能要求所有的业务处理逻辑都支持幂等性,这样会给开发和运维带来额外的负担。
需要保证消息的顺序性
这个有需要的话,总归有解决的办法,具体情况具体分析吧
需要解决消息中间件中的消息延迟
即后入的消息迟迟没有被消费,可能引起用户体验不好。
主要消费端要下功夫,提升消息处理能力:
- 优化消费代码以提升性能。
- 增加消费者数量。
MQ综述
- 消息中间件,就是个数据的中转仓、托管所,提供消息托管和转发功能。
- 消息中间件,很少单节点部署,通常多节点集群部署,达到高可用、高性能的目的。
- 系统引入MQ后,对系统最直接的影响就是提升系统性能、系统间解耦、大流量削峰等。
RabbitMQ 介绍
简介
RabbitMQ 是一个需独立部署的软件程序或者说服务,是个开源的消息中间件。根据操作系统选择相应的版本进行安装启动即可。
RabbitMQ是使用Erlang
语言来编写的,并且基于高级消息队列协议(AMQP
)的、开源的消息中间件。Erlang语言在数据交互方面性能优秀,Erlang对并发处理有着天生优势,有着和原生Socket一样的延迟,这也是RabbitMQ高性能的原因所在。可谓“人如其名”,RabbitMQ像兔子一样迅速。
RabbitMQ可以非常容易地部署到 Windows、Linux 等操作系统下,同时,它也可以很好地部署到服务器集群中。它的队列容量是没有限制的(取决于安装RabbitMQ的磁盘容量),发送与接收信息的性能表现也非常好。RabbitMQ提供了Java、.NET、Erlang以及C语言的客户端API,调用非常简单,并且不会给整个系统引入太多第三方库的依赖。
RabbitMQ基础架构如下图(这个图很重要,需要刻在脑子里):
核心角色:生产者、消费者、消息服务器
-
生产者:负责创建和推送消息到消息服务器的程序是生产者。
-
消息服务器:其实RabbitMQ本身,不会去产生和消费消息,相当于一个中转站,将生产者的消息路由(推送)给消费者。
交换机(exchange):交换机是 RabbitMQ 非常重要的一个部件,一方面它接收来自生产者的消息,另一方面它将消息推送到队列中。交换机必须确切知道如何处理它接收到的消息,是将这些消息推送到特定队列还是推送到多个队列,亦或者是把消息丢弃,这个得有
交换机类型
决定。队列(queue):队列是 RabbitMQ 内部使用的一种数据结构,尽管消息流经 RabbitMQ 和应用程序,但它们只能存储在队列中。队列仅受主机的内存和磁盘限制的约束,本质上是一个大的消息缓冲区。许多生产者可以将消息发送到一个队列,许多消费者可以尝试从一个队列接收数据。这就是我们使用队列的方式。
-
消费者:消费与接收具有相似的含义。消费者大多时候是一个等待接收消息的程序。
请注意生产者、消费者和消息中间件很多时候并不在同一机器上。另外,同一个应用程序既可以是生产者又是可以是消费者。
AMQP协议和RabbitMQ
提到RabbitMQ,就不得不提AMQP协议
。AMQP协议是具有现代特征的二进制协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。
重要概念
先了解一下AMQP协议中间的几个重要概念:
Server
:服务器,接收客户端(消息生产者或消费者)的连接,实现AMQP实体服务,又叫broker
。Connection
:连接,应用程序与Server的网络连接,TCP连接。Channel
:信道,消息读写等操作在信道中进行。客户端可以建立多个信道,每个信道代表一个会话任务。Message
:消息,应用程序和服务器之间传送的数据,消息可以非常简单,也可以很复杂。有Properties
和Body
组成。Properties为外包装,可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body就是消息体内容。Virtual Host
:虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange
和Queue
,同一个虚拟主机里面不能有相同名称的Exchange或Queue。Exchange
:交换器,接收消息并按照路由规则将消息路由到一个或者多个队列。如果路由不到,或者返回给生产者,或者直接丢弃。RabbitMQ常用的交换器常用类型有direct、topic、fanout、headers
四种(后面详细介绍)。Binding
:绑定,交换器和消息队列之间的虚拟连接,绑定中可以包含一个或者多个RoutingKey
。RoutingKey
:路由键,生产者将消息发送给交换器的时候,会发送一个RoutingKey,用来指定路由规则,这样交换器就知道把消息发送到哪个队列。路由键通常为一个“.”分割的字符串,例如“com.rabbitmq”。Queue
:消息队列,用来保存消息,供消费者消费。先加入的先被消费。
我们完全可以直接使用 Connection 就能完成信道的工作,为什么还要引入信道呢? 试想这样一个场景, 一个应用程序中有很多个线程需要从 RabbitMQ 中消费消息,或者生产消息,那么必然需要建立很多个 Connection,也就是许多个 TCP 连接。然而对于操作系统而言,建立和销毁 TCP 连接是非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。 RabbitMQ 采用 TCP 连接复用的方式,不仅可以减少性能开销,同时也便于管理 。
重要过程
生产者是投递消息的一方,首先连接到Server,建立一个连接,开启一个信道;然后生产者声明交换器和队列,设置相关属性,并通过路由键将交换器和队列进行绑定。同理,消费者也需要进行建立连接,开启信道等操作,便于接收消息。(这段很重要,要刻在脑子里)
接着生产者就可以发送消息,发送到服务端中的虚拟主机,虚拟主机中的交换器根据路由键选择路由规则,然后发送到不同的消息队列中,这样订阅了消息队列的消费者就可以获取到消息,进行消费。
最后还要关闭信道和连接。
RabbitMQ是基于AMQP协议实现的,其结构如下图所示,和AMQP协议简直就是一模一样。
RabbitMQ常用的Exchange类型
Exchange的类型 ,决定了一个消息产生时,放入具体一个或多个队列的规则。
RabbitMQ常用的交换器类型有direct、topic、fanout、headers四种。
有一个可自定义的字符串,这里叫做RoutingKey,用于标识一个或多个具体的队列。
Exchange 类型是在,生产者或消费者建立消息通道(channel)时用到的,需指定交换机名称和类型等信息。
Direct Exchange 【定向模式】
该类型的交换器将所有发送到该交换器的消息转发到RoutingKey指定的队列中。
Topic Exchange 【通配符模式】
Topics模式中支持两种通配符 * 代表1个字符 # 代表0个或多个字符 例如 路由Key定义为 *.Dog.* ,那么我们发送消息时中间为Dog且前后均为一个字符的路由key都可以匹配到该通配符,例如:C.Dog.D 【注意要带上 . 】 路由Key定义为 #.Dog ,那么发送消息时以Dog结尾的路由Key都可以匹配到该通配符,例如 chenwolong.Dog【注意要带上 . 】 路由Key定义为 Dog.# ,那么发送消息时以Dog开头的路由Key都可以匹配到该通配符 ,例如 Dog.Chenwolong【注意要带上 . 】 路由Key定义为 #.# ,那么 Dog.Cat,Cat.Dog . 等都可以匹配
Fanout Exchange 【广播模式】
只需在队列绑定交换机时,对不同队列指定相同的RoutingKey即可。
该类型不处理路由键,会把所有发送到交换器的消息路由到所有绑定的队列中。优点是转发消息最快,性能最好。
Headers Exchange 【参数匹配模式】
该类型的交换器不依赖路由规则来路由消息,而是根据消息内容中的headers属性进行匹配。headers类型交换器性能差,在实际中并不常用。
消息确认
1对1的简单生产消费模式中,当消费者有多个时,那么mq消息的转发策略是这样的。
默认情况下,RabbitMQ会顺序的将message发给下一个消费者。每个消费者会得到平均数量的message。这种方式称之为round-robin(轮询).
但是很多情况下并不希望消息平均分配,而是要消费快的多消费,消费少的少消费。还有很多情况下一旦其中一个宕机,那么其它接收者就无法接收原本这个接收者所要接收的数据。
为了保证消息从队列可靠地到达消费者,RabbitMQ提供了消息确认机制。
Rabbit中存在两种消息确认模式
- 自动模式 - 只要消息从队列获取,无论消费者获取到消息后是否成功消费,都认为是消息成功消费.
- 手动模式 - 消费从队列中获取消息后,服务器会将该消息设置为不可用状态,等待消费者反馈。如果消费者在消费过程中出现异常,没有发送应答,那么RabbitMQ会将这个消息重新投递。
消费者订阅队列的时候,可以指定autoAck
参数,当autoAck为true的时候,RabbitMQ采用自动确认模式,即RabbitMQ自动把发送出去的消息设置为确认,然后从内存或者硬盘中删除,而不管消费者是否真正消费到了这些消息。当autoAck为false的时候,RabbitMQ会等待消费者回复的确认信号,收到确认信号之后才从内存或者磁盘中删除消息。
消息确认机制是RabbitMQ消息可靠性投递的基础,只要设置autoAck参数为false,消费者就有足够的时间处理消息,不用担心处理消息的过程中消费者进程挂掉后消息丢失的问题。
NetCore RabbitMQ 的消息确认机制 - 天才卧龙 - 博客园 (cnblogs.com)
持久化
持久化可以防止在异常情况下丢失数据。
消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢?答案就是消息持久化。RabbitMQ的持久化分为三个部分:交换器持久化、队列持久化和消息的持久化。
把exchange和queue的durable
属性设置为true,重启rabbitmq服务时( 重启命令:rabbitmqctl stop_app
、rabbitmqctl start_app
),exchange和queue也会恢复。我们需要注意的是:如果queue设置durable=true,rabbitmq服务重启后队列虽然会存在,但是队列内的消息会丢全部丢失。那么怎么实现消息的持久化呢?实现的方法很简单:将exchange和queue都设置durable=true,然后在消息发布的时候设置persistent=true即可。
当然,也可以将所有的消息都设置为持久化,但是这样做会影响RabbitMQ的性能,因为磁盘的写入速度比内存的写入要慢得多。对于可靠性不是那么高的消息可以不采用持久化处理以提高整体的吞吐量。鱼和熊掌不可兼得,关键在于选择和取舍。在实际中,需要根据实际情况在可靠性和吞吐量之间做一个权衡。
具体编程如何做,参考:NetCore RabbitMQ高级特性 持久化 及 消息优先级 - 天才卧龙 - 博客园 (cnblogs.com)
过期时间(TTL)
Time To Live,也就是生存时间,是一条消息在队列中的最大存活时间,单位是毫秒。了解Redis的朋友应该一看就明白,二者很像。RabbitMQ可以对消息和队列设置TTL。
RabbitMQ支持设置消息的过期时间,在消息发送的时候可以进行指定,每条消息的过期时间可以不同。
RabbitMQ支持设置队列的过期时间,从消息入队列开始计算,直到超过了队列的超时时间配置,那么消息会变成死信,自动清除。
如果两种方式一起使用,则过期时间以两者中较小的那个数值为准。
当然也可以不设置TTL,不设置表示消息不会过期;如果设置为0,则表示除非此时可以直接将消息投递到消费者,否则该消息将被立即丢弃。
死信队列、延迟队列、队列属性
延迟队列是指:消息进入队列后,不能被立即消费,在达到指定的时间后,方可被消费。
那么什么时候需要用延时队列呢?考虑一下以下场景:
- 订单在十分钟之内未支付则自动取消。
- 新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。
- 用户发起退款,如果24小时内没有得到处理则通知相关运营人员。
- 预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议。
延迟队列的使用场景都有一个特点,需要在某个事件发生之后或者之前的指定时间点完成某一项任务。
但是,RabbitMQ中并没有延迟队列的概念,那么我们怎么实现延迟队列呢?
实现延迟队列可采用:TTL+DLX 也就是消息生存周期+死信队列(后面有介绍)。
即:生产者代码实现将消息放入延迟队列,我们只需让消费者侦听死信队列即可。
先看个表格,该表格展示了队列的特性
名称 | 解释 | 值的单位 |
---|---|---|
x-expires | 队列的存活时间 | Number[毫秒] |
x-message-ttl | 消息的存活时间 | Number[毫秒] |
x-single-active-consumer | 表示队列是否是单一消费者 | Bool |
x-max-length | 队列可容纳的消息的最大条数 | Number【字节】 |
x-max-length-bytes | 队列可容纳的消息的最大字节数 | Number |
x-max-priority | 队列的优先级 | Number |
x-overflow | 队列中的消息溢出时,如何处理这些消息.要么丢弃队列头部的消息,要么拒绝接收后面生产者发送过来的所有消息. | String |
x-dead-letter-exchange | 溢出的消息需要发送到绑定该死信交换机的队列 | String |
x-dead-letter-routing-key | 溢出的消息需要发送到绑定该死信交换机,并且路由键匹配的队列 | String |
x-queue-mode | 默认懒人模式 lazy | String |
x-queue-version | 版本 | Number |
x-queue-master-locator | 集群相关设置,Master节点 | String |
消息存活时间(x-message-ttl) 和 队列过期时间(x-expires)
TTL 特性很好理解,是指队列中消息的存活周期,比如你可以设置队列中消息的存活周期为5分钟,5分钟内没有消费者进行消费,消息自动过期,被删除。
TTL是针对队列内的消息,到了设定的时间周期后,消息会被删除掉,队列依旧存在不受影响,如果使用(x-expires)设定周期,那么到达时间后,队列和里面的消息一起被删除。
何为死信队列?
是指当消息变成 dead message 后,可以被重新发送到另外一个交换机,这个交换机就是DLX死信队列(死信交换机)。消息在什么情况下变成Dead Message 呢?
- 原队列存在消息存活时间,当到达存活时间后未被消费,消息变成dead message。
- 队列消息长度达到最大限制。
- 消费者拒绝接收消息,basicNack,basicReject,并且不把消息放入原目标队列,requeue=false。
队列如何绑定死信交换机呢?
队列绑定死信交换机时,需要设置两个参数,x-dead-letter-exchange 、x-dead-letter-routing-key
x-dead-letter-exchange 对应的为死信交换机的名称
x-dead-letter-routing-key 对应的为死信交换机绑定队列的routingKey
死信交换机和普通的交换机没什么区别,只是叫法不同而已,也需要通过routingKey绑定队列。
具体编码怎么做,参考:
NetCore RabbitMQ 高级特性 消息存活周期TTL、死信交换机/死信对列DLX,延迟队列,及幂等性的保障 - 天才卧龙 - 博客园 (cnblogs.com)
一个扩展:
如果根据不同的延时时间设置不同的死信队列,可能数量上会无限增多,所以最好有个通用的死信队列能满足不同的延时信息的存放。//不同的延时信息还可能意味着不同的处理逻辑。待再细细思考下,也许这个问题或需求本身就有问题。
延时队列在需要延时处理的场景下非常有用,使用RabbitMQ来实现延时队列可以很好的利用RabbitMQ的特性,如:消息可靠发送、消息可靠投递、死信队列来保障消息至少被消费一次以及未被正确处理的消息不会被丢弃。另外,通过RabbitMQ集群的特性,可以很好的解决单点故障问题,不会因为单个节点挂掉导致延时队列不可用或者消息丢失。 当然,延时队列还有很多其它选择,比如利用Java的DelayQueu,利用Redis的zset,利用Quartz或者利用kafka的时间轮,这些方式各有特点,但就像炉石传说一般,这些知识就好比手里的卡牌,知道的越多,可以用的卡牌也就越多,遇到问题便能游刃有余,所以需要大量的知识储备和经验积累才能打造出更出色的卡牌组合,让自己解决问题的能力得到更好的提升。 但另一方面,随着时间的流逝和阅历的增长,越来越感觉到自己的能力有限,无法独自面对纷繁复杂且多变的业务需求,在很多方面需要其他人的协助才能很好的完成任务。也知道闻道有先后,术业有专攻,不会再狂妄自大,觉得自己能把所有事情都搞定,也将重心慢慢转移到研究如何有效的进行团队合作上来,我相信一个高度协调的团队永远比一个人战斗要更有价值。
安装RabbitMQ
到官网查看具体安装步骤和要求:https://www.rabbitmq.com/
Windows系统可以参考这边文章的下载安装步骤:https://blog.csdn.net/weixin_45905503/article/details/128620925
总之,需要先安装个Erlang,再安装RabbitMQ(注意与Erlang的版本对应关系),再安装RabbitMQ-Plugins,它相当于是一个管理界面,方便我们在浏览器界面查看RabbitMQ各个消息队列以及exchange的工作情况,最后我们就可以通过http://localhost:15672来访问web端的管理界面,输入用户名:guest,密码:guest(默认)就可以进入管理界面。
实际项目中引入MQ,通常要多个MQ服务集群部署。如果不做集群即单台MQ服务,则mq机器出了故障宕机了,那么mq消息就不能发送了,系统就崩溃了,所以我们需要集群MQ,当其中一台MQ出了故障,其余的MQ机器可以接着继续运转,在生产中,没人使用单机的消息队列。如果有,那肯定为了用而用(显得技术复杂一下,好忽悠多收点钱)。
ASP.NET Core 中使用RabbitMQ
编程使用过程概述
生产者是投递消息的一方,首先连接到Server,建立一个连接,开启一个信道;然后生产者声明交换器和队列,设置相关属性,并通过路由键将交换器和队列进行绑定。同理,消费者也需要进行建立连接,开启信道等操作,便于接收消息。(这段很重要,要刻在脑子里)
接着生产者就可以发送消息,发送到服务端中的虚拟主机,虚拟主机中的交换器根据路由键选择路由规则,然后发送到不同的消息队列中,这样订阅了消息队列的消费者就可以获取到消息,进行消费。
最后还要关闭信道和连接。
Q&A
安装RabbitMQ-Plugins后,可以通过浏览器查看管理消息,那么账号密码怎么更改??
??
guest只能登入localoal,远程ip,需要创建admin用户,用admin用户登入。??
??是这样吗?待确定。
消息的优先级??Rabbitmq有这个概念??
队列声明时,可以指定该队列是否可以被多个消费者同时消费,那么mq是怎么知道所有的消费者都已经消费完的了。因为消费者的数量可能随时增加呀??你不知道自己将被多少个消费者消费。
??
假如消息队列服务器全崩了,或者重启了,此时生产者和消费者程序都一直正常运行,那么消息队列服务死掉的这期间,生产者和消费者都还正常吗?mq恢复后,假设消息不丢失,客户端都还能正常接收消息吗?
一个rabbitmq server可以设置多个死信队列吗?
可以的。
自己系统的消息队列服务器,要对第三方系统公开个账号以便它去消费某些消息吗?如果公开了,他破坏队列比如新建或修改和生产者相同的队列咋办??
??
参考资料
RabbitMQ-概述 - 简书 (jianshu.com)
为什么会需要消息队列(MQ)? - xuyatao - 博客园 (cnblogs.com)
RabbitMQ(一):RabbitMQ快速入门 - James_Shangguan - 博客园 (cnblogs.com)
NetCore RabbitMQ 简介及兔子生产者、消费者 【简单模式,work工作模式,竞争消费】 - 天才卧龙 - 博客园 (cnblogs.com)
《高并发系统实战派》、《分布式架构原理与实战》
更新于:2023.5.24
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示