基于本文回答

播面 播面

文解图解播客视频,多维讲透八股文
0
评论

在 RocketMQ 中如何处理大消息(如超过 4MB 的消息)?

知识点图片

在 RocketMQ 中,默认的最大消息大小通常是 4MB(不同版本可能略有差异,老版本可能是 128KB 或更小)。消息队列(MQ)的核心设计初衷是处理高并发、低延迟、小体积的数据流。如果将大文件或巨大的 Payload 直接塞入 MQ,会导致网络带宽被占满、Broker 内存暴涨、频繁触发 GC,甚至导致其他业务的消息堆积和延迟。

因此,处理大消息(超过 4MB)通常有以下几种方案。按照推荐程度从高到低排列如下:


方案一:使用外部存储(OSS/S3/HDFS)—— ⭐ 最优实践,业界标配

这是处理大消息最正规、最稳定的做法,被称为 "Claim Check"(认领凭证)模式

工作流程:

  1. 上传数据:生产者(Producer)在发送消息前,先将大体积的数据(如图片、视频、超大 JSON)上传到对象存储(如 阿里云 OSS、腾讯云 COS、MinIO、HDFS 等)。
  2. 获取凭证:上传成功后,获取该文件的下载 URL 或唯一标识(Object Key)。
  3. 发送消息:生产者将这个 URL 作为普通小消息发送到 RocketMQ。
  4. 消费下载:消费者(Consumer)收到消息后,解析出 URL,从对象存储中下载真正的大数据进行处理。
  5. 清理数据(可选):处理完成后,消费者调用 API 删除对象存储中的文件,或者依赖对象存储的生命周期规则(TTL)自动清理。

优点:彻底解放 RocketMQ,保持其极高的吞吐量;不受消息大小限制。
缺点:引入了额外的存储组件,增加了系统的网络开销(多了一次上传和下载)。


方案二:消息压缩(Compression)—— 适合文本类大消息

如果你的大消息是 JSON、XML 或纯文本(比如 5MB - 10MB 的文本),它们通常具有极高的压缩比。

工作流程:

  1. RocketMQ 自带压缩:RocketMQ 默认会在 Producer 端对大于 4KBcompressMsgBodyOverHowmuch 参数)的消息使用 ZIP 进行压缩。你可以确认该机制是否生效。
  2. 业务层手动压缩:在将数据转为 byte 数组发送给 MQ 之前,在业务代码中使用高压缩比的算法(如 Gzip, Snappy, LZ4, Zstd)进行压缩。消费者收到后先解压再反序列化。

优点:不需要引入外部存储,代码改造量小。
缺点:消耗 CPU 资源;如果数据本身已经是压缩格式(如 JPG 图片、PDF、视频),此方案无效。


方案三:修改 RocketMQ 参数放宽限制 —— 仅限“略微超标”的场景

如果你不想引入 OSS,且消息大小只是稍微超过 4MB(例如 6MB、8MB),可以通过修改 RocketMQ 的配置来提高限制。

⚠️ 注意:必须同时修改 Broker 端和 Producer 端的配置。

  1. 修改 Broker 端配置:
    在 Broker 的配置文件(broker.conf)中增加或修改以下参数,然后重启 Broker:

    plaintext
    # 将最大消息大小修改为 10MB (10 * 1024 * 1024)
    maxMessageSize = 10485760
  2. 修改 Producer 端配置:
    在生产者的代码中,调整 maxMessageSize 属性:

    java
    DefaultMQProducer producer = new DefaultMQProducer("your_group");
    // 设置为 10MB
    producer.setMaxMessageSize(10 * 1024 * 1024);
    // 注意:如果发送的消息很大,发送超时时间也建议适当延长,默认是 3000ms
    producer.setSendMsgTimeout(5000); 
  3. 修改 Consumer 端配置(可选):
    虽然消费端没有硬性的单条消息大小限制,但如果是拉取模式或批量消费,建议注意拉取批次大小避免 OOM。

优点:最简单,只需改配置。
缺点:会严重影响 RocketMQ 性能。大消息会导致 Broker 写入 PageCache 变慢,占用大量网络带宽,导致同一时刻的其他小消息排队,产生长尾延迟。


方案四:消息拆分(分块发送)—— 极不推荐,复杂度过高

将一个 10MB 的消息,在业务层面拆分成 5 个 2MB 的小消息。

工作流程:

  1. 生产者给这 5 个消息分配同一个 traceId,并标记 chunkIndex (1/5, 2/5...)。
  2. 将它们发送到 RocketMQ。
  3. 消费者收到消息后,不能立刻处理,必须先把切片缓存起来(如存入 Redis)。
  4. 等所有切片都到达后,消费者再将其拼接成完整的 10MB 数据进行处理。

优点:无需修改 MQ 配置,无需外部存储。
缺点极其复杂。需要处理乱序问题、部分切片丢失问题、并发组装时的内存泄漏问题,极其容易出 Bug。除非极端环境受限,否则千万不要用这种方案。


总结与建议

消息大小 数据类型 推荐处理方案
< 4MB 任意 直接使用 RocketMQ 发送。
4MB - 10MB JSON / 文本 方案二:业务层 Gzip/LZ4 压缩后再发送。
4MB - 10MB 无法压缩的二进制 方案三:评估 Broker 带宽后,适当调大 maxMessageSize 配置。
> 10MB 任意 方案一:坚决使用 OSS/S3 等对象存储 + RocketMQ 传递 URL。