1. RabbitMQ如何保证消息不丢失?RabbitMQ 保证消息不丢我一般会按消息流转的三个阶段来处理。第一段是生产者到 MQ这里会开启 publisher confirm确认消息有没有到达交换机如果路由不到队列还要配合 return callback 记录失败消息后续重试或补偿。第二段是 MQ 自身要保证交换机、队列和消息都是持久化的避免 broker 重启后消息丢失。第三段是消费者消费这里不能用自动 ACK而是要手动 ACK。只有业务逻辑真正处理成功后才 ack如果失败就根据情况重试超过次数后丢到死信队列或者异常队列后续人工处理或补偿任务处理。另外实际项目里还要做消费幂等因为消息不丢通常意味着可能重复投递比如 ACK 失败或者生产者重试所以消费者要用业务唯一 ID、状态判断或者 Redis 去重来保证重复消息不会造成脏数据。2. RabbitMQ消息的重复消费问题如何解决RabbitMQ 出现重复消费是比较正常的因为它更多保证的是消息至少被消费一次不保证绝对只消费一次。比如消费者业务已经处理成功了但是 ACK 失败或者服务刚处理完就宕机了MQ 认为这条消息没消费成功就可能重新投递。解决思路主要是在消费端做幂等。我们一般会让消息带一个业务唯一标识比如订单号、支付流水号或者消息 ID。消费者处理前先根据这个唯一标识判断是否已经处理过如果处理过就直接 ACK不再重复执行业务。具体实现要看场景。比如发优惠券这种插入类业务可以对 userId couponId orderId 建唯一索引重复消费时数据库会拦住。比如订单支付这种状态流转业务可以只允许订单从未支付改成已支付重复消息来了更新影响行数就是 0。高并发场景也可以用 Redis setnx 做去重但关键是要保证判断和处理尽量原子不能只是简单地先查再插。4. RabbitMQ中死信交换机了解吗RabbitMQ延迟队列有了解过吗死信交换机我了解是用来接收死信消息的。比如消息 TTL 过期、队列达到最大长度或者消费者 reject/nack 并且不重新入队这些消息都会变成死信然后被投递到配置好的死信交换机。RabbitMQ 实现延迟队列常见有两种方式。第一种是 TTL 加死信交换机生产者先把消息发到一个没有消费者的延迟队列消息在这个队列里等 TTL 过期过期后变成死信再由死信交换机路由到真正的业务队列最后消费者再处理。第二种是使用 RabbitMQ 的延迟消息插件也就是rabbitmq_delayed_message_exchange。它可以声明x-delayed-message类型的交换机通过消息头里的x-delay设置每条消息的延迟时间比 TTL 加死信队列更灵活。实际项目里如果延迟时间比较固定用 TTL 加死信交换机就够了如果每条消息延迟时间不一样插件方式会更方便。5. 如果有100万消息堆积在MQ如何解决-先定位原因-消费者-扩容 -批量处理多线程处理调整prefetch -业务逻辑慢-优化慢SQL减少远程调用批量写入 -下游慢(数据库)-对生产端限流降级 -保护MQ -惰性队列失败进死信如果 RabbitMQ 里堆积了 100 万消息我不会一上来就只加消费者先要看监控和日志确认堆积原因。比如是消费者挂了、消费失败一直重试还是下游数据库、Redis、第三方接口变慢或者生产端流量突然打高。确认原因后再处理。如果是消费者处理能力不够可以临时扩容消费者实例或者在单个消费者内部做批量处理、多线程处理同时适当调整 prefetch避免一个消费者一次拉太多消息。如果是业务逻辑慢就要优化慢 SQL、减少远程调用或者做批量写入。但如果瓶颈在下游比如数据库已经很慢了就不能盲目加消费者否则会把数据库打得更慢。这时候要对生产端做限流必要时降级非核心消息先保证核心链路稳定。另外如果消息堆积量很大要注意保护 RabbitMQ 本身可以用惰性队列让消息更多落盘降低内存压力。消费失败的消息也不能无限重试超过次数应该进入死信队列后面补偿处理。6. RabbitMQ的高可用机制了解吗第一层-普通集群 第二层-队列级别的高可用-Quorum QueueRabbitMQ 的高可用我一般会分两层看。第一层是 RabbitMQ 集群本身多节点部署后交换机、队列元数据、绑定关系这些会在集群内共享但普通集群并不代表队列里的消息也自动多副本所以只做普通集群还不够。第二层就是真正要做队列级高可用早期可以用镜像队列不过现在更推荐 Quorum Queue。Quorum Queue 是基于 Raft 的多副本队列一个队列会有 leader 和多个 followerleader 负责处理读写并把消息复制给 follower。如果 leader 节点宕机集群会从 follower 里重新选出新的 leader 继续工作。但 Quorum Queue 通常要求多数派节点存活比如 3 个副本至少要有 2 个节点可用否则就不能安全选主。7. 那出现丢数据怎么解决呢如果 RabbitMQ 出现丢数据我不会只看一个点而是先按消息链路排查是哪一段丢的。如果是生产者发送到 MQ 这段丢了要开启 publisher confirm确认消息是否到达交换机如果路由不到队列再配合 return callback 记录失败消息后续重试或补偿。关键业务也可以用本地消息表先把消息落库再异步发送失败后定时补发。如果是 MQ 自身存储或节点故障导致的风险要保证交换机、队列和消息都持久化。队列级高可用可以用 Quorum Queue它基于 Raft 做多副本复制leader 挂了可以重新选主比单节点队列更安全。如果是消费者阶段丢了就不能用自动 ACK要改成手动 ACK业务真正处理成功后再 ack。消费失败可以重试超过次数进入死信队列后续补偿处理。另外为了应对重试带来的重复消费消费端还要做幂等。