本文首發于 Nebula Graph Community 公衆号

解決思路
解決 K8s 部署 Nebula Graph 叢集後連接配接不上叢集問題最友善的方法是将 nebula-algorithm / nebula-spark 運作在與 nebula-operator 相同的網絡命名空間裡,将 show hosts meta 的 MetaD 域名:端口 格式的位址填進配置裡就可以了。
注:這裡需要 2.6.2 或者更新的版本,nebula-spark-connector / nebula-algorithm 才支援域名形式的 MetaD 位址。
這裡來具體實操下網絡配置:
- 擷取 MetaD 位址
(root@nebula) [(none)]> show hosts meta
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
| Host | Port | Status | Role | Git Info Sha | Version |
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
| "nebula-metad-0.nebula-metad-headless.default.svc.cluster.local" | 9559 | "ONLINE" | "META" | "d113f4a" | "2.6.2" |
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
Got 1 rows (time spent 1378/2598 us)
Mon, 14 Feb 2022 08:22:33 UTC
這裡需要記錄 Host 名以便後續的配置檔案中使用該名稱。
- 填寫 nebula-algorithm 的配置檔案
參考文檔 https://github.com/vesoft-inc/nebula-algorithm/blob/master/nebula-algorithm/src/main/resources/application.conf。填寫配置檔案有兩種方法:修改 TOML 檔案或者在 nebula-spark-connector 代碼中添加配置資訊。
方法一:修改 TOML 檔案
# ...
nebula: {
# algo's data source from Nebula. If data.source is nebula, then this nebula.read config can be valid.
read: {
# 這裡填上剛獲得到的 meta 的 Host 名,多個位址的話用英文字元下的逗号隔開;
metaAddress: "nebula-metad-0.nebula-metad-headless.default.svc.cluster.local:9559"
#...
方法二:調用 nebula-spark-connector 的代碼
Ref: https://github.com/vesoft-inc/nebula-spark-connector
val config = NebulaConnectionConfig
.builder()
// 這裡填上剛獲得到的 meta 的 Host 名
.withMetaAddress("nebula-metad-0.nebula-metad-headless.default.svc.cluster.local:9559")
.withConenctionRetry(2)
.build()
val nebulaReadVertexConfig: ReadNebulaConfig = ReadNebulaConfig
.builder()
.withSpace("foo_bar_space")
.withLabel("person")
.withNoColumn(false)
.withReturnCols(List("birthday"))
.withLimit(10)
.withPartitionNum(10)
.build()
val vertex = spark.read.nebula(config, nebulaReadVertexConfig).loadVerticesToDF()
好的,到現在為止,過程看起來非常簡單。那麼,為什麼這麼簡單的過程卻值得一篇文章呢?
配置資訊容易忽略的問題
剛才我們講了具體的實際操作,但當中有一些理論小知識在這裡:
a. MetaD 隐含地需要保證 StorageD 的位址能被 Spark 環境通路;
b. StorageD 位址是從 MetaD 擷取的;
c. Nebula K8s Operator 裡,MetaD 中存儲的 StorageD 位址(服務發現)的來源是 StorageD 的配置檔案,而它是 K8s 的内部位址。
背景知識
a. 的理由比較直接,和 Nebula 的架構有關:圖的資料都存在 Storage Service 之中,通常用語句的查詢是透過 Graph Service 來透傳,隻需要 GraphD 的連接配接就足夠,而 nebula-spark-connector 使用 Nebula Graph 的場景是掃描全圖或者子圖,這時候計算存儲分離的設計使得我們可以繞過查詢、計算層直接高效讀取圖資料。
那麼問題來了,為什麼需要且隻要 MetaD 的位址呢?
這也是和架構有關,Meta Service 裡包含了全圖的分布資料與分布式的 Storage Service 的各個分片和執行個體的分布,是以一方面因為隻有 Meta 才有全圖的資訊(需要),另一方面因為從 Meta 可以獲得這部分資訊(隻要)。到這裡 b. 的答案也有了。
- 詳細的 Nebula Graph 架構資訊可以參考架構三部曲系列Nebula 架構剖析系列(零)圖資料庫的整體架構設計Nebula 架構剖析系列(一)圖資料庫的存儲設計Nebula 架構剖析系列(二)圖資料庫的查詢引擎設計
下面我們看看 c. 背後的邏輯:
c. Nebula K8s Operator 裡,MetaD 中存儲的 StorageD 位址(服務發現)的來源是 StorageD 的配置檔案,而它是 k8s 的内部位址。
這和 Nebula Graph 裡的服務發現機制有關:在 Nebula Graph 叢集中,Graph Service 和 Storage Service 都是通過心跳将自己的資訊上報給 Meta Service 的,而這其中服務自身的位址的來源則來自于他們相應的配置檔案中的網絡配置。
- 關于服務自身的位址配置請參考文檔:Storage networking 配置
- 關于服務發現詳細的資訊請參考四王的文章:圖資料庫 Nebula Graph 叢集通信:從心跳說起。
最後,我們知道 Nebula Operator 是一個在 K8s 叢集中按照配置,自動建立、維護、擴縮容 Nebula 叢集的 K8s 控制面的應用,它需要抽象一部分内部資源相關的配置,這就包括了 GraphD 和 StorageD 執行個體的實際位址,他們是被配置的位址實際上是 headless service 位址。
而這些位址(如下)預設是沒法被 K8s 外部網絡通路的,是以針對 GraphD、MetaD 我們可以友善建立服務将其暴露出來。
(root@nebula) [(none)]> show hosts meta
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
| Host | Port | Status | Role | Git Info Sha | Version |
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
| "nebula-metad-0.nebula-metad-headless.default.svc.cluster.local" | 9559 | "ONLINE" | "META" | "d113f4a" | "2.6.2" |
+------------------------------------------------------------------+------+----------+--------+--------------+---------+
Got 1 rows (time spent 1378/2598 us)
Mon, 14 Feb 2022 09:22:33 UTC
(root@nebula) [(none)]> show hosts graph
+---------------------------------------------------------------+------+----------+---------+--------------+---------+
| Host | Port | Status | Role | Git Info Sha | Version |
+---------------------------------------------------------------+------+----------+---------+--------------+---------+
| "nebula-graphd-0.nebula-graphd-svc.default.svc.cluster.local" | 9669 | "ONLINE" | "GRAPH" | "d113f4a" | "2.6.2" |
+---------------------------------------------------------------+------+----------+---------+--------------+---------+
Got 1 rows (time spent 2072/3403 us)
Mon, 14 Feb 2022 10:03:58 UTC
(root@nebula) [(none)]> show hosts storage
+------------------------------------------------------------------------+------+----------+-----------+--------------+---------+
| Host | Port | Status | Role | Git Info Sha | Version |
+------------------------------------------------------------------------+------+----------+-----------+--------------+---------+
| "nebula-storaged-0.nebula-storaged-headless.default.svc.cluster.local" | 9779 | "ONLINE" | "STORAGE" | "d113f4a" | "2.6.2" |
| "nebula-storaged-1.nebula-storaged-headless.default.svc.cluster.local" | 9779 | "ONLINE" | "STORAGE" | "d113f4a" | "2.6.2" |
| "nebula-storaged-2.nebula-storaged-headless.default.svc.cluster.local" | 9779 | "ONLINE" | "STORAGE" | "d113f4a" | "2.6.2" |
+------------------------------------------------------------------------+------+----------+-----------+--------------+---------+
Got 3 rows (time spent 1603/2979 us)
Mon, 14 Feb 2022 10:05:24 UTC
然而,因為前邊提到的 nebula-spark-connector 通過 Meta Service 去擷取 StorageD 的位址,且這個位址是服務發現而得,是以 nebula-spark-connector 實際上擷取的 StorageD 位址就是上邊的這種 headless 的服務位址,沒法直接從外部通路。
是以,我們在有條件的情況下,隻需要讓 Spark 運作在和 Nebula Cluster 相同的 K8s 網絡裡,一切就迎刃而解了,否則,我們需要:
- 将 MetaD 和 StorageD 的位址利用 Ingress 等方式将其 L4(TCP)暴露出來。
- 可以參考 Nebula Operator 的文檔:https://github.com/vesoft-inc/nebula-operator
- 通過反向代理和DNS讓這些 headless 服務能被解析到相應的 StorageD。
那麼,有沒有更友善的方式?
非常抱歉的是,目前最友善的方式依然是如文章最開頭所介紹:讓 Spark 運作在 Nebula Cluster 内部。實際上,我在努力推進 Nebula Spark 社群去支援可以配置的 StorageAddresses 選項,有了它之後,前邊提到的 2. 就是不必要的了。
更便捷的 nebula-algorithm + nebula-operator 體驗
為了友善在 K8s 上嘗鮮 nebula-graph、nebula-algorithm 的同學,這裡安利下本人寫的一個小工具 Neubla-Operator-KinD,它是個一鍵在 Docker 環境内部單獨部署一個 K8s 叢集,并在其中部署 Nebula Operator 以及所有依賴(包括 storage provider)的小工具。不僅如此,它還會自動部署一個小的 Nebula 叢集。可以看下邊的步驟哈:
第一步,部署 K8s + nebula-operator + Nebula Cluster:
curl -sL nebula-kind.siwei.io/install.sh | bash
第二步,照着工具文檔裡的 what’s next
a. 用 console 連接配接叢集,并加載示例資料集
b. 在這個 K8s 裡跑一個圖算法
- 建立一個 Spark 環境
kubectl create -f http://nebula-kind.siwei.io/deployment/spark.yaml
kubectl wait pod --timeout=-1s --for=condition=Ready -l '!job-name'
- 等上邊的 wait 都 ready 之後,進入 spark 的 pod。
kubectl exec -it deploy/spark-deployment -- bash
- 下載下傳 nebula-algorithm 比如 2.6.2 這個版本,更多版本請參考 https://github.com/vesoft-inc/nebula-algorithm/。
注意事項:
- 官方釋出的版本在這裡可以擷取:https://repo1.maven.org/maven2/com/vesoft/nebula-algorithm/
- 因為這個問題:https://github.com/vesoft-inc/nebula-algorithm/issues/42 隻有 2.6.2 或者更新的版本才支援域名通路 MetaD。
# 下載下傳 nebula-algorithm-2.6.2.jar
wget https://repo1.maven.org/maven2/com/vesoft/nebula-algorithm/2.6.2/nebula-algorithm-2.6.2.jar
# 下載下傳 nebula-algorthm 配置檔案
wget https://github.com/vesoft-inc/nebula-algorithm/raw/v2.6/nebula-algorithm/src/main/resources/application.conf
- 修改 nebula-algorithm 中的 mete 和 graph 位址資訊。
sed -i '/^ metaAddress/c\ metaAddress: \"nebula-metad-0.nebula-metad-headless.default.svc.cluster.local:9559\"' application.conf
sed -i '/^ graphAddress/c\ graphAddress: \"nebula-graphd-0.nebula-graphd-svc.default.svc.cluster.local:9669\"' application.conf
##### change space
sed -i '/^ space/c\ space: basketballplayer' application.conf
##### read data from nebula graph
sed -i '/^ source/c\ source: nebula' application.conf
##### execute algorithm: labelpropagation
sed -i '/^ executeAlgo/c\ executeAlgo: labelpropagation' application.conf
- 在 basketballplayer 圖空間執行 LPA 算法
/spark/bin/spark-submit --master "local" --conf spark.rpc.askTimeout=6000s \
--class com.vesoft.nebula.algorithm.Main \
nebula-algorithm-2.6.2.jar \
-p application.conf
- 結果如下:
bash-5.0# ls /tmp/count/
_SUCCESS part-00000-5475f9f4-66b9-426b-b0c2-704f946e54d3-c000.csv
bash-5.0# head /tmp/count/part-00000-5475f9f4-66b9-426b-b0c2-704f946e54d3-c000.csv
_id,lpa
1100,1104
2200,2200
2201,2201
1101,1104
2202,2202
下面,你就可以 Happy Graphing 啦!
想了解更多關于圖資料庫技術的内容?關注 Nebula Graph Community 公衆号 擷取更多資訊哦~