【LevelDB 讀取記錄】
LevelDb是針對大規模Key/Value數據的單機存儲庫,從應用的角度來看,LevelDb就是一個存儲工具。而作為稱職的存儲工具,常見的調用接口無非是新增KV,刪除KV,讀取KV,更新Key對應的Value值這么幾種操作。LevelDb的接口沒有直接支持更新操作的接口,如果需要更新某個Key的Value,你可以選擇直接生猛地插入新的KV,保持Key相同,這樣系統內的key對應的value就會被更新;或者你可以先刪除舊的KV, 之后再插入新的KV,這樣比較委婉地完成KV的更新操作。
假設應用提交一個Key值,下面我們看看LevelDb是如何從存儲的數據中讀出其對應的Value值的。圖7-1是LevelDb讀取過程的整體示意圖。
LevelDb首先會去查看內存中的Memtable,如果Memtable中包含key及其對應的value,則返回value值即可;如果在Memtable沒有讀到key,則接下來到同樣處於內存中的Immutable Memtable中去讀取,類似地,如果讀到就返回,若是沒有讀到,那么只能萬般無奈下從磁盤中的大量SSTable文件中查找。因為SSTable數量較多,而且分成多個Level,所以在SSTable中讀數據是相當蜿蜒曲折的一段旅程。總的讀取原則是這樣的:首先從屬於level 0的文件中查找,如果找到則返回對應的value值,如果沒有找到那么到level 1中的文件中去找,如此循環往復,直到在某層SSTable文件中找到這個key對應的value為止(或者查到最高level,查找失敗,說明整個系統中不存在這個Key)。
那么為什么是從Memtable到Immutable Memtable,再從Immutable Memtable到文件,而文件中為何是從低level到高level這么一個查詢路徑呢?道理何在?之所以選擇這么個查詢路徑,是因為從信息的更新時間來說,很明顯Memtable存儲的是最新鮮的KV對;Immutable Memtable中存儲的KV數據對的新鮮程度次之;而所有SSTable文件中的KV數據新鮮程度一定不如內存中的Memtable和Immutable Memtable的。對於SSTable文件來說,如果同時在level L和Level L+1找到同一個key,level L的信息一定比level L+1的要新。也就是說,上面列出的查找路徑就是按照數據新鮮程度排列出來的,越新鮮的越先查找。
為啥要優先查找新鮮的數據呢?這個道理不言而喻,舉個例子。比如我們先往levelDb里面插入一條數據{key="www.samecity.com" value="我們"},過了幾天,samecity網站改名為:69同城,此時我們插入數據{key="www.samecity.com" value="69同城"},同樣的key,不同的value;邏輯上理解好像levelDb中只有一個存儲記錄,即第二個記錄,但是在levelDb中很可能存在兩條記錄,即上面的兩個記錄都在levelDb中存儲了,此時如果用戶查詢key="www.samecity.com",我們當然希望找到最新的更新記錄,也就是第二個記錄返回,這就是為何要優先查找新鮮數據的原因。
前文有講:對於SSTable文件來說,如果同時在level L和Level L+1找到同一個key,level L的信息一定比level L+1的要新。這是一個結論,理論上需要一個證明過程,否則會招致如下的問題:為神馬呢?從道理上講呢,很明白:因為Level L+1的數據不是從石頭縫里蹦出來的,也不是做夢夢到的,那它是從哪里來的?Level L+1的數據是從Level L 經過Compaction后得到的(如果您不知道什么是Compaction,那么........也許以后會知道的),也就是說,您看到的現在的Level L+1層的SSTable數據是從原來的Level L中來的,現在的Level L比原來的Level L數據要新鮮,所以可證,現在的Level L比現在的Level L+1的數據要新鮮。
SSTable文件很多,如何快速地找到key對應的value值?在LevelDb中,level 0一直都愛搞特殊化,在level 0和其它level中查找某個key的過程是不一樣的。因為level 0下的不同文件可能key的范圍有重疊,某個要查詢的key有可能多個文件都包含,這樣的話LevelDb的策略是先找出level 0中哪些文件包含這個key(manifest文件中記載了level和對應的文件及文件里key的范圍信息,LevelDb在內存中保留這種映射表), 之后按照文件的新鮮程度排序,新的文件排在前面,之后依次查找,讀出key對應的value。而如果是非level 0的話,因為這個level的文件之間key是不重疊的,所以只從一個文件就可以找到key對應的value。
最后一個問題,如果給定一個要查詢的key和某個key range包含這個key的SSTable文件,那么levelDb是如何進行具體查找過程的呢?levelDb一般會先在內存中的Cache中查找是否包含這個文件的緩存記錄,如果包含,則從緩存中讀取;如果不包含,則打開SSTable文件,同時將這個文件的索引部分加載到內存中並放入Cache中。 這樣Cache里面就有了這個SSTable的緩存項,但是只有索引部分在內存中,之后levelDb根據索引可以定位到哪個內容Block會包含這條key,從文件中讀出這個Block的內容,在根據記錄一一比較,如果找到則返回結果,如果沒有找到,那么說明這個level的SSTable文件並不包含這個key,所以到下一級別的SSTable中去查找。
從之前介紹的LevelDb的寫操作和這里介紹的讀操作可以看出,相對寫操作,讀操作處理起來要復雜很多,所以寫的速度必然要遠遠高於讀數據的速度,也就是說,LevelDb比較適合寫操作多於讀操作的應用場合。而如果應用是很多讀操作類型的,那么順序讀取效率會比較高,因為這樣大部分內容都會在緩存中找到,盡可能避免大量的隨機讀取操作。
參考:http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html