RocketMQ(3) 根據消息key查詢功能的實現: indexFile


三: indexFile

除了通過通常的指定Topic進行消息消費外,RocketMQ還提供了根據key進行消息查詢的功能。

該查詢是通過store目錄中的index子目錄中的indexFile進行索引實現的快速查詢。

這個indexFile中的索引數據是在如果包含了key的消息被生產者發送到Broker時寫入的。

如果消息中沒有包含key,則不會寫入。

1. 索引條目結構

每個Broker中會包含一組indexFile,每個indexFile都是以一個時間戳命名的(這個indexFile被創建時 的時間戳)。

每個indexFile文件由三部分構成:indexHeader,slots槽位,indexes索引數據。

每個 indexFile文件中包含500w個slot槽。而每個slot槽又可能會掛載很多的index索引單元。

indexFile的文件結構如下:

其中slots中的每個slot槽掛載的index索引單元都來源於indexes區中

1634476229766

indexHeader:

固定40個字節,其中存放着如下數據:

1634476334142

  • beginTimestamp:該indexFile中第一條消息的存儲時間
  • endTimestamp:該indexFile中最后一條消息存儲時間
  • beginPhyoffset:該indexFile中第一條消息在commitlog中的偏移量commitlog offset
  • endPhyoffset:該indexFile中最后一條消息在commitlog中的偏移量commitlog offset
  • hashSlotCount:已經填充有index的slot數量(並不是每個slot槽下都掛載有index索引單元,這 里統計的是所有掛載了index索引單元的slot槽的數量)
  • indexCount:該indexFile中包含的索引單元個數(統計出當前indexFile中所有slot槽下掛載的所有index索引單元的數量之和)

indexFile中最復雜的是Slots與Indexes間的關系。在實際存儲時,Indexes是在Slots后面的,但為了便於理解,將它們的關系展示為如下形式:

1634476565600

每條消息key的hash值 % 500w的結果即為slot槽位,然后該slot記錄此index索引單元的indexNo,根 據這個indexNo可以計算出該index單元在indexFile中的位置。

不過,該取模結果的重復率是很高的, 為了解決該問題,在每個index索引單元中增加了preIndexNo,用於指定該slot中當前index索引單元的前一個index索引單元。(如圖所示,每個index索引單元都記錄此slot的前一個索引單元)

而slot中始終存放的是其下最新的index索引單元的indexNo,這樣的話,只要找到了slot就可以找到其最新的index索引單元,而通過這個index索引單元就可以依次找到其之前的所有 index索引單元。

slot記錄的索引單元的indexNo是index索引單元在indexFile中的流水號,從0開始依次遞增。即在一個indexFile中所有indexNo是 以此遞增的。

indexNo在index索引單元中是沒有維護的,其是通過indexes中依次數出來的。

index索引單元默寫20個字節,主要存放某條消息key值和地址,其中存放着以下四個屬性:

1634477037948

  • keyHash:消息中指定的業務key的hash值
  • phyOffset:當前key對應的消息在commitlog中的偏移量commitlog offset
  • timeDiff:當前key對應消息的存儲時間與當前indexFile創建時間的時間差
  • preIndexNo:當前slot下當前index索引單元的前一個index索引單元的indexNo

2 indexFile的創建

indexFile的文件名為當前文件被創建時的時間戳。這個時間戳有什么用處呢?

根據業務key進行查詢時,查詢條件除了key之外,還需要指定一個要查詢的時間戳,表示要查詢不大於 該時間戳的最新的消息,即查詢指定時間戳之前存儲的最新消息。這個時間戳文件名可以簡化查詢,提高查詢效率。具體后面會詳細講解。

indexFile文件是何時創建的?其創建的條件(時機)有兩個:

  • 當第一條帶key的消息發送來后,系統發現沒有indexFile,此時會創建第一個indexFile文件

  • 當一個indexFile中掛載的index索引單元數量超出2000w個時,會創建新的indexFile。

當帶key的 消息發送到來后,系統會找到最新的indexFile,並從其indexHeader的最后4字節中讀取到 indexCount。若indexCount >= 2000w時,會創建新的indexFile。

由於可以推算出,一個indexFile的最大大小是:(40 + 500w * 4 + 2000w * 20)字節

3. 查詢流程

當消費者通過業務key來查詢相應的消息時,其需要經過一個相對較復雜的查詢流程。不過,在分析查詢流程之前,首先要清楚幾個定位計算公式:

式子1: 計算指定消息key的slot槽位序號:

​ slot槽位序號 = key的hash % 500w

式子2: 計算槽位序號為n的slot在indexFile中的起始位置:

​ slot(n)位置 = 40 + (n - 1) * 4

式子3: 計算indexNo為m的index在indexFile中的位置:

​ index(m)位置 = 40 + 500w * 4 + (m - 1) * 20

說明:

  • 40為indexFile中indexHeader的字節數
  • 500w * 4 是所有slots所占的字節數

具體查詢流程如下:

1634478632504

這里解釋一下為什么需要計算查詢時間和文件創建時間的差值, 並和 index 索引單元的timeDiff值做比較,

這兩個值都是記錄的和indexFile文件創建時間的差值,

所以如果 index 索引單元的timeDiff大於查詢時間的timeDiff,說明此index索引單元在需要查詢的時間之后創建的,即不滿足需要查詢的時間條件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM