本文由合合信息大數據團隊柳佳浩撰寫
1.前言
圖譜業務隨着時間的推移愈發的復雜化,逐漸體現出了性能上的瓶頸:單機不足以支持更大的圖譜。然而,從性能上來看,Neo4j 的原生圖存儲有着不可替代的性能優勢,這一點是之前調研的 JanusGraph、Dgraph 等都難以逾越的鴻溝。即使 JanusGraph 在 OLAP 上面非常出色,對 OLTP 也有一定的支持,但是 GraphFrame 等也足以支撐其 OLAP 需求,更何況在 Spark 3.0 會提供 Cypher 支持的情況下,圖譜的 OLAP 需求相比 OLTP 有更多途徑可以解決。這個時候,Nebula Graph 的“橫空出世”無疑是對分布式 OLTP 效率低下現狀的一種突破。
之前在各類調研、部署后,特別是從 JanusGraph 的 OLTP 效率最終測試發現無法滿足線上需求之后,我們不再對同一圖譜可以同時進行 OLAP 和 OLTP 進行強制性要求,而 Nebula Graph 的架構剛好符合圖譜方面的需要:
- 分布式——shared-nothing 分布式架構
- 高速 OLTP(性能需要和 Neo4j 相近)——Nebula Graph 的存儲層架構查詢直接映射物理地址,實際上可以算是原生圖存儲
- 服務的高可用(即在非人為情況下,圖譜可以穩定提供服務)——局部失敗服務可用、有快照機制
- 保證可擴展性——支持線性擴容,由於開源、支持二次開發
綜上所述,Nebula Graph 架構上符合實際生產需求,因此對 Nebula Graph 進行了調研、部署、測試。關於部署、性能測試(美團 NLP 團隊性能測試、騰訊雲安全團隊性能測試)的部分無論是官網還是其他同學在博客中都有比較詳盡的數據,本文主要從 Spark 導入出發,算是對 Nebula Graph 對 Spark 的支持進行粗淺的理解。
2.測試環境
- Nebula Graph 集群
- 3 台 32 c(實際限制了16 c)
- 400 G 內存(實際配置了 100 G)
- SSD
- 版本信息:Nebula Graph 版本 1.0.0(當時測試比較早)。
- 網絡環境:萬兆。
- 圖譜大小:十億級別節點(屬性較少),百億級別邊(有向,無屬性或帶權值)。
- Spark 集群
- 版本信息:Spark 2.1.0
實際上 Nebula Graph 的使用資源合計 2T 左右 memory (3 * 30 executor + 1 driver) * 25G。
3.Spark 批量導入
3.1 基礎流程
- 打包 sst.generator(Spark 生成 sst 所需要的包)。
- 配置 Nebula Graph 集群,Nebula Graph 集群正常啟動,創建圖譜。
- Spark 配置文件
config.conf
(可以參考文檔《Spark 導入工具》)進行配置。 - 排查 Spark 集群是否存在沖突的包。
- Spark 啟動時使用配置文件和
sst.generator
快樂地導入。 - 數據校驗。
3.2 一些細節
- 批量導入前推薦先建立索引。
這里推薦先建立索引的原因是:批量導入僅在非線上圖譜進行,雖然建立索引可以選擇是否在提供服務的同時進行,但是為了防止后續 REBUILD
出現問題,這邊可以優先建好索引。帶來的問題就是在批量導入結點時相對較慢。
-
推薦用 int 型節點 ID(可以使用 Snowflake算法 等),如果節點的 ID 不是 int 型,這里可以通過在節點/邊中加入
policy: "uuid"
來設置自動生成 uuid。 -
如果使用的是單獨的 Spark 集群可能不會出現 Spark 集群有沖突包的問題,該問題主要是 sst.generator 中存在可能和 Spark 環境內的其他包產生沖突,解決方法是 shade 掉這些沖突的包,或者改名。
-
Spark 調優方面:可以根據實際情況調整參數,盡量降低 memory 以節約資源,相對的可以適當提高並行度加速。
3.3 導入結果
十億級別節點(屬性較少),百億級別邊(有向,無屬性或帶權值),提前建好索引的情況下大約消耗 20 小時左右導入全圖。
3.4 關於 PR
因為在較早的版本使用了 Spark 導入,自然也有一些不太完善的地方,這邊也提出了一些拙見,對 SparkClientGenerator.scala 略作了修改。
- 最早在使用 Spark Writer(現:Exchange) 寫入 Nebula Graph 時,發現錯列的問題。
通過看源碼發現 SparkClientGenerator.scala 存在 BUG,讀取的是配置文件的位置而非 parquet/json
文件的位置,修復后提了我第一個 PR#2187,有幸通過
- 后續發現使用 SparkClientGenerator 自動生成 uuid/hash 功能時,存在會出現重復的雙引號的問題,導致無法導入。
這塊可以說是由於解決問題的想法不同,提交了好多次。重復引號的問題歸根結底是對類型轉化的時候添加了一次雙引號,我這邊發現有個 extraIndexValue 的方法可以把用戶自填的非 string 類型的轉成 string 類型,我這邊想着可能會有用戶想把非 string 型的 index 轉成 uuid/hash(比如 array),所以修改的比較多。
但是和官方 @darionyaphet 溝通后,發現我這種做法其實是對數據源進行了修改,用戶傳 array 等不支持的類型時,應該報錯而不是轉換類型(這個確實,一開始只考慮到了邏輯上跑通以及自己這邊業務的使用,沒考慮通用性)。重新修改,提交 PR #2258,通過。經過這次 PR 我也學到了很多。
- 之后發現 nebula-python 也有和官方 thrift 沖突的問題,本來想 shade 后提 PR,但是覺得這個改動太大了,所以直接提給官方,近期也修復了。
Nebula Graph 旁白:歡迎社區小伙伴來 GitHub 給我們提 PR,GitHub 傳送門:https://github.com/vesoft-inc/nebula/issues
4.總結 & 展望
因為之前調研過 JanusGraph,Nebula Graph 給我的第一印象就是:暗坑相對較少、社區反饋非常及時。在測試后 Nebula Graph 又用她的效率證明了自己,成為了分布式圖譜的首選項。
Nebula Graph 社區、群組、PR 官方反饋非常及時,這是圖譜迅速、茁壯成長的不可替代的重要因素,也希望可以后續可以繼續見證 Nebula Graph 的成長,繼續為 Nebula Graph 生態的完善添磚加瓦!
喜歡這篇文章?來來來,給我們的 GitHub 點個 star 表鼓勵啦~~ 🙇♂️🙇♀️ [手動跪謝]
Nebula Graph Meetup 深圳場報名中:https://www.huodongxing.com/event/4572357498700,期待你來現場交流技術 😊