RabbitMQ 相关问题如何解决
MQ 是什么?
MQ(Message Queue)消息队列
用队列机制来实现软件之间的通信,消费者可以到指定队列拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息
什么是队列?
是一种数据结构,遵循 FIFO (先进先出)原则
凭啥要使用 MQ , MQ 有啥优势?
- 异步通信
将以前也不中不必要的同步操作,优化成异步操作,提高性能
- 业务解耦
将原有A模块直接调用B模块的接口,优化成,A模块的请求给到MQ,A模块的事情就做完了
MQ会主动推给B模块,或者B模块自己来拉
- 流量削峰
当某一时间大量的流量打到服务器上,服务器一时间无法承受,会宕机
这个时候,若请求都是从消息队列里面出来,则能够保证这种大流量的情况下,服务器仍然能够有序的稳定的处理请求
MQ 有啥劣势呢?
- 系统可用性降低,对外部有依赖了
- 需要考虑 MQ 消息丢失,重复消费的问题
- 需要花费精力保证消息的顺序性,一致性
常用 MQ 性能对比
ActiveMQ | RabbitMQ | RocketMQ | Kafka | |
开发语言 | java | erlang | java | scala |
单机吞吐量 | 万级 | 万级 | 十万级 | 十万级 |
时效性 | ms级 | us级 | ms级 | ms级以内 |
可用性 | 高 主从架构 |
高 主从架构 |
非常高 分布式架构 |
非常高 分布式架构 |
消息可靠性 | 较低概率丢失消息 | 基本不丢 | 可以做到基本不丢 | 可以做到基本不丢 |
功能支持 | 支持功能全 | 性能好 延时低 并发能力强 |
MQ 功能较完善 支持分布式,扩展性好 |
主要用于大数据和日志采集 |
MQ 如何避免消息堆积
- 提高消费速率(集群的方式)
- 消费者批量获取消息进行消费
MQ 如何避免消费者重复消费(幂等性问题)
- 全局ID(增加标志位) + 保证业务一致性
MQ 如何保证消息不丢失
- 消息确认机制
- 持久化
- 消息 ACK
MQ 如何保证消息顺序一致性
- 绑定同一个消费者和队列
MQ 推与拉取架构模型是怎么样的?
- MQ 服务器与消费者建立长连接后,MQ 服务器会主动推数据给到消费者
- 当消费者第一次启动的时候,会去找MQ 服务器拉数据
mq有哪些消费模式
- 推模式 注册一个消费者后,RabbitMQ会在消息可用时,自动将消息进行推送给消费者。这种方式效率最高最及时。
- 拉模式 属于一种轮询模型,发送一次get请求,获得一个消息。如果此时RabbitMQ中没有消息,会获得一个表示空的回复。
- 自动确认
消费者消费消息的时候,将自动向RabbitMQ进行确认。
- 手动确认
消费者消费消息的时候,手动调用相应函数进行ack 应答
- qos预取模式
在确认消息被接收之前,消费者可以预先要求接收一定数量的消息,在处理完一定数量的消息后,批量进行确认
当然,如果消费者应用程序在确认消息之前崩溃,则所有未确认的消息将被重新发送给其他消费者
RabbitMQ
中既然有了connections
为什么还要有 channel
?
connection 是什么
connection 是 生产者或消费者与 RabbitMQ Broker 建立的连接,是一个TCP连接
一旦 TCP 连接建立起来,客户端紧接着可以创建一个 AMQP 信道(Channel),每个信道都会被指派一个唯一的 ID
信道是建立在 Connection 之上的虚拟连接,多个信道复用一个TCP连接,可以减少性能开销,同时也便于管理
因为一个应用需要向RabbitMQ 中生成或者消费消息的话,都要建一个TCP连接,TCP连接开销非常大,如果遇到使用高峰,性能瓶颈也随之显现
信道复用连接优势:
- 复用TCP连接,减少性能开销,便于管理
- RabbitMQ 保障每一个信道的私密性
当每个信道的流量不是很大时,复用单一的 Connection 可以在产生性能瓶颈的情况下有效地节省 TCP 连接资源
信道本身的流量很大时,这时候多个信道复用一个 Connection 就会产生性能瓶颈,进而使整体的流量被限制了,此时就需要开辟多个 Connection,将这些信道均摊到这些 Connection 中
RabbitMQ
的作用
- 削峰填谷
- 生产者和消费者业务解耦
- 服务间异步通信
- 定时任务
- 顺序消费
为什么选择 RabbitMQ
现在的市面上有很多 MQ 可以选择,比如 ActiveMQ、ZeroMQ、Appche Qpid为什么要选择 RabbitMQ?
- 除了 Qpid,RabbitMQ 是唯一一个实现了 AMQP 标准的消息服务器
- 可靠性,RabbitMQ 的持久化支持,保证了消息的稳定性
- 高并发,RabbitMQ 使用了 Erlang 开发语言,Erlang 是为电话交换机开发的语言,天生自带高并发光环,和高可用特性
- 集群部署简单,正是应为 Erlang 使得 RabbitMQ 集群部署变的超级简单
- 社区活跃度高,根据网上资料来看,RabbitMQ 也是首选
RabbitMQ 的特点是什么?
- 可靠
RabbitMQ 使用 如持久化、传输确认及发布确认等机制来保证可靠性
- 灵活的路由
通过交换器来路由消息
对于典型的路由功能, RabbitMQ 己经提供了一些内置的交换器来实现
针对更复杂的路由功能,可以将多个 交换器绑定在一起,这个就需要通过插件来实现了
- 扩展性
多个 RabbitMQ 节点可以组成一个集群,也可以根据实际业务情况动态地扩展集群中节点
- 高可用性
队列可以在集群中的机器上设置镜像,使得在部分节点出现问题的情况下队列仍然可用
- 支持的协议多
RabbitMQ 除了原生支持 AMQP 协议,还支持 STOMP, MQTT等多种消息中间件协议
- 多语言客户端
RabbitMQ 几乎支持所有常用语言,比如 GO、 Java、 Python、 Ruby、 PHP等
- WEB 管理界面
RabbitMQ 提供了一个易用的用户界面,使得用户可以监控和管理消息、集群中的节点等
- 命令插件机制
RabbitMQ 提供了许多插件 , 以实现从多方面进行扩展,当然也可以编写自己的插件
生产者Producer和消费者Consumer 有哪些知识点?
生产者
- 消息生产者,投递消息
- 消息一般包含两个部分:消息体(
payload
)和标签(Label
)
消费者
- 消费消息,接收消息
- 消费者连接到 RabbitMQ 服务器,并订阅到队列
消费消息时只消费消息体,丢弃标签
RabbitMQ 消息持久化中的坑
默认情况下重启服务器会导致消息丢失,我们如何保证重启 RabbitMQ 不丢失数据?
那就是做持久化,持久化需要满足如下三个条件才可以恢复 RabbitMQ 的数据
- 投递消息的时候 durable 设置为 true,消息持久化
- 消息已经到达持久化交换器上
- 消息已经到达持久化的队列上
持久化的工作原理
Rabbit 会将持久化消息写入磁盘上的持久化日志文件,等消息被消费之后,Rabbit 会把这条消息标识为等待垃圾回收
持久化的优缺点
优点
- 数据持久化,数据不丢失
缺点
- 对性能有影响,写硬盘比写内存性能低,从而降低服务的吞吐量
RabbitMQ ACK 应答机制
ACK 应答分为手动和自动,各有优劣
- 如果消息不太重要,丢失也没有影响,那么自动 ACK 会比较方便
- 如果消息非常重要,不容丢失。那么最好在消费完成后手动 ACK
否则接收消息后就自动 ACK,RabbitMQ 就会把消息从队列中删除。若此时消费者宕机或处理业务失败,那么消息就丢失了
ACK 机制的开发注意事项
如果忘记了 ACK,那么后果很严重
当 Consumer 退出时候,Message 会一直重新分发。然后 RabbitMQ 会占用越来越多的内容,由于 RabbitMQ 会长时间运行,这个” 内存泄漏” 是致命的
为什么需要限流,消费者流量控制
- 某一时刻,生产者在 RabbitMQ 队列中堆积了很多消息,此时有一个消费者启动,大量的消息会推送到消费者上面,这种瞬时大流量会把消费者打挂
- 生产者和消费者效率不平衡的情况,会导致消费者端性能下降,服务端卡顿或者崩溃
RabbitMQ 的组成
- 生产者 producer
- 消费者 consumer
- 交换机 exchange
用于接受、分配消息
- 消息 message
- 队列 queue
用于存储生产者的消息
- 信道 channel AMQP
消息推送使用的通道
- 连接 connections
生成者或者消费者与Rabbit 建立的TCP 连接
- 路由键 routingKey
用于把生成者的数据分配到交换器上
- 绑定键 BindingKey
用于把交换器的消息绑定到队列上
- 连接管理器 ConnectionFactory
应用程序与 Rabbit 之间建立连接的管理器,程序代码中使用
- VHost
vhost 可以理解为虚拟 broker,即虚拟机
其内部均含有独立的 queue、exchange 和 binding 等
拥有独立的权限系统,做到资源隔离,资源高效利用
RabbitMQ 的六种模式
- single
简单的生产者生产消息,放入队列,消费者消费消息
- work
当生产者生产消息的速度大于消费者消费的速度,就要考虑用 work 工作模式,这样能提高处理速度提高负载
work 模式与 single 模式类似, 只是work 模式比 single 模式多了一些消费者
- publish
应用场景:简单消息队列的使用,一个生产者一个消费者
- routing
消息生产者将消息发送给交换机按照路由判断,路由是字符串(info) 当前产生的消息携带路由字符(对象的方法),交换机根据路由的key
只能匹配上路由key对应的消息队列,对应的消费者才能消费消息
- topic
话题模式,一个消息被多个消费者获取,消息的目标 queue 可用 BindingKey 以通配符
- rpc
通过远程过程调用的方式实现
存储机制
- 持久化消息
持久化的消息在到达队列时就被写入磁盘,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除
- 非持久化消息
一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间
RabbitMQ中消息可能有的几种状态
- alpha
消息内容(包括消息体、属性和 headers) 和消息索引都存储在内存中
- beta
消息内容保存在磁盘中,消息索引保存在内存中
- gamma
消息内容保存在磁盘中,消息索引在磁盘和内存中都有
- delta
消息内容和索引都在磁盘中
RabbitMQ 的队列结构?
- rabbit_amqqueue_process
负责协议相关的消息处理,即接收生产者发布的消息、向消费者交付消息、处理消息的确认等
- backing_queue
是消息存储的具体形式和引擎,并向 rabbit_amqqueue_process 提供相关的接口以供调用
交换器无法根据自身类型和路由键找到符合条件队列时,会如何处理?
我们对交换机设置参数的时候,有一个标志叫做 mandatory
- 当mandatory标志位设置为true时
如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,那么broker就会调用basic.return方法将消息返还给生产者
- 当mandatory设置为false时
前置条件和上述保持一致,此时 broker会直接将消息丢弃
如何保证消息可靠性嘞?
- 消息从生产者到 MQ
由事务机制,确认机制 来保障
- MQ 自身可靠性
由持久化、集群、普通模式、镜像模式来保证
- MQ 消息到消费者
由basicAck机制、死信队列、消息补偿等机制来保证
集群中的节点类型有哪些?
- 内存节点
ram,将变更写入内存。
- 磁盘节点
disc,磁盘写入操作
RabbitMQ中 要求最少有一个磁盘节点
如何保证 RabbitMQ 消息队列的高可用?
RabbitMQ中有三种模式来保证:
- 单机模式
一般是本地启动,自己学习和测试使用,不会用在生产环境上
- 普通集群模式
在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个
- 镜像集群模式
RabbitMQ的高可用模式
跟普通集群模式不一样的是,创建的 queue,无论元数据(元数据指 RabbitMQ 的配置数据)还是 queue 里的消息都会存在于多个实例上,
然后每次写消息到 queue 的时候,都会自动把消息到多个实例的 queue 里进行消息同步
参考资料:
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~