1 前言
- RocketMQ特性
- 基本概念
1.1 RocketMQ特性
- 原生分布式
- 设计的时候就考虑到分布式,相较于ActiveMQ存在的单点故障问题,RocketMQ天生就支持分布式集群
- 两种消息拉取方式
- 严格消息顺序
- 特有的分布式协调器
- 亿级消息堆积
- 组(Group)
- 分组可以实现消息的负载均衡
1.2 RocketMQ基本概念
- Producer:消息生产者,负责生产消息,一般由业务系统负责生产消息,如订单系统
- Consumer:消息消费者,负责消费消息,一般是后台系统负责异步消费,如短信系统
- Push:broker接收到消息后,推送消息给Consumer,由于Consumer消费消息的速率不同,因此有可能造成消息堆积和网络拥堵
- Pull:Consumer主动向broker拉取消息,适用于不同速率的Consumer消费消息的情景
- Broker:消息中转者(RocketMQ Server),负责存储消息,转发消息
- Topic:消息的主题,通常一个业务系统一个Topic,用于消息分类,也就是Consumer可以按照主题进行订阅,在RockerMQ Server进行配置
- Message:在Producer、Consumer和Broker之间传递的消息,一个Message必须属于一个Topic
- Offset:偏移量,Consumer拉取消息时需要知道上一次消费到了什么位置,这一次从哪里开始拉取
- Partition:分区,Topic物理上的分区,一个Topic可以分为多个分区,每一个分区是一个有序的队列,分区中的每条消息都会给分配一个有序的ID,也就是偏移量
- Tag:用于对Message进行过滤,同一业务不同目的的Message可以使用相同的Topic,但是可以用不同的Tag来区分
- Key:消息的Key字段是为了唯一表示消息的,为了方便开发和运维定位问题,如Key可以是订单ID
- NameServer:注册中心,可以集群部署,每一个Broker启动时,都会向NameServer注册,主要是接收客户端的路由请求并返回路由信息
- Consumer Group:每个Consumer对应一个特定Group,可以为单个Consumer指定Group,不指定则在默认Group,同一Topic的一条消息只能被同一Group的一个Consumer消费,保证了不会被重复消费,但该消息可以被多个Group消费
2 架构方案
为了避免出现单点故障,在实际生产环境中,会把Producer、Consumer、Broker和NameServer部署成集群,Producer、Consumer会跟NameServer建立长连接,用于发现Broker;Broker自动伸缩、故障或者升级都会更新NameServer中的注册信息
- Producer Cluster:查询NameServer集群,根据返回的路由信息(负载均衡),往Broker集群发送消息
- NameServer Cluster:存储当前集群所有的Broker信息、Topic跟Broker的对应关系
- Broker Cluster:向NameServer集群注册,Broker Master和Broker Slave会进行数据同步
- Consumer Cluster:查询NameServer集群,根据返回的路由信息(负载均衡),从Broker集群拉取消息
3 有序消息
- 全局顺序
- 分区顺序
- 全局顺序与分区顺序对比
- RocketMQ顺序消息的实现
3.1 全局顺序
一个Topic内所有的Message都发布到同一个queue,按照先进先出的顺序进行发布和消费
- 适用场景:性能要求不高,所有的消息严格按照FIFO原则进行消息发布和消费
3.2 分区顺序
对于指定的一个Topic,所有消息根据sharding key发布到不同queue,同一queue中的消息严格按照FIFO原则进行消息发布和消费
- 适用场景:性能要求高,根据消息中的sharding key决定消息发送到哪个queue
3.3 全局顺序与分区顺序对比
消息类型 | 支持事务消息 | 支持定时消息 | 性能 |
---|---|---|---|
无序消息(普通、事务、定时、延迟消息) | 是 | 是 | 最高 |
全局顺序消息 | 否 | 否 | 一般 |
分区顺序消息 | 否 | 否 | 高 |
3.4 RocketMQ顺序消息的实现
4 订阅机制和定时消息
- RocketMQ发布订阅
- Push(推模式)
- Pull(拉模式)
- 延迟级别
- Broker定时消息发送逻辑
4.1 RocketMQ发布订阅
- Push模式(MQPushConsumer):Broker主动向消费者推送
- Pull模式(MQPullConsumer):消费者在需要消息时,主动到Broker拉取
但是,在RocketMQ中,具体实现时,Push和Pull模式都是采用消费端主动从Broker拉取消息的形式实现的
4.2 Push(推模式)
4.3 Pull(拉模式)
Pull方式里,取消息的过程需要用户自己写
- 首先通过Topic获取MessageQueue集合
- 遍历集合
- 针对每个MessageQueue批量取消息,记录offset
4.4 延迟级别
Broker延迟级别从1-18,对应时间1s、5s、10s、30s、1m、2m、3m、4m、5m、6m、7m、8m、9m、10m、20m、30m、1h、2h
4.5 Broker定时消息发送逻辑
5 批量消息和事务消息
- 为什么使用批量消息
- 使用批量消息的限制
- RocketMQ事务消息设计
- 事务消息的使用约束
- 事务消息的状态
5.1 为什么使用批量消息
追求性能,尤其在消息量特别大的情况,将请求合并发送,如数据库批处理
5.2 使用批量消息的限制
- 同一批次的消息应该具有相同Topic、相同的消费配置
- 不支持延迟消息
- 建议一次批量消息不要超过1MB
5.3 RocketMQ事务消息设计
- MQ发布方发布Half消息到Server
- Half消息发送成功
- MQ发布方执行本地事务
- MQ发布方向Server发送Commit或Rollback
- Server未收到4的确认,回查事务状态
- MQ发布方检查本地事务状态
- MQ发布方根据事务状态向Server发送Commit或Rollback
- Server接收到Commit,向MQ订阅方投递消息
- Server接收到Rollback,删除消息不投递
5.4 事务消息的使用约束
- 不支持定时和批量
- 为了避免消息堆积,限制了单个消息的默认检查次数为15次,可以通过修改broker配置文件中的transactionCheckMax参数进行调整
- 特定的时间段之后才检查事务,通过broker配置文件中的transactionTimeout参数进行调整
- 一个事务消息可能被检查或消费多次
- 事务消息的生产者ID不能与其它类型消息的生产者ID共享
5.5 事务消息的状态
- TransactionStatus.CommitTransaction提交事务,允许消费者消费这个消息
- TransactionStatus.RollbackTransaction回滚事务,消息将会被删除或不再允许消费
- TransactionStatus.Unknown中间状态,MQ需要重新检查来确定状态
6 RocketMQ高性能最佳实践
- Producer最佳实践
- 消费者组和订阅
- 消息监听器
- NameServer最佳实践
6.1 Producer最佳实践
- 一个应用尽可能用一个Topic,消息子类型用tags来标识,tags可以由应用自由设置
- 每个消息在业务层面的唯一标识码,要设置到keys字段,方便将来定位消息丢失问题
- 如有可靠性需要,消息发送成功或者失败,要打印消息日志(sendresult和key信息)
- 如果相同性质的消息量大,使用批量消息,可以提升性能
- 建议消息大小不超过512kb
- send(msg)会阻塞,如果有性能要求,可以使用异步的方式:send(msg, callback)
- 对于消息不可丢失应用,务必要有消息重发机制
- send消息方法发送成功会有多个状态,在sendResult中定义
以上策略不一定保证消息一定发送成功,建议将消息存储到db,由后台线程定时重试,保证消息定到达Broker
6.2 消费者组和订阅
不同的消费组可以消费同样的主题,并且每个消费者都有各自的消费偏移量
确保同一消费者组的消费者订阅相同的Topic
6.3 消息监听器
关于这一部分,之后会有另一篇博客详细讲述
6.4 NameServer最佳实践
为了让Broker和Client启动后,能够向注册中心提供注册消息,有以下四种方式可以进行配置
- 编程的方式
- HTTP端点
- JVM配置
- Linux内核配置
参考文章
结语
本人所有博客仅用于学习记录,不做任何商业用途,如涉及侵权,还请联系删除,感谢阅读,欢迎留言,一起进步~