小结一下
Producer 每 30s 会向 NameSrv 拉取路由信息更新本地路由表,有新的 Broker 就和其建立长连接,每隔 30s 发送心跳给 Broker 。
不要在生产环境开启 autoCreateTopicEnable。
Producer 会通过重试和延迟机制提升消息发送的高可用。
Broker
Broker 就比较复杂一些了,但是非常重要。大致分为以下五大模块,我们来看一下官网的图。
- Remoting 远程模块,处理客户请求。
- Client Manager 管理客户端,维护订阅的主题。
- Store Service 提供消息存储查询服务。
- HA Serivce,主从同步高可用。
- Index Serivce,通过指定key 建立索引,便于查询。
有几个模块没啥可说的就不分析了,先看看存储的。
Broker 的存储
RocketMQ 存储用的是本地文件存储系统,效率高也可靠。
主要涉及到三种类型的文件,分别是 CommitLog、ConsumeQueue、IndexFile。
CommitLog
RocketMQ 的所有主题的消息都存在 CommitLog 中,单个 CommitLog 默认 1G,并且文件名以起始偏移量命名,固定 20 位,不足则前面补 0,比如 00000000000000000000 代表了第一个文件,第二个文件名就是 00000000001073741824,表明起始偏移量为 1073741824,以这样的方式命名用偏移量就能找到对应的文件。
所有消息都是顺序写入的,超过文件大小则开启下一个文件。
ConsumeQueue
ConsumeQueue 消息消费队列,可以认为是 CommitLog 中消息的索引,因为 CommitLog 是糅合了所有主题的消息,所以通过索引才能更加高效的查找消息。
ConsumeQueue 存储的条目是固定大小,只会存储 8 字节的 commitlog 物理偏移量,4 字节的消息长度和 8 字节 Tag 的哈希值,固定 20 字节。
在实际存储中,ConsumeQueue 对应的是一个Topic 下的某个 Queue,每个文件约 5.72M,由 30w 条数据组成。
消费者是先从 ConsumeQueue 来得到消息真实的物理地址,然后再去 CommitLog 获取消息。
IndexFile
IndexFile 就是索引文件,是额外提供查找消息的手段,不影响主流程。
通过 Key 或者时间区间来查询对应的消息,文件名以创建时间戳命名,固定的单个 IndexFile 文件大小约为400M,一个 IndexFile 存储 2000W个索引。
我们再来看看以上三种文件的内容是如何生成的:
消息到了先存储到 Commitlog,然后会有一个 ReputMessageService 线程接近实时地将消息转发给消息消费队列文件与索引文件,也就是说是异步生成的。
消息刷盘机制
RocketMQ 提供消息同步刷盘和异步刷盘两个选择,关于刷盘我们都知道效率比较低,单纯存入内存中的话效率是最高的,但是可靠性不高,影响消息可靠性的情况大致有以下几种:
- Broker 被暴力关闭,比如 kill -9
- Broker 挂了
- 操作系统挂了
- 机器断电
- 机器坏了,开不了机
- 磁盘坏了
如果都是 1-4 的情况,同步刷盘肯定没问题,异步的话就有可能丢失部分消息,5 和 6就得依靠副本机制了,如果同步双写肯定是稳的,但是性能太差,如果异步则有可能丢失部分消息。
所以需要看场景来使用同步、异步刷盘和副本双写机制。
页缓存与内存映射
Commitlog 是混合存储的,所以所有消息的写入就是顺序写入,对文件的顺序写入和内存的写入速度基本上没什么差别。
并且 RocketMQ 的文件都利用了内存映射即 Mmap,将程序虚拟页面直接映射到页缓存上,无需有内核态再往用户态的拷贝,来看一下我之前文章画的图。