nemo本質(zhì)上是對rocksdb的改造和封裝,使其支持多數(shù)據(jù)結(jié)構(gòu)的存儲(rocksdb只支持kv存儲)??偟膩碚f,nemo支持五種數(shù)據(jù)結(jié)構(gòu)類型的存儲:KV鍵值對(為了區(qū)分,nemo的的鍵值對結(jié)構(gòu)用大寫的“KV”表示)、Hash結(jié)構(gòu)、List結(jié)構(gòu)、Set結(jié)構(gòu)和ZSet結(jié)構(gòu)。因為rocksdb的存儲方式只有kv一種結(jié)構(gòu),所以以上所說的5種數(shù)據(jù)結(jié)構(gòu)的存儲最終都要落盤到rocksdb的kv存儲方式上。
KV存儲沒有添加額外的元信息,只是在value的結(jié)尾加上8個字節(jié)的附加信息(前4個字節(jié)表示version,后 4個字節(jié)表示ttl)作為最后落盤kv的值部分。具體如下圖:
version字段用于對該鍵值對進(jìn)行標(biāo)記,以便后續(xù)的處理,如刪除一個鍵值對時,可以在該version進(jìn)行標(biāo)記,后續(xù)再進(jìn)行真正的刪除,這樣可以減少刪除操作所導(dǎo)致的服務(wù)阻塞時間。
對于每一個Hash存儲,它包括hash鍵(key),hash鍵下的域名(field)和存儲的值 (value)。nemo的存儲方式是將key和field組合成為一個新的key,將這個新生成的key與所要存儲的value組成最終落盤的kv鍵值對。同時,對于每一個hash鍵,nemo還為它添加了一個存儲元信息的落盤kv,它保存的是對應(yīng)hash鍵下的所有域值對的個數(shù)。下面的是具體的實現(xiàn)方式:
顧名思義,每個List結(jié)構(gòu)的底層存儲也是采用鏈表結(jié)構(gòu)來完成的。對于每個List鍵,它的每個元素都落盤為一個kv鍵值對,作為一個鏈表的一個節(jié)點(diǎn),稱為元素節(jié)點(diǎn)。和hash一樣,每個List鍵也擁有自己的元信息。
a. 每個元素節(jié)點(diǎn)對應(yīng)的落盤kv存儲格式
b.每個元信息的落盤kv的存儲格式
a中前面橫條代表的是最終落盤kv結(jié)構(gòu)的鍵部分,總共4個字段,前面三個字符段分別為一個字符’l’(表明是List結(jié)構(gòu)的結(jié)存),List鍵的字符串長度(1個字節(jié))、List鍵的字符串內(nèi)容(最多254個字節(jié)),第四個字段是該元素節(jié)點(diǎn)所對應(yīng)的索引值,用8個字節(jié)表示(int64_t類型),對于每個元素節(jié)點(diǎn),這個索引(sequence)都是唯一的,是其他元素節(jié)點(diǎn)訪問該元素節(jié)點(diǎn)的唯一媒介;往一個空的List鍵內(nèi)添加一個元素節(jié)點(diǎn)時,該添加的元素節(jié)點(diǎn)的sequence為1,下次一次添加的元素節(jié)點(diǎn)的sequence為2,依次順序遞增,即使中間有元素被刪除了,被刪除的元素的sequence也不會被之后新插入的元素節(jié)點(diǎn)使用,這就保證了每個元素節(jié)點(diǎn)的sequence都是唯一的。b中后面的橫條代表的是具體落盤kv結(jié)構(gòu)的值,它有5個字段,后面的三個字段分別為存入的value值、version、ttl,這和前面的hash結(jié)構(gòu)存儲是類似的;前兩個字段分別表示的是前一個元素節(jié)點(diǎn)的sequence、和后一個元素節(jié)點(diǎn)的sequence、通過這兩個sequence,就可以知道前一個元素節(jié)點(diǎn)和后一個元素節(jié)點(diǎn)的羅盤kv的鍵內(nèi)容,從而實現(xiàn)了一個雙向鏈表的結(jié)構(gòu)。
b中的前面橫條表示存儲元信息的落盤kv的鍵部分,和前面的hash結(jié)構(gòu)是類似的;后面的橫條表示存儲List鍵的元信息,它有四個字段,從前到后分別為該List鍵內(nèi)的元素個數(shù)、最左邊的元素 節(jié)點(diǎn)的sequence(相當(dāng)于鏈表頭)、最右邊的元素節(jié)點(diǎn)的sequence(相當(dāng)于鏈表尾)、下一個要插入元素節(jié)點(diǎn)所應(yīng)該使用的sequence。
a.每個元素節(jié)點(diǎn)對應(yīng)的落盤kv存儲格式
b.每個Set鍵的元信息對應(yīng)的落盤kv存儲格式
Set結(jié)構(gòu)的存儲和hash結(jié)構(gòu)基本是相同的,只是Set中每個元素對應(yīng)的落盤kv中,值的部分只有version和ttl,沒有value字段。
ZSet存儲結(jié)構(gòu)是一個有序Set,所以對于每個元素,增加了一個落盤kv,在這個增加的羅盤 kv的鍵部分,把該元素對應(yīng)的score值整合進(jìn)去,這樣便于依據(jù)Score值進(jìn)行排序(因為從rocksdb內(nèi)拿出的數(shù)據(jù)時按鍵排序的),下面是落盤kv的存儲形式。
a. score值在value部分的落盤kv存儲格式
b. score值在key部分的落盤kv存儲格式
c.存儲元信息的落盤kv的存儲格式
a、c與前面的幾種數(shù)據(jù)結(jié)構(gòu)類似,不再贅述。b中的score是從double類型轉(zhuǎn)變過來的int64_t類型,這樣做是為了可以讓原來的浮點(diǎn)型的score直接參與到字符串的排序當(dāng)中(浮點(diǎn)型的存儲格式與字符串的比較方式不兼容)。
更多建議: