设计理念
- 追求简单和速度
- NameServer简化,减少复杂度,提高速度;
- 高效的io存储,
- 简化系统,不保证消息只被消费一次,需要消费者自己做幂等;
核心模块
NameServer
NameServer采用了极简设计,节点之间不进行数据同步,因为即使NameServer不是强一致性,客户端也会通过重试避免故障。
整体工作流程如下:
- broker向所有NameServer注册路由元数据,每30秒更新一次
- NameServer每10秒发送一次心跳检测,如果超过120秒未收到反馈则移除该broker相关元数据
- NameServer收到broker发送的更新元数据,进行路由元数据和时间戳更新
消息发送
发送方式:同步、异步、oneway,其中oneway发送出去就返回,不能设置回调函数
整体流程
- 生产者创建并与MQClientInstance关联,后者负责同server之间的网络通信
- 从NameServer更新topic路由信息,并且每30秒定时刷新
- 如果没有该topic会请求默认topic的路由信息,在发送消息给broker的时候,broker会初始化该topic
- 发送前会检查消息体大小不能超过4M
- 选择可写的消息队列进行发送,同步消息发送失败可以进行重试,发送失败会更新broker的不可用延时,从而选择可用的broker进行发送,增加发送成功率
- 非oneway消息发送支持回调处理
- 支持批量消息发送
延时消息发送
- rocketmq只支持不同等级的延迟消息,不能支持精度的延时消息
- 生产者发送消息的delay-level>0,broker会更改主题为schedual_topic_xxx
- 然后根据延时等级,存入对应的ConsumeQueue
- 通过异步定时线程将消息全部取出,恢复消息的原主题,重新写入commitlog
- 实现粗略定时发送的目的
消息存储
整体工作流程如下:
- 存储消息的入口DefaultMessageStore::putMessage
- 校验:如果broker不支持写入,或者消息主题长度超过256个字符、属性长度超过65526个字符则拒绝写入
- 如果是延迟消息则更新消息的主题为延迟消息主题和队列为对应的延迟等级
- 获取当前可写入的commitlog,名称为当前偏移量,大小为1G
- 申请putMessageLock,串行化
- 如果第一次写入,则以偏移量0创建文件
- 写入MappedFile
- 生成消息id:4字节ip、4字节端口、8字节消息偏移量
- 获取消息的队列偏移量
- 计算消息的字节长度
- 如果消息+空闲字节数>commitlog空闲空间,则新建commitlog文件存储
- 更新消息逻辑队列的偏移量
- 释放putMessage锁
- 根据同步异步策略进行刷盘