《从零开始带你成为消息中间件实战高手》 笔记四

一、第四十九课  生产者是如何发送消息的

1、Topic、MessageQueue、Broker之间的关系

一个Topic可以分布在多个Broker上,所以Topic的数据是分布式存储在多个Broker机器上的 

创建Topic的时候要指定MessageQueue的数量。MessageQueue是非常关键的一个数据分片机制,它将Topic的数据拆成了很多个数据分片,然后在每个Broker上存储了一些MessageQueue,通过这个方法,实现了Topic的分布式存储

《从零开始带你成为消息中间件实战高手》 笔记四_第1张图片

 

2、生产者写入

生产者会从NameServer获取Topic的路由数据,知道一个Topic有几个MessageQueue,分别在哪个Broker机器上,现在先假定均匀写入每个MessageQueue。当一个Master Broker挂了,Slave Broker会切换成Master Broker,在切换的过程中,这个Master Broker就会访问失败,所以建议在生产者中设置一个开关:sendLatencyFaultEnable。打开这个开关后,它就有容错机制,比如某次访问某个Broker时间超过500ms,那么在接下来的一定时间内,就不会再访问这个Broker,等这段时间过了,Slave Broker已经切换成Master Broker了,那么又能让生产者访问了

《从零开始带你成为消息中间件实战高手》 笔记四_第2张图片

二、第五十一课  Broker是如何持久化存储消息的

Broker接收到消息后,顺序写入磁盘上名为CommitLog的日志文件,这个CommitLog文件就像LogBack日志文件一样,每个文件最多1G

《从零开始带你成为消息中间件实战高手》 笔记四_第3张图片

我们之前提过,Topic在这台Broker机器上会有几个MessageQueue,而一个MessageQueue,也有很多的ConsumeQueue文件,存储目录是{HOME}/stoe/consumequeue/{topicId}/{queueId}/{fileName}下,这个文件存储的是一条信息对应在CommitLog里的物理地址,即偏移量offset,还包括了消息长度、tag hashcode,一条数据是20个字节,每个ConsumeQueue文件保存30万条数据,大概是5.72MB

《从零开始带你成为消息中间件实战高手》 笔记四_第4张图片

那么写入CommitLog的速度就直接影响了MQ的性能,所以MQ是基于OS系统的PageCache和顺序写两个机制,来提升写入性能的

顺序写就是上面提到的,在CommitLog的尾部追加数据。而PageCache,是在数据写入CommitLog时,不是直接写入底层的物理磁盘文件的,而是先写入OS的pageCache内存缓存中,然后后续由OS的后台线程自己找一个时间,异步将OS的pageCache缓存中的数据刷新到磁盘文件中

《从零开始带你成为消息中间件实战高手》 笔记四_第5张图片

使用PageCache被称作异步刷盘,因为数据写入PageCache就被视作写入成功,当Broker宕机时,这些数据就会消失,因此异步刷盘适合高吞吐量的环境,但存在数据丢失风险。另一种模式被称作同步刷盘,broker必须把消息写入硬盘内,才视作写入成功

总结: 一个Broker上可以有多个Topic,但都存储在统一的CommitLog中。一个Topic分布在多个Broker上,一个Topic分片内有多个MessageQueue,一个MessageQueue对应多个ConsumeQueue文件

《从零开始带你成为消息中间件实战高手》 笔记四_第6张图片

三、第五十三课  基于DLedger技术的Broker主从同步原理到底是什么

在使用DLedger前,RocketMQ的主从Broker模式,如果主Broker挂了,那么只能通过手动方式来进行重启或切换,而引入DLedger就是为了实现自动切换。DLedger是基于Raft协议的,使用DLedger CommitLog替代了原来的CommitLog

《从零开始带你成为消息中间件实战高手》 笔记四_第7张图片

Raft协议的多副本同步机制

简单来说,数据同步会分为uncommitted阶段和committed阶段。首先Leader Broker上的DLedger收到一条数据后,会标记为uncommitted状态,然后它会通过自己的DLedgerServer组件把这个uncommitted数据发送给Follower Broker的DLedgerServer。接着Follower Broker的DLedgerServer收到uncommitted消息之后,必须返回一个ack给Leader Broker的DLedgerServer,然后如果Leader Broker收到超过半数的的Follower Broker返回ack后,就将消息标记为committed状态。然后Leader Broker就把committed消息也发给Follower Broker的DLedgerServer,让它们也把消息标记为committed状态

《从零开始带你成为消息中间件实战高手》 笔记四_第8张图片

如果Leader Broker挂了,剩下的两个Follower Broker就会重新选举出新的Leader Broker,并且会对没有完成的数据同步进行一些恢复性操作,保证数据不丢失

《从零开始带你成为消息中间件实战高手》 笔记四_第9张图片

四、第五十五课  消费者是如何获取消息处理以及进行ACK的

1、消费者组

给一组消费者起一个名字,它们会消费同一个Topic中的内容。

生产者生产一条消息后,一个消费者组的多台机器都能消费到这条消息吗?在集群模式下,不能,只有其中一台能消费到。在广播模式下,都可以消费到,但广播模式基本不使用。

如下图所示,库存系统和营销系统就是2个消费者组,它们订阅了同一个Topic,所以都可以获取到这个Topic生产的消费信息,但各自系统中只有一个机器可以获取到这条信息。

《从零开始带你成为消息中间件实战高手》 笔记四_第10张图片

2、MessageQueue与消费者的关系

大致理解为,让一个Topic内的多个MesageQueue均匀分摊给消费者组内的多个机器去消费。基本原则是一个MessageQueue只能有一个消费者机器消费,但一个消费者机器可以消费多个MesageQueue

3、Broker是如何将消息读取出来给消费者的

假设一台消费者机器要拉去MessageQueue0的消息,并且之前从没拉过,那就从第一条开始拉。于是,Broker找到MessageQueue0对应的ConsumeQueue0,找到第一条消息的offset,去CommitLog中读取出来这条数据

《从零开始带你成为消息中间件实战高手》 笔记四_第11张图片

 

《从零开始带你成为消息中间件实战高手》 笔记四_第12张图片

消费者机器获取到这些消息后,会调用我们的回调函数,如图所示,返回消费状态为成功

《从零开始带你成为消息中间件实战高手》 笔记四_第13张图片

等我们处理完后,消费者机器会提交我们目前的消费进度到Broker机器上,然后Broker会存储我们的消费进度

《从零开始带你成为消息中间件实战高手》 笔记四_第14张图片

4、如果消费者组中有机器宕机了怎么办

会重新给消费者机器分配它们要处理的MessageQueue

五、第五十七课  消费者是根据什么策略从Master或Slave上拉取消息的

1、ConsumeQueue文件也是基于os cache的

ConsumeQueue文件很小,只有几MB,所以它们基本都是放在os cache里的,以此保证消费的高性能

2、CommitLog文件是基于os cache和硬盘一起读的

CommitLog是先写入os cache,再由os把cache中比较旧的数据写入到硬盘,这个过程是不断持续的。因此,如果读取的是刚刚写入的CommitLog数据,那么它们大概率还在os cache中,这样性能就很快。如果读的是较早的数据,那么就都在硬盘中的,这样的效率就会变慢。因此,如果你的消费速度跟上了生产速度,那么基本都是从os cache中取的数据,否则大概率是从磁盘取的。

3、Master Broker什么时候会让你从Slave Broker拿数据

Master broker会根据自身内存的大小,最多可以在os cache存放的数据量,你需要的数据量,来判断出会不会对自己造成比较大的负担,从而决定要不要让你去Slave Broker上拉取数据。

比如你要8万条数据,但Master Broker的os cache最多存3万条,有5万条就要从硬盘上拉取,这样会影响Master Broker的性能,所以会让你去Slave Broker上拉。

六、第六十一课  探索黑科技,基于mmap内存映射实现磁盘文件的高性能读写

传统IO方式读取文件数据,发生了2次数据拷贝

《从零开始带你成为消息中间件实战高手》 笔记四_第15张图片

基于mmap+PageCache的读写。比如要写入消息到CommitLog文件里,先把一个CommitLog文件通过MappedByteBuffer的map()函数映射其地址到你的虚拟内存地址。然后对这个MappedByteBuffer执行写入操作,写入的时候会直接进入PageCache,然后过一段时间,由os的线程异步刷入磁盘中。这样就只有一次拷贝过程,就是从PageCache拷入到磁盘空间而已

预热映射机制+文件预热机制

《从零开始带你成为消息中间件实战高手》 笔记四_第16张图片

七、阶段性复习

《从零开始带你成为消息中间件实战高手》 笔记四_第17张图片

《从零开始带你成为消息中间件实战高手》 笔记四_第18张图片

 

思考题

1、Kafka和RabbitMQ有类似RocketMQ的分片机制吗,它们是如何实现的?

 

2、基于Raft协议的主从复制,会对Leader Broker的TPS产生影响吗?是不是必须所有场景都这么做?

 

3、消费者是跟少数几台Broker建立连接,还是跟所有Broker建立连接?

 跟少数Broker建立长连接,只有要消费指定Topic下MessageQueue对应的Broker时,才会建立连接

4、Kafka和RabbitMQ支持主从架构的读写分离吗?支持Slave Broker的读取吗?

 

5、比如数据刚刚到Master Broker,还没到Slave Broker,导致Master Broker和Slave Broker数据不一致怎么办?

会存在主从不同步 

6、消费处理太慢,会导致你跟不上生产的速度,会导致后续都从硬盘上拉取数据,所以在处理消息的时候,有什么要注意的?

 

 

 

 

你可能感兴趣的:(RocketMQ,中间件)