<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          圖文并茂!深入了解RocketMQ的內(nèi)存映射機(jī)制

          共 3602字,需瀏覽 8分鐘

           ·

          2022-05-18 13:35

          大家好,我是Leo。

          今天聊一下RocketMQ的內(nèi)存映射機(jī)制

          傳統(tǒng)文件IO機(jī)制

          假如沒有使用mmap技術(shù)的時(shí)候,使用最傳統(tǒng)和基本的普通文件進(jìn)行io操作會(huì)產(chǎn)生數(shù)據(jù)多拷貝問題。比如從磁盤上把數(shù)據(jù)讀取到內(nèi)核IO緩沖區(qū)里面,然后再從內(nèi)核IO緩沖區(qū)中讀取到用戶進(jìn)程私有空間里去,然后我們才能拿到這個(gè)數(shù)據(jù)。

          如上圖顯示,可以明顯的看出數(shù)據(jù)被拷貝了兩次,這樣肯定對磁盤讀性能是有影響的。同樣的如果想給磁盤中寫內(nèi)容,也是得先從用戶進(jìn)程的私有空間把數(shù)據(jù)拷貝到內(nèi)核IO緩沖區(qū),然后從內(nèi)核IO緩沖區(qū)再拷貝到磁盤文件。

          內(nèi)存映射機(jī)制

          優(yōu)化

          后續(xù)雖然基于磁盤的順序?qū)懣梢詷O大提高 IO 的寫效率,但是基于文件的存儲(chǔ)采用多拷貝方式。在性能提升上會(huì)很有限,RocketMQ 引入了內(nèi)存映射,將磁盤文件映射到內(nèi)存中,以操作內(nèi)存的方式操作磁盤,性能又提升了一個(gè)檔次。

          所謂的這個(gè)內(nèi)存映射是什么意思呢。看見這個(gè)內(nèi)存映射有的人可能就會(huì)認(rèn)為是把磁盤文件的數(shù)據(jù)讀取到內(nèi)存里面,其實(shí)這不完全正確。因?yàn)樵趧傞_始建立映射的時(shí)候,并沒有任何的數(shù)據(jù)拷貝操作,其實(shí)磁盤文件還是停留在哪里,只不過就是它把?物理磁盤上的一些地址和用戶進(jìn)程私有空間的一些虛擬內(nèi)存地址進(jìn)行了一個(gè)映射。這個(gè)映射的過程就是JDK下面的NIO包里面的MapperByteBuffer的map函數(shù)干的事情,底層就是基于mmap技術(shù)實(shí)現(xiàn)的。

          這個(gè)mmap技術(shù)在地址映射的過程中對文件的大小是有限制的,在1.5G~2G之間,所以RocketMQ就會(huì)把單個(gè)的commitLog文件大小控制在1GB,consumeQueue文件大小控制在5.72MB,這樣就在讀寫的時(shí)候,方便的進(jìn)行內(nèi)存映射了。

          在 JAVA 中可通過 FileChannel 的 map 方法創(chuàng)建內(nèi)存映射文件。如下圖所示

          在 Linux 服務(wù)器中由該方法創(chuàng)建的文件使用的就是操作系統(tǒng)的 pagecache,即頁緩存。

          Linux 操作系統(tǒng)中的內(nèi)存使用策略時(shí)會(huì)盡可能地利用機(jī)器的物理內(nèi)存,并常駐內(nèi)存中,就是所謂的頁緩存。在操作系統(tǒng)的內(nèi)存不夠的情況下,采用緩存置換算法,例如 LRU 將不常用的頁緩存回收,即操作系統(tǒng)會(huì)自動(dòng)管理這部分內(nèi)存。

          如果 RocketMQ Broker 進(jìn)程異常退出,存儲(chǔ)在頁緩存中的數(shù)據(jù)并不會(huì)丟失,操作系統(tǒng)會(huì)定時(shí)將頁緩存中的數(shù)據(jù)持久化到磁盤,做到數(shù)據(jù)安全可靠。不過如果是機(jī)器斷電等異常情況,存儲(chǔ)在頁緩存中的數(shù)據(jù)就有可能丟失。

          實(shí)現(xiàn)

          磁盤文件和用戶進(jìn)程私有空間的一些虛擬內(nèi)存地址進(jìn)行映射之后,我們就可以對這個(gè)已經(jīng)映射到內(nèi)存里的磁盤文件進(jìn)行讀寫了,比如要寫入commitLog文件,就會(huì)先把commitlog文件通過MapperByteBuffer的map函數(shù)映射起地址到你的虛擬內(nèi)存地址。接著可以對這個(gè)mapperByteBuffer執(zhí)行寫入操作,寫入的時(shí)候會(huì)直接寫入到pagecache中,然后過一段時(shí)間,由os的線程異步刷入到磁盤中。

          此時(shí)我們看上面的圖是不是就會(huì)發(fā)現(xiàn)只有一次數(shù)據(jù)的拷貝,這樣是不是性能就有所提高了呢。這就是基于mmap技術(shù)相比傳統(tǒng)io操作的一個(gè)性能優(yōu)化。接著如果我們從磁盤上讀取數(shù)據(jù)的時(shí)候,就會(huì)先在pagecache中判斷一些緩沖中是否有數(shù)據(jù),如果有就直接讀取了。比如剛剛把數(shù)據(jù)寫入commiglog中,此時(shí)consumer就從里面直接消費(fèi)數(shù)據(jù),那基本pagecache中肯定會(huì)有該數(shù)據(jù),哪怕如果沒有,此時(shí)就會(huì)從磁盤文件中加載數(shù)據(jù)到pagecache中,而且pagecache在加載數(shù)據(jù)的時(shí)候,還會(huì)把你要?加載的數(shù)據(jù)塊臨近的其他數(shù)據(jù)塊也一起加載到pagecache里去。

          源碼

          RocketMQ的內(nèi)存映射機(jī)制的幾個(gè)重要類

          • MappedFile 映射文件
          • MappedFileQueue 映射文件隊(duì)列
          • AllocateMappedFileService 創(chuàng)建MappedFile核心類

          MappedFileQueue 是MappedFile的管理容器,MappedFileQueue是對存儲(chǔ)目錄的封裝,該目錄下會(huì)存在多個(gè)內(nèi)存映射文件(mappedFile)。

          • storePath:存儲(chǔ)目錄
          • mappedFileSize:單個(gè)文件的存儲(chǔ)大小
          • mappedFiles:MappedFile文件集合
          • allocateMappedFileService:創(chuàng)建MappedFile服務(wù)類
          • flushedWhere:當(dāng)前刷盤指針,表示該指針之前的所有數(shù)據(jù)全部持久化到硬盤
          • committedWhere:當(dāng)前數(shù)據(jù)提交指針,內(nèi)存中byteBuffer當(dāng)前的寫指針,該值大于等于】flushedWhere

          MappedFile初始化(init)

          transientStorePoolEnable為true 表示內(nèi)容先存儲(chǔ)在堆外內(nèi)存,然后通過 Commit 線程將數(shù)據(jù)提交到內(nèi)存映射Buffer中,再通過 Flush 線程將內(nèi)存映射 Buffer 中的數(shù)據(jù)持久化到磁盤中

          MappedFile提交(commit)

          內(nèi)存映射文件的提交動(dòng)作由 MappedFile的commit 方法實(shí)現(xiàn):執(zhí)行提交操作, commitLeastPages 為本次提交最小的頁數(shù),如果待提交數(shù)據(jù)不滿 commitLeastPages ,則不執(zhí)行本次提交操作,待下次提交。writeBuffer 如果為空,直接返回 wrotePosition 指針 ,無須執(zhí)行 commit 操作, 表明commit 操作主體是 writeBuffer.

          判斷是否執(zhí)行commit操作。如果文件已滿返回true;如果commitLeastPages大于0,則比較 wrotePosition (當(dāng)前 writeBuffe 的寫指針)與上一次提交的指針(committedPosition) 的差值,除以 OS_ PAGE_ SIZE 得到當(dāng)前臟頁的數(shù)量,如果大于 commitLeastPages 則返回 true ;如果 commitLeastPages小于0 表示只要存在臟頁就提交

          MappedFile刷盤(flush)

          刷盤是指將內(nèi)存中數(shù)據(jù)刷寫到磁盤,永久存儲(chǔ)到磁盤中,其具體實(shí)現(xiàn)由mappedFile的flush方法實(shí)現(xiàn):刷寫磁盤,直接調(diào)用 mappedByteBuffer或者 fileChannel的 force 方法將內(nèi)存中的數(shù)據(jù)持久化到磁盤,那么 flushedPosition 應(yīng)該等于 MappedByteBuffer 中的寫指針;如果 writeBuffer 不為空, 則flushedPosition 應(yīng)等于上一次 commit 指針;因?yàn)樯弦淮翁峤坏臄?shù)據(jù)就是進(jìn)入到 MappedByteBuffer 中的數(shù)據(jù);如 writeBuffer 空,數(shù)據(jù)是直接進(jìn)入到 MappedByteBuffer, wrotePosition 代表的是 MappedByteBuffer 中的指針,故設(shè)置 flushedPosition 為wrotePosition。

          獲取MappedFile最大讀指針(getReadPositon)

          RockketMQ文件的一個(gè)組織方式是內(nèi)存映射方式,預(yù)先申請一塊連續(xù)的固定大小的內(nèi)存,需要一套指針標(biāo)識(shí)當(dāng)前最大有效數(shù)據(jù) 的位置。獲取當(dāng)前文件最大的可讀指針。如果 writeBuffer為空, 則直接返回當(dāng)前的寫指針;如果 writeBuffer 不為空, 則返回上一次提交的指針。在MappedFile 設(shè)計(jì)中,只有提交了的數(shù) 據(jù)(寫入到 MappedByteBuffer FileChannel 中的數(shù)據(jù) )才是安全的數(shù)據(jù)。

          MappedFile銷毀

          關(guān)閉mappedFile,釋放掉資源,并關(guān)閉文件通道,刪除物理文件。

          TransientStorePool

          TransientStorePool:短暫的存儲(chǔ)池。RocketMQ單獨(dú)創(chuàng)建一個(gè)MappedByteBuffer內(nèi)存緩存池,用來臨時(shí)存儲(chǔ)數(shù)據(jù),數(shù)據(jù)先寫入該內(nèi)存映射中,然后由commit線程定時(shí)將數(shù)據(jù)從該內(nèi)存復(fù)制到與目的物理文件對應(yīng)的內(nèi)存映射中。RokcetMQ引入該機(jī)制主要的原因是提供一種內(nèi)存鎖定,將當(dāng)前堆外內(nèi)存一直鎖定在內(nèi)存中,避免被進(jìn)程將內(nèi)存交換到磁盤。

          往期推薦

          2022年文章目錄整理

          RocketMQ性能提升

          圖文并茂!深入理解RocketMQ的刷盤機(jī)制

          圖文并茂!深入了解RocketMQ的過期刪除機(jī)制

          結(jié)尾

          本篇文件介紹了RocketMQ的內(nèi)存映射機(jī)制,從傳統(tǒng)的多拷貝模式,后來的磁盤順序?qū)懙膬?yōu)化。最終采用 mmap+ page cache 技術(shù)實(shí)現(xiàn)高性能的文件讀寫。

          學(xué)習(xí)途中感謝?簡書作者:G__yuan?和?簡書作者:mingxungu

          非常歡迎大家加我個(gè)人微信有關(guān)后端方面的問題我們在群內(nèi)一起討論!?我們下期再見!

          歡迎『點(diǎn)贊』、『在看』、『轉(zhuǎn)發(fā)』三連支持一下,下次見~



          瀏覽 48
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本黄色片网址 | 国产九色| 99鲁鲁精品秘 一区二区三区 | 国产精品福利一区二区 | 亚洲在线黄片 |