本文由美團 NLP 團隊高辰、趙登昌撰寫
首發于 Nebula Graph 官方論壇:
https://discuss.nebula-graph.com.cn/t/topic/1377

1. 前言
近年來,深度學習和知識圖譜技術發展迅速,相比于深度學習的“黑盒子”,知識圖譜具有很強的可解釋性,在搜尋推薦、智能助理、金融風控等場景中有着廣泛的應用。美團基于積累的海量業務資料,結合使用場景進行充分地挖掘關聯,逐漸建立起包括美食圖譜、旅遊圖譜、商品圖譜在内的近十個領域知識圖譜,并在多業務場景落地,助力本地生活服務的智能化。
為了高效存儲并檢索圖譜資料,相比傳統關系型資料庫,選擇圖資料庫作為存儲引擎,在多跳查詢上具有明顯的性能優勢。目前業界知名的圖資料庫産品有數十款,選型一款能夠滿足美團實際業務需求的圖資料庫産品,是建設圖存儲和圖學習平台的基礎。我們結合業務現狀,制定了選型的基本條件:
- 開源項目,對商業應用友好
- 擁有對源代碼的控制力,才能保證資料安全和服務可用性。
- 支援叢集模式,具備存儲和計算的橫向擴充能力
- 美團圖譜業務資料量可以達到千億以上點邊總數,吞吐量可達到數萬 qps,單節點部署無法滿足存儲需求。
- 能夠服務 OLTP 場景,具備毫秒級多跳查詢能力
- 美團搜尋場景下,為確定使用者搜尋體驗,各鍊路的逾時時間具有嚴格限制,不能接受秒級以上的查詢響應時間。
- 具備批量導入資料能力
- 圖譜資料一般存儲在 Hive 等資料倉庫中。必須有快速将資料導入到圖存儲的手段,服務的時效性才能得到保證。
我們試用了 DB-Engines 網站上排名前 30 的圖資料庫産品,發現多數知名的圖資料庫開源版本隻支援單節點,不能橫向擴充存儲,無法滿足大規模圖譜資料的存儲需求,例如:Neo4j、ArangoDB、Virtuoso、TigerGraph、RedisGraph。經過調研比較,最終納入評測範圍的産品為:NebulaGraph(原阿裡巴巴團隊創業開發)、Dgraph(原 Google 團隊創業開發)、HugeGraph(百度團隊開發)。
2. 測試概要
2.1 硬體配置
- 資料庫執行個體:運作在不同實體機上的 Docker 容器。
- 單執行個體資源:32 核心,64GB 記憶體,1TB SSD 存儲。【Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz】
- 執行個體數量:3
2.2 部署方案
Metad 負責管理叢集中繼資料,Graphd 負責執行查詢,Storaged 負責資料分片存儲。存儲後端采用 RocksDB。
|執行個體 1 | 執行個體 2 | 執行個體 3 |
|-|-|-|
|Metad | Metad | Metad|
|Graphd | Graphd | Graphd|
|Storaged[RocksDB] | Storaged[RocksDB] | Storaged[RocksDB]|
Zero 負責管理叢集中繼資料,Alpha 負責執行查詢和存儲。存儲後端為 Dgraph 自有實作。
|Zero | Zero | Zero|
|Alpha | Alpha | Alpha|
HugeServer 負責管理叢集中繼資料和查詢。HugeGraph 雖然支援 RocksDB 後端,但不支援 RocksDB 後端的叢集部署,是以存儲後端采用 HBase。
|執行個體1 | 執行個體2 | 執行個體3 |
|HugeServer[HBase]|HugeServer[HBase]|HugeServer[HBase]|
|JournalNode | JournalNode | JournalNode|
|DataNode | DataNode | DataNode|
|NodeManager | NodeManager | NodeManager|
|RegionServer | RegionServer | RegionServer|
|ZooKeeper | ZooKeeper | ZooKeeper|
|NameNode | NameNode[Backup] | -|
| -|ResourceManager | ResourceManager[Backup]|
|HBase Master | HBase Master[Backup] |-|
3. 評測資料集
- 社交圖譜資料集: https://github.com/ldbc 011
- 生成參數:branch=stable, version=0.3.3, scale=1000
- 實體情況:4 類實體,總數 26 億
- 關系情況:19 類關系,總數 177 億
- 資料格式:csv
- GZip 壓縮後大小:194 G
4. 測試結果
4.1 批量資料導入
4.1.1 測試說明
批量導入的步驟為:
Hive 倉庫底層 csv 檔案 -> 圖資料庫支援的中間檔案 -> 圖資料庫
。各圖資料庫具體導入方式如下:
- Nebula :執行 Spark 任務,從數倉生成 RocksDB 的底層存儲 sst 檔案,然後執行 sst Ingest 操作插入資料。
- Dgraph :執行 Spark 任務,從數倉生成三元組 rdf 檔案,然後執行 bulk load 操作直接生成各節點的持久化檔案。
- HugeGraph :支援直接從數倉的 csv 檔案導入資料,是以不需要數倉-中間檔案的步驟。通過 loader 批量插入資料。
4.1.2 測試結果
4.1.3 資料分析
- Nebula:資料存儲分布方式是主鍵哈希,各節點存儲分布基本均衡。導入速度最快,存儲放大比最優。
- Dgraph:原始 194G 資料在記憶體 392G 的機器上執行導入指令,8.7h 後 OOM 退出,無法導入全量資料。資料存儲分布方式是三元組謂詞,同一種關系隻能儲存在一個資料節點上,導緻存儲和計算嚴重偏斜。
- HugeGraph:原始 194G 的資料執行導入指令,寫滿了一個節點 1,000G 的磁盤,造成導入失敗,無法導入全量資料。存儲放大比最差,同時存在嚴重的資料偏斜。
4.2 實時資料寫入
4.2.1 測試說明
- 向圖資料庫插入點和邊,測試實時寫入和并發能力。
- 響應時間:固定的 50,000 條資料,以固定 qps 發出寫請求,全部發送完畢即結束。取用戶端從送出請求到收到響應的 Avg、p99、p999 耗時。
- 最大吞吐量:固定的 1,000,000 條資料,以遞增 qps 發出寫請求,Query 循環使用。取 1 分鐘内成功請求的峰值 qps 為最大吞吐量。
- 插入點
-
INSERT VERTEX t_rich_node (creation_date, first_name, last_name, gender, birthday, location_ip, browser_used) VALUES ${mid}:('2012-07-18T01:16:17.119+0000', 'Rodrigo', 'Silva', 'female', '1984-10-11', '84.194.222.86', 'Firefox')
-
{ set { <${mid}> <creation_date> "2012-07-18T01:16:17.119+0000" . <${mid}> <first_name> "Rodrigo" . <${mid}> <last_name> "Silva" . <${mid}> <gender> "female" . <${mid}> <birthday> "1984-10-11" . <${mid}> <location_ip> "84.194.222.86" . <${mid}> <browser_used> "Firefox" . } }
-
g.addVertex(T.label, "t_rich_node", T.id, ${mid}, "creation_date", "2012-07-18T01:16:17.119+0000", "first_name", "Rodrigo", "last_name", "Silva", "gender", "female", "birthday", "1984-10-11", "location_ip", "84.194.222.86", "browser_used", "Firefox")
-
- 插入邊
-
INSERT EDGE t_edge () VALUES ${mid1}->${mid2}:();
-
{ set { <${mid1}> <link> <${mid2}> . } }
-
g.V(${mid1}).as('src').V(${mid2}).addE('t_edge').from('src')
-
4.2.2 測試結果
- 實時寫入
4.2.3 資料分析
- Nebula:如 4.1.3 節分析所述,Nebula 的寫入請求可以由多個存儲節點分擔,是以響應時間和吞吐量均大幅領先。
- Dgraph:如 4.1.3 節分析所述,同一種關系隻能儲存在一個資料節點上,吞吐量較差。
- HugeGraph:由于存儲後端基于 HBase,實時并發讀寫能力低于 RocksDB(Nebula)和 BadgerDB(Dgraph),是以性能最差。
4.3 資料查詢
4.3.1 測試說明
- 以常見的 N 跳查詢傳回 ID,N 跳查詢傳回屬性,共同好友查詢請求測試圖資料庫的讀性能。
- 響應時間:固定的 50,000 條查詢,以固定 qps 發出讀請求,全部發送完畢即結束。取用戶端從送出請求到收到響應的 Avg、p99、p999 耗時。
- 60s 内未傳回結果為逾時。
- 最大吞吐量:固定的 1,000,000 條查詢,以遞增 qps 發出讀請求,Query 循環使用。取 1 分鐘内成功請求的峰值 qps 為最大吞吐量。
- 緩存配置:參與測試的圖資料庫都具備讀緩存機制,預設打開。每次測試前均重新開機服務清空緩存。
- 響應時間:固定的 50,000 條查詢,以固定 qps 發出讀請求,全部發送完畢即結束。取用戶端從送出請求到收到響應的 Avg、p99、p999 耗時。
- N 跳查詢傳回 ID
-
GO ${n} STEPS FROM ${mid} OVER person_knows_person
-
{ q(func:uid(${mid})) { uid person_knows_person { #${n}跳數 = 嵌套層數 uid } } }
-
g.V(${mid}).out().id() #${n}跳數 = out()鍊長度
-
- N 跳查詢傳回屬性
-
GO ${n} STEPS FROM ${mid} OVER person_knows_person YIELDperson_knows_person.creation_date, $$.person.first_name, $$.person.last_name, $$.person.gender, $$.person.birthday, $$.person.location_ip, $$.person.browser_used
-
{ q(func:uid(${mid})) { uid first_name last_name gender birthday location_ip browser_used person_knows_person { #${n}跳數 = 嵌套層數 uid first_name last_name gender birthday location_ip browser_used } } }
-
g.V(${mid}).out() #${n}跳數 = out()鍊長度
-
- 共同好友查詢語句
-
GO FROM ${mid1} OVER person_knows_person INTERSECT GO FROM ${mid2} OVER person_knows_person
-
{ var(func: uid(${mid1})) { person_knows_person { M1 as uid } } var(func: uid(${mid2})) { person_knows_person { M2 as uid } } in_common(func: uid(M1)) @filter(uid(M2)){ uid } }
-
g.V(${mid1}).out().id().aggregate('x').V(${mid2}).out().id().where(within('x')).dedup()
-
4.3.2 測試結果
單個傳回節點的屬性平均大小為 200 Bytes。
-
共同好友
本項未測試最大吞吐量。
4.3.3 資料分析
- 在 1 跳查詢傳回 ID「響應時間」實驗中,Nebula 和 DGraph 都隻需要進行一次出邊搜尋。由于 DGraph 的存儲特性,相同關系存儲在單個節點,1 跳查詢不需要網絡通信。而 Nebula 的實體分布在多個節點中,是以在實驗中 DGraph 響應時間表現略優于 Nebula。
- 在 1 跳查詢傳回 ID「最大吞吐量」實驗中,DGraph 叢集節點的 CPU 負載主要落在存儲關系的單節點上,造成叢集 CPU 使用率低下,是以最大吞吐量僅有 Nebula 的 11%。
- 在 2 跳查詢傳回 ID「響應時間」實驗中,由于上述原因,DGraph 在 qps=100 時已經接近了叢集負載能力上限,是以響應時間大幅變慢,是 Nebula 的 3.9 倍。
- 在 1 跳查詢傳回屬性實驗中,Nebula 由于将實體的所有屬性作為一個資料結構存儲在單節點上,是以隻需要進行【出邊總數 Y】次搜尋。而 DGraph 将實體的所有屬性也視為出邊,并且分布在不同節點上,需要進行【屬性數量 X * 出邊總數 Y】次出邊搜尋,是以查詢性能比 Nebula 差。多跳查詢同理。
- 在共同好友實驗中,由于此實驗基本等價于 2 次 1 跳查詢傳回 ID,是以測試結果接近,不再詳述。
- 由于 HugeGraph 存儲後端基于 HBase,實時并發讀寫能力低于 RocksDB(Nebula)和 BadgerDB(Dgraph),是以在多項實驗中性能表現均落後于 Nebula 和 DGraph。
5. 結論
參與測試的圖資料庫中,Nebula 的批量導入可用性、導入速度、實時資料寫入性能、資料多跳查詢性能均優于競品,是以我們最終選擇了 Nebula 作為圖存儲引擎。
6. 參考資料
- NebulaGraph Benchmark: https://discuss.nebula-graph.com.cn/t/topic/782
- NebulaGraph Benchmark 微信團隊: https://discuss.nebula-graph.com.cn/t/topic/1013
- DGraph Benchmark: https://dgraph.io/blog/tags/benchmark/
- HugeGraph Benchmark: https://hugegraph.github.io/hugegraph-doc/performance/hugegraph-benchmark-0.5.6.html
- TigerGraph Benchmark: https://www.tigergraph.com/benchmark/
- RedisGraph Benchmark: https://redislabs.com/blog/new-redisgraph-1-0-achieves-600x-faster-performance-graph-databases/
本次性能測試系美團 NLP 團隊高辰、趙登昌撰寫,如果你對本文有任意疑問,歡迎來原貼和作者交流: