上面講了訊息到記憶體的過程,為了訊息不丟失,是需要持久化到磁碟上的,這裡又分為同步刷屏和非同步刷屏。
在記憶體裡處理後,就開始釋放鎖,處理完的結果叫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。