核心概念
NameServer
- nameserver是整个rocketmq的大脑,是rocketmq的注册中心。
- broker在启动时向所有nameserver注册。
- 生产者在发送消息之前先从 NameServer 获取 Broker 服务器地址列表(消费者一 样),然后根据负载均衡算法从列表中选择一台服务器进行消息发送。
- NameServer 与每台 Broker 服务保持长连接,并间隔 30S 检查 Broker 是否存活,如果检测到 Broker 宕机,则从路由注册表中将其移除。这样就可以实 现 RocketMQ 的高可用。
- 类似kafka中zookeeper的作用
生产者
消费者
消息
- 字节数组
Broker
- 同kafka broker
整体运转
- NameServer 先启动
- Broker 启动时向 NameServer 注册
- 生产者在发送某个主题的消息之前先从 NamerServer 获取 Broker 服务器地址列表(有可能是集群),然后根据负载均衡算法从列表中选择一台
Broker 进行消息发送。 - NameServer 与每台 Broker 服务器保持长连接,并间隔 30S 检测 Broker 是否存活,如果检测到 Broker 宕机(使用心跳机制,如果检测超过
120S),则从路由注册表中将其移除。 - 消费者在订阅某个主题的消息之前从 NamerServer 获取 Broker 服务器地址列表(有可能是集群),但是消费者选择从 Broker 中订阅消息,订阅
规则由 Broker 配置决定。
分组(Group)
- 生产者:标识发送同一类消息的 Producer,通常发送逻辑一致。发送普通消息的时候,仅标识使用,并无特别用处。
- 主要作用用于事务消息:
(事务消息中如果某条发送某条消息的 producer-A 宕机,使得事务消息一直处于 PREPARED 状态并超时,则 broker 会回查同一个 group 的其它 producer, 确认这条消息应该 commit 还是 rollback)
- 消费者:标识一类 Consumer 的集合名称,这类 Consumer 通常消费一类消息,且消费逻辑一致。同一个 Consumer Group 下的各个实例将共同消费 topic 的消息,起到负载均衡的作用。
- 消费进度以 Consumer Group 为粒度管理,不同 Consumer Group 之间消费进度彼此不受影响,即消息 A 被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。
Topic主题
- 标识一类消息的逻辑名字,消息的逻辑管理单位。无论消息生产还是消费,都需要指定 Topic。
- 区分消息的种类;一个发送者可以发送消息给一个或者多个 Topic;一个消息的接收者可以订阅一个或者多个 Topic 消息
- 同Kafka topic
标签
- RocketMQ支持再发送时给topic打tag,同一个topic的消息虽然逻辑管理是一样的,但消费topic1时,如果你消费订阅的时候指定tagA,那么tagB消息不会订阅
消息队列
- 同kafka partation
- 简称 Queue 或 Q。消息物理管理单位。
- 一个 Topic 将有若干个 Q。若一个 Topic 创建在不同的 Broker,则不同的 broker 上都有若干 Q,消息将物理地 存储落在不同 Broker 结点上,具有水平扩展的能力。
- 无论生产者还是消费者,实际的生产和消费都是针对 Q 级别。例如 Producer 发送消息的时候,会预先选择(默认轮询)好该 Topic 下面的某一条 Q 发送;Consumer 消费的时候也会负载均衡地分配若干个 Q,只拉取对应 Q 的消息。
- 每一条 message queue 均对应一个文件,这个文件存储了实际消息的索引信息。并且即使文件被删除,也能通过实际纯粹的消息文件(commit log) 恢复回来。
消息堆积如何解决
- 提高消费能力
- 消费者扩容:如果当前Topic的Message Queue的数量大于消费者数量,就可以对消费者进行扩容,增加消费者,来提高消费能力,尽快把积压的消息消费玩。
- 消息迁移Queue扩容:如果当前Topic的Message Queue的数量小于或者等于消费者数量,这种情况,再扩容消费者就没什么用,就得考虑扩容Message Queue。可以新建一个临时的Topic,临时的Topic多设置一些Message Queue,然后先用一些消费者把消费的数据丢到临时的Topic,因为不用业务处理,只是转发一下消息,还是很快的。接下来用扩容的消费者去消费新的Topic里的数据,消费完了之后,恢复原状。
- 类似kafka的增加分区
顺序消息如何实现
- 顺序消息分为全局顺序消息和部分顺序消息
- 全局顺序消息指某个 Topic 下的所有消息都要保证顺序;
- 部分顺序消息只要保证每一组消息被顺序消费即可,比如订单消息,只要保证同一个订单 ID 个消息能按顺序消费即可。
- 订单场景为例,保证每个订单都保证创建、付款、完成的顺序,且每个订单不能互相串联
- 将不同订单的消息路由到不同的分区中。文档只是给出了Producer顺序的处理,Consumer消费时通过一个分区只能有一个线程消费的方式来保证消息顺序
- 同kafka,比如说我们建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。
- 全局顺序消息
- 要保证全局顺序消息, 需要先把 Topic 的读写队列数设置为 一,然后Producer Consumer 的并发设置,也要是一。简单来说,为了保证整个 Topic全局消息有序,只能消除所有的并发处理,各部分都设置成单线程处理 ,这时候就完全牺牲RocketMQ的高并发、高吞吐的特性了。
分布式事务
- 核心思路利用事务回查,即rocketmq会定时遍历commitlog中的半事务消息
- RocketMQ不能保证消息不重复,要再消费者端做好幂等性
半事务阶段
- 生产者发一条消息到rocketmq,但该消息只存在commitlog中,对消费者不可见
commit/rollback阶段
- 该阶段主要是把 prepared 消息保存到 consumeQueue 中,即让消费端可以看到此消息,也就是可以消费此消息。
- 如果是 rollback 就不保存
Kafka与Rocketmq的区别
Broker差异
- 主从差异
- kafka的master、slave是基于partition维度,leader同步给follower
- 而rocketmq是基于broker维度,master同步给salve
- 刷盘
- rocketmq支持同步刷盘,每次消息刷盘之后再返回
- kafka内部partation支持异步同步数据
- 数据写入
- kafka每个partition独占一个目录,每个partition均有数据文件.log,kafka的topic对应多个partition
- rocketmq是每个topic共享一个数据文件commitlog
Producer差异
- 发送方式
- kafka默认使用异步发送的形式,有一个memory buffer暂存消息,同时会将多个消息整合成一个数据包发送,这样能提高吞吐量,但对消息的实效有些影响;rocketmq可选择使用同步或者异步发送。
- 发送响应
- kafka的发送ack支持三种设置:消息存进memory buffer就返回;等到leader收到消息返回,等到leader和ISR的follower都收到消息返回,当然kafka都是异步刷盘。rocketmq都需要等broker的响应确认,有同步刷盘,异步刷盘,同步双写,异步双写等策略,相比于kafka多了一个同步刷盘。
Consumer差异
- 消息过滤
- rocketmq的queue和kafka的partition对应,但rocketmq的topic还能更加细分,可对消息加tag,同时订阅时也可指定特定的tag来对消息做更进一步的过滤。
- 有序消息
- rocketmq支持全局有序和局部有序,kafka也支持有序消息,但是如果某个broker宕机了,就不能在保证有序了
- 消费确认
- rocketmq仅支持手动确认,也就是消费完一条消息ack+1,会定期向broker同步消费进度,或者在下一次pull时附带上offset。kafka支持定时确认,拉取到消息自动确认和手动确认,offset存在zookeeper上
- 事务支持
- rocketmq利用事务回查实现分布式事务
- kafka不支持