跳转到内容

消息模型与投递语义

用途:明确“消息会不会重复/丢失/乱序”,并据此设计消费方

  • Topic:一类消息的逻辑名称。
  • MessageQueue(队列):Topic 的分片,是并行与顺序的单位。
  • Tag:二级过滤(TagA || TagB),Broker 侧按 hash 粗过滤 + 客户端精过滤,避免为每个子类建 Topic。
  • Key:业务检索键(订单号),用于消息查询与去重排查。
  • 消费者组:同一组内实例分摊队列(集群模式);不同组各自独立消费全量(广播语义由多组实现)。
  • 位点(offset):组维度的消费进度,集群模式由 Broker 持久化。

RocketMQ 提供至少一次(at-least-once),不提供恰好一次:

现象 成因
重复 消费超时重投、Broker 主从切换、生产者重试、位点提交失败
乱序 多队列并行、重试打乱顺序、生产者未指定同一队列
丢失 异步刷盘 + 异步复制下宕机、Topic 自动创建配置错误、消费端吞异常

结论:消费方必须幂等(见“幂等与去重”),并把“重复”当作正常事件设计。

方式 适用 注意
同步发送 需要确认结果(业务事件) 设超时与重试次数;重试可能产生重复
异步发送 高吞吐、允许稍后确认 回调线程不要做重活
单向发送 日志/指标类可丢数据 不保证到达
批量发送 同 Topic 大量小消息 受单批大小限制

可靠性配置组合:同步发送 + 重试(多 Broker)+ 同步刷盘/同步复制 + 事务消息或本地消息表 + 消费幂等 + 对账。

只有同一队列内有序。要保证业务实体有序,生产者需按业务键选择队列(MessageQueueSelector,如 hash(orderId) % queueNum),且该队列不能并发消费(消费锁/单线程)。顺序消息与吞吐互斥,务必只在真正需要的场景使用。

  • 单消息体上限默认 4MB,但实践应远小于此(建议 KB 级):大消息放大存储、网络与重试成本。
  • 传“事件 + 关键标识”,不要传完整快照;订阅方按需回查详情(避免结构耦合与体积膨胀)。
  • 敏感数据不进消息体(消息会被复制、索引、保留多日)。
误区 修正
认为 MQ 保证不重复 至少一次,重复是常态
用广播模式做集群消费 广播位点在本地,实例重启会重放或漏消费
Tag 数量当枚举无限扩展 Tag 过滤能力有限,分类多时拆 Topic 或用属性过滤(SQL92)
消息体塞大对象 改为事件 + 回查
全局顺序(所有消息单队列) 吞吐归零,业务上通常也不需要
  • Apache RocketMQ 官方文档:Concept、Producer/Consumer 配置
  • Martin Kleppmann《数据密集型应用系统设计》第 11 章(消息系统的投递保证)