1. 程式人生 > 實用技巧 >在 Spark 資料匯入中的一些實踐細節

在 Spark 資料匯入中的一些實踐細節

本文由合合資訊大資料團隊柳佳浩撰寫

1.前言

圖譜業務隨著時間的推移愈發的複雜化,逐漸體現出了效能上的瓶頸:單機不足以支援更大的圖譜。然而,從效能上來看,Neo4j 的原生圖儲存有著不可替代的效能優勢,這一點是之前調研的 JanusGraph、Dgraph 等都難以逾越的鴻溝。即使 JanusGraph 在 OLAP 上面非常出色,對 OLTP 也有一定的支援,但是 GraphFrame 等也足以支撐其 OLAP 需求,更何況在 Spark 3.0 會提供 Cypher 支援的情況下,圖譜的 OLAP 需求相比 OLTP 有更多途徑可以解決。這個時候,Nebula Graph 的“橫空出世”無疑是對分散式 OLTP 效率低下現狀的一種突破。

之前在各類調研、部署後,特別是從 JanusGraph 的 OLTP 效率最終測試發現無法滿足線上需求之後,我們不再對同一圖譜可以同時進行 OLAP 和 OLTP 進行強制性要求,而 Nebula Graph 的架構剛好符合圖譜方面的需要:

  1. 分散式——shared-nothing 分散式架構
  2. 高速 OLTP(效能需要和 Neo4j 相近)——Nebula Graph 的儲存層架構查詢直接對映實體地址,實際上可以算是原生圖儲存
  3. 服務的高可用(即在非人為情況下,圖譜可以穩定提供服務)——區域性失敗服務可用、有快照機制
  4. 保證可擴充套件性——支援線性擴容,由於開源、支援二次開發

綜上所述,Nebula Graph 架構上符合實際生產需求,因此對 Nebula Graph 進行了調研、部署、測試。關於部署、效能測試(

美團 NLP 團隊效能測試騰訊雲安全團隊效能測試)的部分無論是官網還是其他同學在部落格中都有比較詳盡的資料,本文主要從 Spark 匯入出發,算是對 Nebula Graph 對 Spark 的支援進行粗淺的理解。

2.測試環境

  1. Nebula Graph 叢集
    1. 3 臺 32 c(實際限制了16 c)
    2. 400 G 記憶體(實際配置了 100 G)
    3. SSD
    4. 版本資訊:Nebula Graph 版本 1.0.0(當時測試比較早)。
  2. 網路環境:萬兆。
  3. 圖譜大小:十億級別節點(屬性較少),百億級別邊(有向,無屬性或帶權值)。
  4. Spark 叢集
    1. 版本資訊:Spark 2.1.0

實際上 Nebula Graph 的使用資源合計 2T 左右 memory (3 * 30 executor + 1 driver) * 25G。

3.Spark 批量匯入

3.1 基礎流程

  1. 打包 sst.generator(Spark 生成 sst 所需要的包)。
  2. 配置 Nebula Graph 叢集,Nebula Graph 叢集正常啟動,建立圖譜。
  3. Spark 配置檔案 config.conf(可以參考文件《Spark 匯入工具》)進行配置。
  4. 排查 Spark 叢集是否存在衝突的包。
  5. Spark 啟動時使用配置檔案和 sst.generator 快樂地匯入。
  6. 資料校驗。

3.2 一些細節

  1. 批量匯入前推薦先建立索引

這裡推薦先建立索引的原因是:批量匯入僅在非線上圖譜進行,雖然建立索引可以選擇是否在提供服務的同時進行,但是為了防止後續 REBUILD 出現問題,這邊可以優先建好索引。帶來的問題就是在批量匯入結點時相對較慢。

  1. 推薦用 int 型節點 ID(可以使用 Snowflake演算法 等),如果節點的 ID 不是 int 型,這裡可以通過在節點/邊中加入 policy: "uuid" 來設定自動生成 uuid。

  2. 如果使用的是單獨的 Spark 叢集可能不會出現 Spark 叢集有衝突包的問題,該問題主要是 sst.generator 中存在可能和 Spark 環境內的其他包產生衝突,解決方法是 shade 掉這些衝突的包,或者改名。

  3. Spark 調優方面:可以根據實際情況調整引數,儘量降低 memory 以節約資源,相對的可以適當提高並行度加速。

3.3 匯入結果

十億級別節點(屬性較少),百億級別邊(有向,無屬性或帶權值),提前建好索引的情況下大約消耗 20 小時左右匯入全圖。

3.4 關於 PR

因為在較早的版本使用了 Spark 匯入,自然也有一些不太完善的地方,這邊也提出了一些拙見,對 SparkClientGenerator.scala 略作了修改。

  1. 最早在使用 Spark Writer(現:Exchange) 寫入 Nebula Graph 時,發現錯列的問題。

通過看原始碼發現 SparkClientGenerator.scala 存在 BUG,讀取的是配置檔案的位置而非 parquet/json 檔案的位置,修復後提了我第一個 PR#2187,有幸通過

  1. 後續發現使用 SparkClientGenerator 自動生成 uuid/hash 功能時,存在會出現重複的雙引號的問題,導致無法匯入。

這塊可以說是由於解決問題的想法不同,提交了好多次。重複引號的問題歸根結底是對型別轉化的時候添加了一次雙引號,我這邊發現有個 extraIndexValue 的方法可以把使用者自填的非 string 型別的轉成 string 型別,我這邊想著可能會有使用者想把非 string 型的 index 轉成 uuid/hash(比如 array),所以修改的比較多。

但是和官方 @darionyaphet 溝通後,發現我這種做法其實是對資料來源進行了修改,使用者傳 array 等不支援的型別時,應該報錯而不是轉換型別(這個確實,一開始只考慮到了邏輯上跑通以及自己這邊業務的使用,沒考慮通用性)。重新修改,提交 PR #2258,通過。經過這次 PR 我也學到了很多。

  1. 之後發現 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 表鼓勵啦~~