上面讲了消息到内存的过程,为了消息不丢失,是需要持久化到磁盘上的,这里又分为同步刷屏和异步刷屏。
在内存里处理后,就开始释放锁,处理完的结果叫result。所以到了刷屏的阶段,可能会有一个或者多个的result需要处理。
同步刷盘
同步刷盘的服务,也是一个线程,专门用来处理这些result。他维护着requestsWrite和requestsRead的链表。requestsWrite是放需要处理的result,requestsRead是放准备处理的result。
每个result需要同步刷盘服务处理的时候,都会放入requestsWrite,由于requestsWrite并不是线程安全的,所以这里也需要加锁和释放锁的操作。
上面提过,这个服务也是一个线程,这个线程就是用来处理requestsRead的。
这个线程每处理完requestsRead就会等待最多10ms的时间,直至被重新唤醒。
所以requestsWrite有数据的时候,就会唤醒这个线程,这个线程就会把requestsWrite和requestsRead里的数据进行交换。
由于写入requestsWrite是并发的,所以交换的时候,可能会有多个result到requestsRead里。
交换完后,就开始把requestsRead里的数据进行落盘,这个线程并不影响requestsWrite的写入。
异步刷盘
异步刷盘,简单的说,就是不等落盘就直接返回。
同样的,异步刷盘也有一个线程的服务,每隔一段时间就开始进行刷盘。但是这里也有一个小区别,就是是否开启堆外内存机制。
如果没有开启,那消息是追加到与物理文件映射的内存中,然后写入到磁盘。
如果开启了,那会创建一个一个commitlog一样大小的堆外内存,所以消息会追加到这个堆外内存中,然后是提交到与物理文件映射的内存中,最后写入到磁盘。
mmap内存映射
为了提高性能,RocketMQ通过内存映射文件来提高IO访问性能。
所谓内存映射,就是物理地址和内存地址做了一个映射,实际上并没有把数据拷贝到内存中。
内存映射是有大小限制的,在1.5到2G之间,所以Commitlog的文件大小为1G,ConsumeQueue的文件大小为5.72M。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。