RabbitMQ
2021-06-29 15:47:58 4 举报
AI智能生成
RabbitMQ
作者其他创作
大纲/内容
持久化机制
不管是否持久化,都可以被写入磁盘
需要持久化的,会被保存到队列里,并且保存到内存,最后会被刷盘
不需要持久化的,会保存到内存,等内存到达阈值时,会被刷入磁盘
队列持久化
消息持久化
交换机持久化
内存控制
当内存使用超过配置的阈值或高于配置的阈值,会阻塞客户端连接,并停止接收从客户端,以免服务器崩溃
内存阈值为40%,超过阈值会产生警告并阻塞所有生产者连接
相对值设置,建议取值在40%~66% 不建议超过70%
绝对值,单位为KB、MB、GB
内存换页
将队列中的消息,持久化到磁盘空间,达到释放内存空间,无论是否持久化,都会被存储到磁盘,持久化的消息会从内存中清除
默认在内存达到内存阈值的50%会进行换页操作
内存阈值40% * 换页阈值50% = 20%时会进行换页
内存8G 内存阈值3.2G,换页阈值50%,当有1.6G时会进行换页
可以进行修改,修改大于1时禁用换页功能
磁盘控制
当磁盘剩余空间低于确定的阈值,同样会阻塞生产者,避免服务器崩溃
默认阈值50MB剩余空间,磁盘空间低于50MB会阻塞
建议将磁盘阈值设置为操作系统的内存大小,例如内存为16G 磁盘阈值也设置为16G
高可靠
消息丢了,消息重复怎么办?
鱼和熊掌不可兼得,效率与可靠性不可兼得
消息丢失
1、发送者发送时丢失
2、从交换机路由到队列丢失
3、消息队列的存储丢失
4、消费者订阅队列消费丢失
1、发送者发送时丢失
服务端提供两种确认机制
Transaction(事务)模式
将channel设置成事务模式,需要手动提交事务或回滚
优点:可以解决生产者和服务端确认的问题
缺点:事务模式是阻塞的,消息没发送完毕需要阻塞,会榨干MQ服务器性能
结论:交互太多浪费性能,不推荐使用
Confirm(确认)模式
将channel设置成Confirm模式,本质上是MQ服务端收到ACK应答
普通确认模式
发送一条,确认一条
缺点:效率太低
批量确认模式
多次发送,确认一次
优点:效率高
缺点:发送1000条,第999条失败,又要重新发送
异步确认模式
一边发送,一边确认
需要添加一个监听器,服务器会分批确认,还需要Sortedset维护标识,已确认的移除,留下的是未确认的
推荐使用
2、从交换机路由到队列丢失
routingkey错误,或者队列不存在会丢失消息
使用回发监听器,回发给生产者
指定交换机的备份交换机
3、消息队列的存储丢失
把消息本身和元数据(队列,交换机,绑定关系)都保存到磁盘
队列持久化
交换机持久化
消息持久化
做集群
4、消费者订阅队列消费丢失
消费者接收到消息后出现异常会导致消息丢失
消息确认机制(ACK)
自动
autoACK:true
缺点:接收到消息就发送ACK
手动
自动ACK停用,手动调用ACK
优点:业务处理完毕发送ACK保证可靠性
SpringBoot
spring.rabbitmq.listener.direct.acknowledge-mode
spring.rabbitmq.listener.simple.acknowledge-mode
NONE:自动ACK
MANUAL:手动ACK
AUTO:方法未出现异常发送ACK
其他
消费者回调
调用生产者预先定义的API(可选)
为了保证可靠性,发送响应消息
补偿机制
定义超时时间,超时重发(使用定时任务扫描业务表、或者消息表)
最终一致性
约定标准,以核心系统数据为准,拿到文件,进行解析手工平账
消息幂等性
消息接收一次,跟接受很多次,结果一定是一模一样的(消费者控制,唯一标识)
重复消费的原因
生产者问题,环节1重发了消息
环节4出了问题,消费者未发送ACK
生产者代码,网络出了问题
解决,对每一条消息生成一个唯一的业务ID,通过日志或者消息入库来做重复控制
消息顺序性
从生产者到消费者到数据库消费的顺序是一致的
一个队列有多个消费者,消费速率不一样,无法保证顺序
一个队列只有一个消费者的情况下才能保证顺序消费
总结:不同业务消息发送到不同的专用队列,除非复杂场景,不要用多个消费者消费
高可用
集群
25672端口进行集群部署,无法在广域网搭建集群,需要插件
节点类型
内存节点:将元数据存放在内存中,优势读写更快,用内存节点提供应用访问
磁盘节点:默认将元数据放在磁盘中,用磁盘节点做数据备份
集群模式
普通集群
不同的节点之间只会相互同步元数据,而不会同步消息
优点:速度快,只同步元数据
缺点:只同步元数据,不同步消息,节点失效造成消息丢失
镜像队列
镜像队列模式,消息内容在节点之间同步
优点:稳定,可用性更高
缺点:会降低系统性能,节点过多导致同步代价大
负载均衡
HAProxy
Keepalived
面试题
消息队列的作用与使用场景?
要点:异步,解耦,削峰,广播
Channel的作用是什么?
要点:减少TCP长连接的消耗,在JAVA API里重要的编程接口
多个项目共用MQ服务器,怎么实现权限隔离
要点:VHost,创建不同的账户进行隔离
RabbitMQ的消息有哪些路由方式?适合在什么业务场景使用?
要点:直连,主题,广播,头部
交换机与队列、队列与消费者的绑定关系是什么样的?
要点:多对多轮询评分,顺序消费一个消费者进行消费
无法被路由的消息,去了哪里?
要点:返回生产者,备份交换器,直接丢弃
消息在什么时候会变成 Dead Letter (死信)?
要点:队列最大长度,队列最大大小限制,被消费者拒绝的消息,并未设置重回队列
RabbitMQ如何实现延迟队列?
要点:消息过期 + 死信队列,延迟队列插件
哪些情况会导致消息丢失?怎么解决?
要点:参考高可用
可以用队列的x-max-length最大消息数来实现限流吗?例如秒杀场景。
要点:队列超过大小或者长度 ,会把头消息扔掉
如果一个项目要从多个服务器接收消息,怎么做?如果一个项目要发送消息到多个服务器,怎么做?
定义多个ConnectionFactory,注入到消费者监听类的模板方法
一个队列最多可以存放多少条消息?
要点:设置队列最大长度,队列最大大小,默认无限制
如何提高消息的消费速率?
要点:创建多个消费者,使用多线程消费
AmqpTemplate和RabbitTemplate的区别?
要点:amqp是抽象接口,rabbit是具体实现
如何动态地创建队列和消费者?
要点:使用ListenerContainer.setQueues();方法
Spring AMQP中消息怎么封装?用什么转换?
要点:Message,MessageConvertor进行序列化反序列化,也可以自己实现
如何保证消息的顺序性?
要点:RabbitMQ本身没有这样机制,一个队列只有一个消费者
RabbitMQ的集群节点类型?
要点:磁盘节点跟内存节点
如何保证RabbitMQ的高可用?
要点:集群部署,HAProxy + Keepalived
大量消息堆积怎么办?
重启(手动狗头)
Ready的消息太多
多创建几个消费者
Unacked的消息太多
直接清空队列,重发消息
MQ的作用
异步通信
发出请求后,调用者不会马上得到结果,被调用者通过状态、通知来通知调用者
系统解耦
耦合是系统内部或者系统之间存在相互作用,相互影响,相互依赖
把没有严格的先后顺序的业务,发送到消息队列,由各个下游的业务系统自己创建队列消费消息
优点
1、其他系统做了网络迁移只需要修改MQ服务器的地址
2、引入MQ会把消息保存在MQ服务器,即使下游业务系统宕机,或者接口超时,也没有影响,恢复了自己消费就可以
3、即使消费出了问题,生产者也不会受到影响,只需要关心消息有没有发送到MQ服务器上
流量削峰
普通硬件服务器支撑不了百万或者千万级别的并发
引入MQ队列(先进先出 FIFO),相当于排队通道
广播通信
心情不好了就去跟小区大妈聊天,不出十分钟你就知道谁过的比你惨,心情会好很多!
实现一对多通信,用户退货,需要修改积分,修改订单状态,进行退款,只需要增加队列监听,生产者没有任何代码修改
总结
1、引入MQ实现异步,对于数据量大的操作,不需要客户端等待,减少客户端性能消耗,提升高吞吐,大大提升用户体验
2、引入MQ实现解耦,减少系统之间的直接依赖,可拓展性,可维护性得到提升
3、引入MQ实现流量削峰,流量承接下来存放到服务器上,处理完毕后再返回结果,想处理快点,多加几个消费者,达到保护应用和数据库的目的
4、实现一对多的广播通信
引入MQ的问题
1、增加运维成本,必须分配资源部署MQ,保证MQ时刻正常运行
2、系统可用性降低,原本两个人说话,现在还需要一个中间人传话,一旦中间人出现问题,会严重的影响业务
3、增加系统复杂性,了解熟悉MQ才能用好MQ,必须保证MQ的高可用,考虑各种问题
AMQP协议
什么是AMQP
类似JDBC协议,通过相同的API连接不同的数据库
本质上是一种进程间传递异步消息的网络协议,跨语言,跨平台,只要遵循AMQP协议,就可以实现消息的交互
AMQP结构
Module Layer
位于最高层,主要定义了一些供客户端调用的命令,实现客户端的业务逻辑
Sessuion Layer
位于中间层,负责将客户端的命令发送给服务端,再将客户端与服务器之间的通讯提供可靠性同步机制
Transport Layer
位于最底层,主要传输二进制数据流,提供帧的处理,信道复用,错误检测和数据表示等
RabbitMQ工作模型
Prdoucer 生产者
与Broker建立连接,是TCP长链接
通过Channel连接,只需要创建或者释放Channel连接,不需要断开长连接,节省资源
Broker 主机
MQ主机,默认端口5672
VHost 虚拟主机
同一个硬件上需要多个MQ服务,只需要创建VHost,可以提高资源利用率,起到相互隔离的作用
Exchange 交换机
路由消息,根据规则分发消息,多对多的绑定关系
路由方式
Direct 直连
使用明确的绑定键或路由键
适用于业务目的明确的场景
Topic 主题
使用支持通配符的绑定键
#:代表0个或者多个单词
*:代表不多不少一个单词
单词:使用“.”隔开字符 a.bc.defg 3个单词
适用于根据业务主题过滤消息的场景
Fanout 广播
无需绑定键
适用于通用类业务进行广播
Headers 头交换
用消息的消息头属性进行匹配
行能差,不实用
Binding 绑定
交换机与队列建立绑定的关系
Queue 队列
Broker有一个对象来存储消息,这个消息就是Queue
实际上用数据库存储消息,都是Erlang开发的
队列是生产者跟消费者之间的纽带,生产者发送消息到达队列,消费者从队列消费消息
Connection 连接
生产者跟消费者必须跟Broker建立一个连接,这个是TCP长连接
Channel 信道
AMQP引入的概念,是虚拟连接,只需要创建和释放Channel,大大减少资源消耗
相互隔离,每个Channel有自己的编号
原生API重要的编程接口,调用的都是Channel接口上的方法
Consumer 消费者
同生产者
消费模型
Pull
消息存放在服务端,消费者主动获取才能拿到消息,
缺点:每个一段时间获取消息,消息实时性会降低
优点:根据消费者的能力决定获取消息的频率
Push
通过事件机制对队列进行监听,只要生产者发送消息到服务器,马上推送给消费者
缺点:不会根据消费者的能力判断推送多少消息,会造成消息积压
优点:消息实时性高
一个消费者可以监听多个队列,一个队列也可以被多个消费者监听
建议一个消费者只处理一个队列的消息,如果需要提升消息处理能力,可以增加多个消费者,消息进行轮询
MQ进阶
订单延迟关闭
消息设置过期
使用死信队列指定消息过期时间
x-dead-letter-exchange交换机跟队列进行绑定
消息流转过程
1、生产者生产消息,通过默认交换机路由到默认队列,但是无消费者进行消费
2、设置x-dead-letter-exchange;消息到达TTL之后会进入死信交换机
3、死信交换机与死信队列进行绑定,路由到死信队列,最后由消费者进行消费
队列设置过期
x-message-ttl设置一个统一的过期时间
缺点
如果消息也设置了过期时间,会选择过期时间较小的时间
实现不同阶梯(2分一次,4分一次)的消息投递,需要创建很多队列
RabbitMQ插件
通过rabbitmq-delayed-message-exchange实现
创建x-delayed-message交换机,指定投递的时间
推荐使用,更方便
什么时候会进入死信队列
1、队列达到了长度的限制 x-max-length
2、队列达到最大字节限制x-max-length-bytes
3、被消费者拒绝,而且未设定重回队列
对头的消息会被丢入死信队列,不适合做秒杀
消息存满了怎么办
服务端控流
设置队列长度
内存控制:默认40%
磁盘控制:默认30%
消费端限流
prefetch count 预取,最多同时处理的消息数量
非自动确认消息的前提下,如果一定数目的消息未被确认钱,不进行新消息的推送
0 条评论
下一页