一、MMDB簡介
MMDB(MaxMind Database) 是MaxMind推出的一個資料儲存和檢索的資料庫格式,用於旗下針對IP檢索和儲存的Geo產品。
IP格式由二進位制位元陣列組成,很容易想到每個位元對應二元樹一個節點,可以說二元樹檢索特別適合於IP格式。
MMDB的構造過程正是把一顆資料位於葉子節點的二元樹進行序列化。
序列化後是位元組陣列,和其他檢索格式都是反序列化為結構化的記憶體形式不同,MMDB檢索時把整個mmdb檔案載入為一個位元組陣列即可。
檢索過程在位元組陣列上操作,由於每個節點大小固定,通過簡單記憶體計算即可完成節點定位,不需要額外生成其他中間結構,可以說非常簡潔和高效。
Maxmind的GeoIP產品用於檢索以下網段的geo資訊,其中最左一列是網段,第二列是geoname_id。根據網段找到geoname_id,再根據geoname_id找到下圖的資料。
二、構造過程
構造過程是生成一顆二叉檢索樹的過程。
假設只儲存一個網段「110」的資料,則可以得到二元樹為:
三、MMDB總體格式
二元樹經過序列化會得到一個位元組陣列,資料格式如下圖:
節點序列儲存二元樹的節點,資料資訊則儲存在資料序列中,資料使用MMDB序列化格式(類似json)。
第三部分為後設資料,儲存版本號、生成時間、資料庫型別、IP版本、語言、節點個數、節點記錄規格等。檢索過程需要使用這些進行記憶體定址來完成節點位置的計算。
第一個分隔符為16位元組的"NULL",即16個0。
第二個分隔符為"\xAB\xCD\xEFMaxMind.com"。
四、節點序列說明
節點序列等於一個節點陣列,每個節點由兩個記錄組成,分別對應二元樹的左孩子和右孩子。
在IP檢索中,位元0對應第一個記錄,位元1對應第二個記錄。
如上圖所示,包含3個節點,第一個節點的兩個記錄為3和1,第二個節點為3和2,第三個節點為19和3。
當記錄數等於節點數3時,表示沒找到資料。當記錄數大於節點數3時,則為資料節點的記錄值。
資料偏移量的計算公式:資料偏移量 = 記錄值 - 節點個數 - 16(分隔符的長度)。
第三個節點記錄19表示資料偏移量為0,19-3(節點數)-16。
五、檢索演演算法
在一個總節點數為3的mmdb資料庫上,網段「110」的檢索過程
六、資料段說明
資料序列由資料頭和資料組成,資料頭記錄資料型別和資料大小,目前MMDB支援多種資料型別,包括int, string, map, bytes等。
程式讀到位元組陣列後通過反序列化得到實際資料。
七、實驗例子
1、構造一個網段為「192.2.10.0/3」,對應二進位制網路「110」的節點,資料為{"iso":156,"country_name":"China"},生成的節點序列為:
注意:上圖每三個位元組儲存一個記錄,中間16個0是分隔符。格式化列印後得到下圖,符號「-」表示空節點:
可以看到「110」網段根據二元樹檢索演演算法得到資料段的偏移量19,則資料段偏移量為19-3(節點數)-16=0。
2、再加入一個網段為「64.2.10.0/3」,對應二進位制網路「010」的節點,資料為{"iso":826,"country_name":"England"},生成的節點序列為:
可以看到「010」網段根據二元樹檢索演演算法得到資料段的偏移量21,則資料段偏移量為21-5(節點數)-16=0。而此時「110」網段的資料段的偏移量變成了50,則資料段偏移量為50-5(節點數)-16=29。
八、總結
1、生成過程使用二元樹。
2、儲存和檢索都是序列化位元組陣列格式。
3、MMDB是記憶體資料庫 。
參考連結
MaxMind DB File Format Specification
Enriching MMDB files with your own data using go
Building your own MMDB database for fun and profit