Home
avatar

.𝙃𝙤𝙬𝙚

向下滚动

消息队列核心知识|java知识点

消息队列的作用

消息队列在分布式系统中主要解决四个问题:

  • 异步:将非核心操作异步处理,提升主流程响应速度。
  • 削峰:高峰期将请求先写入队列,消费端按自身能力匀速消费,避免瞬时流量压垮下游服务。
  • 解耦:生产者和消费者不需要感知彼此的存在,通过消息中间件间接通信,降低服务间的耦合度。
  • 分布式事务:通过事务消息机制保证跨服务的数据最终一致性。

消息模型

点对点模型

一条消息只能被一个消费者消费。消费者从队列中取出消息后,该消息从队列中移除。

发布/订阅模型

一条消息可以被多个消费者消费,消费者之间互不影响。生产者将消息发送到 Topic,每个订阅该 Topic 的消费者组都能收到全量消息。

集群消费与广播消费

RocketMQ 在发布/订阅模型基础上扩展了两种消费模式:

  • 集群消费:同一消费者组内的多个实例进行负载均衡,每条消息只被组内一个实例消费。
  • 广播消费:同一消费者组内的每个实例都消费全部消息。

消费者组

消费者组(Consumer Group)解决大流量场景下的消费能力瓶颈问题:

  • 队列分片:Topic 被拆分为多个队列(分区),每个队列分配给组内一个消费者。
  • 重平衡(Rebalance):当消费者上下线时,自动重新分配队列与消费者的映射关系,保证每个队列有且只有一个消费者负责。
  • 消费能力扩展:增加消费者实例即可水平扩展消费能力(受限于队列数量)。

顺序消息

由于多生产者并发发送、多队列写入、多消费者并发消费,MQ 天然无法保证全局消息顺序。RocketMQ 的顺序消息方案:

  • 生产端:将需要保证顺序的消息(如同一订单的状态变更)通过相同的消息 Key 路由到同一个队列。
  • 消费端:消费者对同一个队列进行单线程消费(加锁),保证同一队列内的消息按顺序处理。
  • 局限性:顺序只在同一个队列内保证,多个队列之间不保证全局顺序。

消息幂等

为什么会出现重复消费

MQ 只能保证 At Least Once(至少消费一次),无法严格保证 Exactly Once。重复消费的原因:

  • 生产者因网络超时重试发送。
  • 消费者处理成功但提交 Offset 前崩溃,重平衡后消息被重新分配。
  • 消费端异常触发重试机制。

幂等实现方式

  • 数据库唯一索引:利用唯一约束防止重复插入。
  • 去重表 / 业务唯一 ID:消费前先查询去重表是否已处理。
  • Redis 前置过滤:在 Redis 中记录已消费的消息 ID,高并发场景下快速过滤重复消息。
  • 高并发组合方案:Redis 做前置去重过滤,数据库做最终一致性兜底。

不丢消息

保证消息不丢失需要从三个环节入手:

生产端

  • 使用同步发送(send),确保消息成功到达 Broker 后再继续。
  • 配置发送重试机制(默认重试 2 次),应对网络抖动。

Broker 端

  • 同步刷盘:消息写入内存后立即刷到磁盘。安全性最高但性能较差。
  • 异步刷盘:消息先写入内存,由后台线程定期刷盘。性能好但可能丢失少量消息。
  • 主从复制:主节点收到消息后同步到从节点。建议至少 2 副本。

消费端

  • 业务处理成功后再提交 Offset。
  • 消费失败时抛出异常,触发 Broker 重试。

同步 vs 异步策略的选择

同步刷盘 + 同步复制虽然最安全,但会显著增加延迟,吞吐量大幅下降。大多数生产环境选择异步刷盘 + 异步复制,通过发送重试、主从复制和业务幂等来实现最终可靠性,在可靠性与性能之间取得工程上的平衡。

事务消息

RocketMQ 的事务消息解决了生产者本地事务与消息发送的一致性问题。

流程

  1. 发送半消息(Half Message):生产者先发送一条对消费者不可见的半消息到 Broker。
  2. 执行本地事务:半消息发送成功后,生产者执行本地数据库操作。
  3. 提交或回滚:根据本地事务的执行结果,向 Broker 发送 Commit(消息对消费者可见)或 Rollback(消息丢弃)。
  4. 回查机制:如果 Broker 长时间未收到 Commit/Rollback,会主动回查生产者本地事务状态,决定消息最终是提交还是回滚。

事务消息保证了消息发送与本地事务的原子性,最终实现跨服务的数据一致性。

RocketMQ 与 RabbitMQ 对比

特性RocketMQRabbitMQ
开发语言JavaErlang
吞吐量高(十万级/秒)中(万级/秒)
延迟毫秒级微秒级
事务消息原生支持需要自行实现
顺序消息支持需要特殊配置
延迟消息原生支持通过 TTL + 死信队列实现
消息回溯支持按时间回溯不支持
生态与 Java / Spring 生态深度集成社区成熟,协议标准(AMQP)
适用场景大规模分布式系统、电商、金融中小规模、需要灵活路由规则

简要总结:RabbitMQ 成熟稳重、生态完善,适合中小规模场景;RocketMQ 高吞吐、高可用,原生支持事务消息和延迟消息,更适合大规模分布式系统。

消费失败重试策略

当消费者处理消息失败时:

  • 自动重试:RocketMQ 默认最多重试 16 次,重试间隔逐步增大(从 10 秒到 2 小时)。RabbitMQ 通过 nack + 重回队列或死信队列实现重试。
  • 死信队列(Dead Letter Queue):超过最大重试次数的消息进入死信队列,需要人工介入处理。
  • 重试中的幂等保护:每次重试消费时都必须做幂等判断,防止重试导致重复处理。

本文内容整理自消息队列学习笔记,涵盖消息模型、消费机制、顺序消息、幂等、可靠投递、事务消息和 MQ 选型对比等核心知识点。

java知识点 Java 消息队列 RocketMQ RabbitMQ