RabbitMQ
-
![img]()
-
消息传输模式(生产者与消费者之间的传输关系)
模式 交换机类型 路由机制 消息分发特点 典型应用场景 简单模式 默认(Direct) 队列名精确匹配 1:1(单生产者→单消费者) 单次通知、简单任务处理 工作队列模式 默认(Direct) 队列名精确匹配 1:N(多消费者竞争消费) 任务分发、负载均衡(如订单处理) 发布/订阅模式 Fanout 忽略路由键,广播所有队列 1:N(所有消费者收到相同消息) 日志广播、系统通知 路由模式 Direct 路由键精确匹配(如 error)1:1 或 1:N(相同Key的队列) 订单分类、日志分级(如仅处理错误日志) 主题模式 Topic 通配符匹配( *单级、#多级)M:N(动态匹配多个队列) 多维度事件分发(如新闻订阅 news.*)RPC模式 依赖Direct/Topic 请求/响应队列绑定 双向通信(生产者→消费者→生产者) 同步远程调用(较少使用) -
消息分发机制
默认轮询分发
还有不公平分发和预取值分发等
-
消息确认机制
消费者/生产者确认机制都是默认关闭的。
消息发送失败场景大多是网络原因,概率极低。风险多聚焦在消费者层面
支付等零失败场景下务必针对核心业务实施 生产者确认、集群高可用、重试补偿 三重重保。
生产者确认机制:rabbitmq将ack返回给发送者。如果rabbitmq返回ack失败,生产端也无法确认消息是否真的发送成功,也会造成数据丢失。最好的办法是使用rabbitmq的事务机制,但是rabbitmq的事务机制效率极低。
消费者确认机制:消费者在声明队列时,可以指定autoAck参数,当autoAck=false时,RabbitMQ会等待消费者显式发回ack信号后才从内存(和磁盘,如果是持久化消息的话)中移去消息。否则,RabbitMQ会在队列中消息被消费后立即删除它。
消费者手动确认可能出现的问题(测试点):(1)消息无法ack:消费端在消费消息过程中出现异常,不能回复ack应答,消息将变成unacked状态,并且一直处于队列中。如果积压的过多将会导致程序无法继续消费数据。消费端服务重启,断开rabbitmq的连接后,unacked的消息状态会重新变为ready等待消费。但是如果不重启消费端服务,消息将一直驻留在MQ中。所以,可以捕获异常,然后调用Nack确认,然后消息进入队列重新消费。
(2)无效消息循环重入队列:如果消费端捕获异常,并进行basicNack应答,并将消息重新放入队列中,可能会出现无效的消息循环入队列的问题。假设消息或者代码本身有bug,每次处理这个消息都会报异常,那消息将一直处于消费——>报异常——>重入队列——>继续消费——>报异常。。。的死循环过程。防止死循环有两种处理办法:一是:设置异常的类型,根据不同的异常类型选择那种异常是需要重新入队列;二是:将异常的消息放入专门存放异常信息的对列中,后期人工再去取处理这些异常信息。 -
幂等性
消息幂等性,其实就是保证同一个消息不被消费者重复消费两次。当消费者消费完消息之后,在返回ack应答确认的时候失败了,会导致生产者接收不到确认消息,往往会将这个消息重新发送给消费端,但是消费端在之前一次就已经完成消费了,如果不能保证幂等性的话,那么消费者就会出现重复消费同一个消息。实现消息幂等性的方案:
生产者每次发送消息的时候会生成一个全局唯一的id放到信息中,每次消费消息之前根据这个全局id去查询db或者redis中是否存在该id的消息信息,如果有,则说明该消息已经消费过,直接返回不再做后续处理;如果没有,则说明该消息未被消费过,继续进行后续业务处理,处理成功之后再将该全局id插入到bd或者redis中。场景 配置 消息重复概率 说明 无任何保障 禁用Confirm,自动ACK 极高 消息可能既在生产者端丢失,又在消费者端因自动ACK而丢失,但自动ACK也可能导致处理失败后消息丢失而无重试。 基础保障 开启Confirm,手动ACK 中等 解决了大部分丢失问题,但生产者超时重发和消费者ACK前崩溃会导致重复。这是最典型的重复场景。 网络不稳定环境 任何配置 高 网络抖动会大幅提高连接超时的概率,从而触发生产者和消费者两端的重试机制。 高可用稳定集群 最佳实践配置 低 硬件和网络稳定使得意外断开减少,但不等于零。微服务重启、部署等操作仍会导致重复。 -
持久化
队列持久化:队列持久化后重启rabbit-server服务后该队列依然存在,而非持久化的队列则会丢失。持久化的队列在web控制台中有一个D的标记。
消息持久化:RabbitMQ默认把消息放在内存中是为了加快传输和消费的速度,消息持久化后将会存入磁盘中。当消息持久化后,重启rabbit-server服务,消息依然存在,而非持久化的消息则会丢失。消息持久化必须保证所在的队列也是持久化的,且将消息标记为持久化并不能完全保证不会丢失消息。因为当消息刚准备存储在磁盘的时候,但是还没有存储完,消息还在缓存的一个间隔点,此时宕机会导致消息丢失。
消息的持久化是为了防止 RabbitMQ 服务重启或崩溃时消息丢失。RabbitMQ 会在消息被成功消费后,根据确认机制来决定何时以及如何从磁盘上删除它们。
阶段 持久化状态 消费者确认后的变化 消息待消费时 持久化消息会同时存在于内存(为了性能)和磁盘(为了安全) - 消费者开始处理消息 消息状态变为 Unacked(未确认),但仍占用磁盘空间- 消费者发送ACK确认成功 RabbitMQ 会将这条消息从磁盘存储中删除,释放空间 消息被删除,无法再被获取 消费者发送NACK或超时 消息状态可能变回 Ready(重新入队),磁盘上的持久化数据依旧保留以供再次投递消息会保留在磁盘上,等待被下一个消费者消费 交换机持久化:同理
-
事务:
Rabbitmq事务与db中的事务类似,db中的事务是为了保证一系列的数据库操作要么全部执行成功,要么都不执行,而 Rabbitmq事务则是为了保证生产者发送的消息要么都发送到Rabbitmq服务上,要么都不发送。
-
死信队列:
消息变成死信的3中原因:
(1)消息过了过期时间TTL(time to live),消息队列中存放的消息一般都是有一定时间的,超过了这个时间,这条消息就会被放到死信队列中去;
(2)消息队列满了,后续再投递到该队列中的消费会转存到死信队列去;
(3)消费者主动拒绝(Nack)


浙公网安备 33010602011771号