?? Java学习:Java从入门到精通总结
?? 深入浅出RocketMQ设计思想:深入浅出RocketMQ设计思想
?? 绝对不一样的职场干货:大厂最佳实践经验指南
?? 最近更新:2022年5月14日
?? 个人简介:通信工程本硕??、Java程序员??。做过科研,发过专利,优秀的程序员不应该只是CRUD
?? 点赞 ?? 收藏 留言 ?? 都是我最大的动力!
文章目录
RocketMQ 总体架构
上图里的虚线表示数据同步过程,目的是保证数据的最终一致性。
从上图可以看出,RabbitMQ使用了一个注册中心作为发现与注册服务器,Producer
向Broker
发送消息,Consumer
从Broker
处接收消息,Broker
使用主从结构来进行消息的存储(为了方便理解,我画了最经典的一主三从结构)。
接下来,我们将对每一个部分做更详细的拆解分析。
注册中心
在RocketMQ里,注册中心使用的是nameserver
,原因是它具有稳定性高的特点,集群部署时单台nameserver
挂掉并不会影响其它的,即使全部nameserver
挂掉,也可以使用最近一次的注册信息来提供服务,不影响整体业务。
nameserver
不会有频繁的读写,所以性能开销很少,稳定性也高。
在RocketMQ里,注册中心每隔10s会扫描一次所有的Broker
,如果发现某个Broker
已经连续2min没有发送心跳过来了,就认为其挂了,断开连接。此时注册中心会更新Topic
与队列的对应关系,但不会通知Producer
和Consumer
。
Broker 架构
Broker
通常以集群的形式运行,存储Producer
发来的消息。
与注册中心的交互:
- 每个
Broker
和所有的注册中心保持长连接 - 每30s向注册中心发送心跳,心跳里面有自身的
Topic
信息
负载均衡设计:
Broker
和Topic
是多对多的关系,一个Topic
会分布在多个Broker
上,一个Broker
里也会有多个Topic
- 如果某个
Topic
收到的消息很多,则应该给它配置多个队列,并让这些队列尽量平均分在多个Broker
上
高可用设计:
RocketMQ采用主从结构来保证高可用,Master负责消息的写入,多个Slave负责消息的读取,Slave定期从Master处同步数据,保证最终一致性,如果Master挂了,可以由Slave继续提供度服务,并重新投票选举出新的Master。
这里有两个关键细节需要注意:
- 一旦
Broker
挂了,由于RocketMQ的心跳机制实现细节,Producer
和Consumer
最多30s才能够发现,在这一段时间里,发往这个Broker的消息都会发送失败,并且也没有办法消费消息 - RocketMQ保证的是最终一致性,所以会出现有一部分数据没来得及同步给Slave,Master就挂了的情况,但一旦Master回复之后,就又可以重新同步不一致的数据
高可靠设计:
- 所有收到的消息都会有同步和异步的刷盘机制,也就是将数据保存在硬盘上,可靠性很高
- 同步刷盘时,只有写入成功了才会返回成功
- 异步刷盘时,只有服务器宕机了才会丢失数据,这个概率是非常小的
读写性能:
- 使用了Linux系统的特性:以文件内存映射方式操作文件,避免read/write用户态和核心态的多次切换,性能很高
- 使用了顺序写IO,也会提高效率
- 读写分离,极大程度的缓解写锁和读锁的争用
除此之外,RocketMQ还提供了其他的功能及特性。
消息清理:
- 清理时机:默认是每天凌晨4点,或者磁盘空间不足时清理
- 磁盘空间阈值:默认阈值是85%,也就是当磁盘空间被占了超过85%之后会触发清理过程
- 消息写入磁盘文件后默认保存时间是72h
对此,我们也可以总结一下RocketMQ对服务器的硬件要求:
- 内存占用高
- 属于IO密集型应用,这种应用的特点是CPU附在高但使用率较低,大部分时间是在等待IO操作
- 硬盘要求高,这样数据持久化就会很快
消费者架构
与注册中心的交互:
- 一个
Consumer
与注册中心的一台服务器保持长连接,并且会定时查询MQ的Topic
配置信息,如果当前注册中心的服务器宕机,Consumer
会自动与下一台服务器连接 - 在保持长连接的情况下,
Consumer
每30s获取一次配置中心的所有Topic
配置信息,如果某个Broker
宕机,Consumer
最多需要30s可以从配置中心感知到(如果读消息多次失败也可以感知到)
与Broker
的交互:
Consumer
及与之关联的Broker
之间保持长连接Consumer
默认每隔30s向与之关联的Broker
发送心跳;Broker
每10s扫描所有的长连接,如果某个连接2min内没有发送心跳数据,则关闭连接,并且通知消费者组里的其他消费者重新按照策略分配队列消费
负载均衡设计:
- 一个
Consumer
集群里的每个Consumer
只消费一个队列,如果某个Consumer
挂了,则他的任务会被同组内Consumer
接替
消费消息过程:
- RocketMQ采用拉模型,
Consumer
不断拉取消息到本地来消费。拉取消息和消费消息是一个异步操作,所以就需要一个数据结构来存储拉下来的消息,这就是本地队列 - 默认每隔5s,RocketMQ就会将各个队列的消息消费进度存储到对应的
Broker
上 - 消费者拉取队列里的消息时,会将消息拉取任务放在本地的线程执行队列里逐次执行,执行完毕后再将任务放到队尾,依次循环
生产者架构
与注册中心的交互:
- 一个
Producer
与注册中心的一台服务器保持长连接,并且会定时查询MQ的Topic
配置信息,如果当前注册中心的服务器宕机,Producer
会自动与下一台服务器连接 - 在保持长连接的情况下,
Producer
每30s获取一次配置中心的所有Topic
的最新队列情况,如果某个Broker
宕机,Producer
最多需要30s可以从配置中心感知到(如果写入消息多次失败也可以感知到)
与Broker
的交互:
Producer
及与之关联的Broker
之间保持长连接Producer
默认每隔30s向与之关联的Broker
发送心跳;Broker
每10s扫描所有的长连接,如果某个连接2min内没有发送心跳数据,则关闭连接