上面讲了消息到内存的过程,为了消息不丢失,是需要持久化到磁盘上的,这里又分为同步刷屏和异步刷屏。

在内存里处理后,就开始释放锁,处理完的结果叫result。所以到了刷屏的阶段,可能会有一个或者多个的result需要处理。

image.png

同步刷盘

同步刷盘的服务,也是一个线程,专门用来处理这些result。他维护着requestsWrite和requestsRead的链表。requestsWrite是放需要处理的result,requestsRead是放准备处理的result。

image.png

每个result需要同步刷盘服务处理的时候,都会放入requestsWrite,由于requestsWrite并不是线程安全的,所以这里也需要加锁和释放锁的操作。

image.png

上面提过,这个服务也是一个线程,这个线程就是用来处理requestsRead的。

这个线程每处理完requestsRead就会等待最多10ms的时间,直至被重新唤醒。

所以requestsWrite有数据的时候,就会唤醒这个线程,这个线程就会把requestsWrite和requestsRead里的数据进行交换。

由于写入requestsWrite是并发的,所以交换的时候,可能会有多个result到requestsRead里。

image.png

交换完后,就开始把requestsRead里的数据进行落盘,这个线程并不影响requestsWrite的写入。

异步刷盘

异步刷盘,简单的说,就是不等落盘就直接返回。

同样的,异步刷盘也有一个线程的服务,每隔一段时间就开始进行刷盘。但是这里也有一个小区别,就是是否开启堆外内存机制。

如果没有开启,那消息是追加到与物理文件映射的内存中,然后写入到磁盘。

如果开启了,那会创建一个一个commitlog一样大小的堆外内存,所以消息会追加到这个堆外内存中,然后是提交到与物理文件映射的内存中,最后写入到磁盘。

mmap内存映射

为了提高性能,RocketMQ通过内存映射文件来提高IO访问性能。

所谓内存映射,就是物理地址和内存地址做了一个映射,实际上并没有把数据拷贝到内存中。

内存映射是有大小限制的,在1.5到2G之间,所以Commitlog的文件大小为1G,ConsumeQueue的文件大小为5.72M。


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆