PalDB 详解
轉(zhuǎn)自:http://www.jianshu.com/p/23db015e81a5
github:https://github.com/linkedin/PalDB
簡介
PalDB是 Linkedin 公司開源的一款只讀型的 KV 存儲(chǔ)數(shù)據(jù)庫,目的是在某些場(chǎng)景下替代 HashMap/HashSet 或 LevelDB,在性能和內(nèi)存之間做了一個(gè)良好的平衡。下面是官方給出的測(cè)試圖表:
讀的吞吐量是 leveldb 和 rocksdb 的5倍
內(nèi)存使用是 hashset 的1/6
使用方式
作為一個(gè)存儲(chǔ)工具包,其使用方式也很簡單,一看就會(huì)明白:
//寫數(shù)據(jù)
StoreWriter writer = PalDB.createWriter(new File("store.paldb"));
writer.put("foo", "bar");
writer.put(1213, new int[] {1, 2, 3});
writer.close();
//讀數(shù)據(jù)
StoreReader reader = PalDB.createReader(new File("store.paldb"));
String val1 = reader.get("foo");
int[] val2 = reader.get(1213);
reader.close();
應(yīng)用場(chǎng)景
PalDB 適合一次寫入,多次讀取,且數(shù)據(jù)量較大的場(chǎng)景,如:
Hadoop/Spark 計(jì)算時(shí)產(chǎn)生的一些中間結(jié)果
機(jī)器學(xué)習(xí)訓(xùn)練出的模型
詞典
實(shí)現(xiàn)原理
PalDB 本質(zhì)上是一個(gè)哈希表,用開放尋址法處理哈希沖突。下面從讀寫兩方面來分析其實(shí)現(xiàn)細(xì)節(jié)。
寫
寫數(shù)據(jù)的過程主要分為3塊:序列化,預(yù)寫入,最終寫入。
序列化:序列化過程主要負(fù)責(zé)將準(zhǔn)備寫入的 key-value 值進(jìn)行序列化。PalDB 自己實(shí)現(xiàn)了對(duì) java 基本對(duì)象的序列化,對(duì)數(shù)據(jù)進(jìn)行了一定的壓縮(如果覺得壓縮的仍不夠,PalDB 默認(rèn)支持 Snappy 壓縮算法,可手動(dòng)開啟)。
預(yù)寫入:程序每調(diào)用一次 writer.put(Object key, Object value) ,PalDB 就進(jìn)行一次預(yù)寫入。預(yù)寫入負(fù)責(zé)寫兩類文件:
索引文件:存儲(chǔ) key 以及 value 在數(shù)據(jù)文件中的位置
數(shù)據(jù)文件:存儲(chǔ) value 長度以及 value
這兩類文件都有一個(gè)或者多個(gè),成對(duì)出現(xiàn),文件數(shù)量決于 key(序列化后)的長度,一個(gè) key 長度對(duì)應(yīng)一對(duì)<索引文件,數(shù)據(jù)文件>。也就是說,key 長度是一個(gè)一級(jí)索引,這個(gè)在讀的時(shí)候會(huì)用到。下面用一張圖總結(jié)下預(yù)寫入的過程。
預(yù)寫入工程
預(yù)寫入過程中還會(huì)記錄一些重要的值,如:value 位置的最大長度,key 總數(shù)以及每個(gè) key 長度下的 key 數(shù)量。
3.最終寫入
當(dāng)寫完數(shù)據(jù)最終調(diào)用 writer.close() 時(shí)就進(jìn)入最終寫入階段。預(yù)寫入生成的索引文件只是順序的存儲(chǔ)了 key 以及 value 在數(shù)據(jù)文件中的位置,最終寫入階段負(fù)責(zé)將索引文件轉(zhuǎn)化成哈希表,跟索引文件一樣,每一個(gè) key 長度對(duì)應(yīng)一個(gè)哈希表。對(duì)每一個(gè)哈希表:
哈希表 slot 數(shù)量 = 該 key 長度下的 key 數(shù)量 / loadFactor(默認(rèn)0.75,可手動(dòng)指定)
每個(gè) slot 的大小是固定的,等于 key 長度 +? value 位置的最大長度(因此,slot 里的數(shù)據(jù)其實(shí)是有部分空閑的)。
寫這個(gè)哈希表的過程是順序讀預(yù)寫入階段生成的索引文件,按 key? hash 到指定 slot(用開放尋址法處理哈希沖突)并寫入 key 以及 value 位置的過程。
遍歷處理完所有 key 長度對(duì)應(yīng)的索引文件后,將所有哈希表、數(shù)據(jù)文件、meta 信息拼接,形成最終的數(shù)據(jù)庫文件。文件結(jié)構(gòu)如下:
最終數(shù)據(jù)庫文件結(jié)構(gòu)
讀
首先 PalDB 會(huì)將數(shù)據(jù)庫文件初始化,初始化過程分為三步:
讀取 meta 信息,如 key 數(shù)據(jù),key 長度數(shù)量、每個(gè) key 長度對(duì)應(yīng)的索引文件 slot 數(shù)等,并存儲(chǔ)在內(nèi)存中。
以一個(gè)只讀內(nèi)存映射文件方式(MappedByteBuffer)打開 key 索引集合。由于 PalDB 將 key 索引集合當(dāng)做一個(gè)文件打開,由于內(nèi)存映射文件的大小限制,key 索引集合的大小不能超過 2G。
以一個(gè)或多個(gè)只讀內(nèi)存映射文件方式打開數(shù)據(jù)文件集合。如果數(shù)據(jù)文件過大(大于2G),PalDB 會(huì)將其切分成多塊。
初始化完成后,就可以調(diào)用 reader.get(Object o) 方法進(jìn)行數(shù)據(jù)讀取,數(shù)據(jù)讀取的流程如下:
讀取數(shù)據(jù)流程
總結(jié)
PalDB 的實(shí)現(xiàn)原理還是比較簡單的,但是在某些場(chǎng)景下效果會(huì)比常規(guī)方法更好。就筆者的實(shí)踐來說,用 PalDB 存儲(chǔ)推薦模型來代替之前的文件 load 到內(nèi)存的方式,在性能影響很小的情況下大大減少了內(nèi)存的使用,值得一試。
作者:兩棵橘樹
鏈接:http://www.jianshu.com/p/23db015e81a5
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
總結(jié)
- 上一篇: 蓝港CIO韩明顺谈零售数字化转型:面向体
- 下一篇: Docker安装及配置