Nebula Storage 2.0 儲存格式

nebulagraph發表於2021-03-10

storage-format-in-nebula-graph-2.0

隨著 2.0 各版本的陸續釋出,Nebula Graph 迎來了一系列的改動,在儲存方面,影響最大的改動就是底層編碼格式進行了修改。Nebula Graph 的底層儲存是基於 KV 儲存在 RocksDB 中,本文將介紹新老編碼格式的差異,以及為什麼要修改儲存格式等一系列問題。

1.0 版本的格式

我們先簡單回顧下 1.0 版本的編碼格式,不熟悉的可以參考這篇部落格《Nebula 架構剖析系列(一)圖資料庫的儲存設計》。由於在 1.0 版本中,點的 ID 只能夠用整型來表示,所以底層所有 VertexID 都是以 int64 來儲存的。

  • 點的格式

Nebula Graph 1.0 點的格式

  • 邊的格式

Nebula Graph 1.0 邊的格式

給定任何一個 VertexID,經過 hash,可以得到對應的 PartID,因此對於一個點和這個點的所有邊(邊用起點計算 hash),都會對映到同一個分片中。需要指出的是,在 1.0 版本中,點和邊的第一個位元組的 Type 是相同的。也就是說,對於一個點而言,它的所有 tag 並沒有在物理上連續儲存,比如可能是如下儲存的。對於這個 src 這個點的三個 tag(tag1 tag2 tag3),實際上可能會被其他邊隔開。

rocksdb key 儲存

這個格式能夠滿足 1.0 絕大多數介面的需要,比如 fetchgo 都只需要指定對應字首,就能獲取對應資料。

2.0 版本的格式

在 GA 之前釋出的版本,底層儲存格式其實和 1.0 是基本相同的。如果 VertexID 是整型,和 1.0 格式完全一致。而如果 VertexID 型別支援 string,則從佔用 8 個位元組的 int64 改成了固定長度的 FIXED_STRING,長度需要使用者在 create space 時候指定長度。對於不足的長度系統自動使用 \0 補齊,而超過指定長度的 VertexID 會直接報錯。

在 GA 版本中,我們對底層儲存格式進行了若干改動,因此這次版本升級時需要通過升級工具,將原有格式的資料轉換為新格式的資料。如下是在 2.0 GA 版本中採用的儲存格式。

2.0 版本儲存格式

  • 點的格式

Nebula Graph 2.0 點的格式

  • 邊的格式

Nebula Graph 2.0 邊的格式

和 1.0 儲存格式對比

點格式版本對比

點格式版本對比

其中有幾個比較大的改動:

  1. VertexID 的長度如前文所說,從固定的 8 位元組,修改為 n 個位元組。VertexID 型別為整型時,n 為 8,VertexID 型別為 string 型別時,n 為指定長度。
  2. 點去掉了 1.0 的時間戳。邊將 1.0 時間戳改為了一個位元組的佔位符。
  3. 對於點和邊的第一個位元組,不再使用同一個 Type,在物理上點和邊進行了分離。

這些改動主要是基於以下幾點進行考慮的:

  1. VertexID 改變主要是為了支援 string ID 同時相容 1.0 版本 int ID。在 storage 中,把 VertexID 都處理為 bytes,只在返回結果時根據 space 的設定不同,返回相應型別的 VertexID。

    為什麼 string ID 要使用 FIXED_STRING ? 如果不使用固定長度,則無法使用字首進行掃描。通過長度不足補齊,使得所有點之間和邊之間的各個字首長度相同,從而進行相應的字首查詢。

  2. 去掉時間戳主要是因為儲存多版本資料會影響效能,另外一段時間內暫時不考慮做 MVCC 的相關工作。

    在邊裡面還保留一個位元組的佔位符,主要是留給 TOSS(transaction on storage side)使用。主要用於標識一條邊的出邊和入邊是否完整插入了,這裡不詳細介紹,後續會有其他文章進行詳盡的分析。

  3. 點和邊分離的好處主要是能夠方便快速拿某個點的所有 tag(在Cypher 的 MATCH 語句中大量使用)。如果按原先同一 Type + VertexID 字首掃描,由於點邊可能摻雜在一起,會極大影響效能。而 Type 分離之後,按 VertexType + VertexID 字首掃描,可以快速獲取所有 tag。

    在 1.0 版本中,由於沒有取某個點的所有 tag 的需求,因此點和邊可以按同一個字首儲存。不過在程式碼層面,還是有不小影響,例如 fetch 介面在 1.0 是按 VertexID 的字首去掃描的,對於超級大點來說取 tag 效能比較差。另外如果使用 storage 提供的 scan 介面,想要獲取全圖的所有點,實際是掃描了整個 RocksDB。

除了點和邊的格式相關改動之外,索引的格式其實也有所改變。

一方面是 2.0 支援 NULL 後,索引也需要能夠表示對應的語義。另一方面是在 1.0 的版本中,對於索引中 string 的欄位的處理,實際是按變長 string 處理。因此在 LOOKUP 語句中只要使用了帶 string 欄位的索引,就只能使用等值查詢。而在 2.0 的版本中,索引的 string 欄位和資料中的 VertexID 一樣,使用固定長度的 FIXED_STRING,LOOKUP 語句中帶 string 欄位的索引能夠使用範圍查詢,例如 LOOKUP ON index1 WHERE col > "aaa"。有關索引部分的功能和修改,後續也會再有其他文章介紹。

以上,為本次 Nebula Storage 2.0 儲存格式講解。

喜歡這篇文章?來來來,給我們的 GitHub 點個 star 表鼓勵啦~~ ?‍♂️?‍♀️ [手動跪謝]

交流圖資料庫技術?交個朋友,Nebula Graph 官方小助手微信:NebulaGraphbot 拉你進交流群~~

推薦閱讀

相關文章