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