1. 概述
本文主要分享 SkyWalking Collector Cluster Module,負責叢集的管理,即 Collector 節點的注冊于發現。
友情提示:建議先閱讀 《SkyWalking 源碼分析 —— Collector 初始化》 ,以了解 Collector 元件體系。
Cluster Module 在 SkyWalking 架構圖處于如下位置( 紅框 ) :
FROM https://github.com/apache/incubating-skywalking
下面我們來看看整體的項目結構,如下圖所示 :
-
:定義叢集管理接口。collector-cluster-define
-
:基于 H2 的 叢集管理實作。該實作是單機版,建議僅用于 SkyWalking 快速上手,生産環境不建議使用。collector-cluster-standalone-provider
-
:基于 Redis 的叢集管理實作。目前暫未完成。collector-cluster-redis-provider
-
:基于 Zookeeper 的叢集管理實作。生産環境推薦使用collector-cluster-zookeeper-provider
下面,我們從接口到實作的順序進行分享。
2. collector-cluster-define
collector-cluster-define
:定義叢集管理接口。項目結構如下 :
- 互動如下圖 :
- ModuleListenerService 暴露給其他 Module 注冊監聽器 ( ClusterModuleListener ) 到 DataMonitor 。
- ModuleRegisterService 暴露給其他 Module 注冊元件登記( ModuleRegistration ) 到 DataMonitor 。
- 通過實作 DataMonitor 接口,基于不同的存儲器實作注冊發現。
2.1 ClusterModule
org.skywalking.apm.collector.cluster.ClusterModule
,實作 Module 抽象類,叢集管理 Module 。
#name()
實作方法,傳回子產品名為
"cluster"
。
#services()
實作方法,傳回 Service 類名:ModuleListenerService / ModuleRegisterService 。
2.2 ModuleRegisterService
org.skywalking.apm.collector.cluster.service.ModuleRegisterService
,繼承 Service 接口,子產品注冊服務接口。
#register(moduleName, providerName, registration)
接口方法,注冊子產品注冊資訊。一般情況下,實作該接口方法,調用
DataMonitor#register(path, registration)
方法。
2.2.1 ModuleRegistration
org.skywalking.apm.collector.cluster.ModuleRegistration
,子產品注冊資訊抽象類。不同 Module 通過實作 ModuleRegistration ,将它們注冊到 ModuleRegisterService。目前子類如下 :
#buildValue()
抽象方法,獲得子產品注冊資訊( Value )。
2.3 ModuleListenerService
org.skywalking.apm.collector.cluster.service.ModuleListenerService
,繼承 Service 接口,注冊監聽器服務接口。
#addListener(listener)
接口方法,添加監聽器。一般情況下,實作該接口方法,調用
DataMonitor#addListener(listener)
方法。
2.3.1 ClusterModuleListener
org.skywalking.apm.collector.cluster.ClusterModuleListener
,叢集元件監聽器抽象類。目前子類如下 :
構造方法,建立位址數組(
addresses
)。該數組的讀寫方法如下:
-
#addAddress(address)
-
#removeAddress(address)
-
#getAddresses()
#path()
抽象方法,傳回路徑。該路徑即為 ClusterModuleListener 監聽的“事件”。多個 Collector 節點的相同 Module ,通過路徑分組形成叢集。
#serverJoinNotify(serverAddress)
/
#serverQuitNotify(serverAddress)
抽象方法,通知服務的加入 / 下線。目前隻有 GRPCRemoteSenderService 真正( 其它都是空方法 )實作該方法,在 《SkyWalking 源碼分析 —— Collector Remote 遠端通信服務》「3.2 GRPCRemoteSenderService」 詳細解析。
2.4 DataMonitor
org.skywalking.apm.collector.cluster.DataMonitor
,資料螢幕接口。通過實作 DataMonitor 接口,基于不同的存儲器實作注冊發現。目前子類如下 :
#register(path, registration)
接口方法,注冊子產品注冊資訊。
#addListener(ClusterModuleListener)
接口方法,添加監聽器。
-
接口方法,獲得監聽指定路徑的監聽器。#getListener(path)
#setClient(Client)
接口方法,設定 Client 。在
client-component
有 ZookeeperClient / H2Client / ElasticSearchClient 等多種實作。
-
屬性,基礎目錄為BASE_CATALOG
。例如說,在 Zookeeper 為根節點的路徑。"/skywalking"
-
接口方法,使用 Client 建立路徑。#createPath(path)
-
接口方法,使用 Client 設定路徑的值。#setData(path)
3. collector-cluster-zookeeper-provider
collector-cluster-zookeeper-provider
,基于 Zookeeper 的叢集管理實作。項目結構如下 :
實際使用時,通過
application.yml
配置如下:
|
- 生産環境下,推薦 Zookeeper 配置成叢集。
3.1 ClusterModuleZookeeperProvider
org.skywalking.apm.collector.cluster.zookeeper.ClusterModuleZookeeperProvider
,實作 ModuleProvider 抽象類,基于 Zookeeper 的叢集管理服務提供者。
#name()
實作方法,傳回元件服務提供者名為
"zookeeper"
。
module()
實作方法,傳回元件類為 ClusterModule 。
#requiredModules()
實作方法,傳回依賴元件為空。
#prepare(Properties)
實作方法,執行準備階段邏輯。
- 第 63 行 :建立 ClusterZKDataMonitor 對象。
- 第 69 行 :建立 ZookeeperClient 對象。注意,此時并未連接配接 Zookeeper 。
- 第 71 至 73 行 :建立 ZookeeperModuleListenerService / ZookeeperModuleRegisterService 對象,并調用
父類方法,注冊到#registerServiceImplementation()
。services
#start()
實作方法,執行啟動階段邏輯。
- 第 79 行 :調用
方法,初始化 ZookeeperClient ,此時會連接配接 Zookeeper。ZookeeperClient#initialize()
#notifyAfterCompleted()
實作方法,執行啟動完成邏輯。
- 第 88 行 :調用
方法,啟動 ClusterZKDataMonitor 。在本文 「3.4 ClusterZKDataMonitor」 詳細解析。ClusterZKDataMonitor#start()
3.2 ZookeeperModuleRegisterService
org.skywalking.apm.collector.cluster.zookeeper.service.ZookeeperModuleRegisterService
,基于 Zookeeper 的子產品注冊服務實作類。
#register(moduleName, providerName, registration)
實作方法,調用
ClusterZKDataMonitor#register(path, registration)
方法,注冊子產品注冊資訊。
3.3 ZookeeperModuleListenerService
org.skywalking.apm.collector.cluster.zookeeper.service.ZookeeperModuleListenerService
,基于 Zookeeper 的注冊監聽器服務實作類。
#addListener(ClusterModuleListener)
實作方法,調用
ClusterZKDataMonitor#addListener(ClusterModuleListener)
方法,注冊子產品注冊資訊。
3.4 ClusterZKDataMonitor
org.skywalking.apm.collector.cluster.zookeeper.ClusterZKDataMonitor
,基于 Zookeeper 的資料螢幕實作類。
在看具體代碼實作之前,我們先來看看 Zookeeper 是如何存儲資料的,如下圖所示 :
- 紫色部分,通過調用
方法,順着路徑,逐層建立持久節點。#createPath(path)
- 黃色部分,通過調用
方法,建立臨時節點,設定 Collector 子產品位址。若 Collector 叢集有 N 個節點,則此處會有 N 個臨時節點。#setData(path)
- 打開
,我們來看一個例子 :zkClient.sh
[zk: localhost:2181(CONNECTED) 1] ls /skywalking
[remote, ui, agent_jetty, agent_gRPC]
[zk: localhost:2181(CONNECTED) 2] ls /skywalking/ui
[jetty]
[zk: localhost:2181(CONNECTED) 3] ls /skywalking/ui/jetty
[localhost:12800]
[zk: localhost:2181(CONNECTED) 4] get /skywalking/ui/jetty/localhost:12800
/
cZxid = 0x24
ctime = Thu Dec 14 16:05:25 CST 2017
mZxid = 0x24
mtime = Thu Dec 14 16:05:25 CST 2017
pZxid = 0x24
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x16052d8b9f40006
dataLength = 1
numChildren = 0
#register(path, registration)
實作方法,添加到元件注冊資訊集合(
registrations
)。
#start()
方法,啟動 ClusterZKDataMonitor ,将元件注冊資訊(
registrations
) 寫到 Zookeeper 中。
#addListener(listener)
實作方法,添加到監聽器集合(
listeners
)。
#process(WatchedEvent)
實作方法,處理有 Collector 節點的元件加入或下線。總體邏輯是,從 Zookeeper 擷取變更的路徑下的位址數組,和本地的位址(
ClusterModuleListener.addresses
)比較,處理加入或移除邏輯的位址。
- ClusterZKDataMonitor 實作
接口,是以實作該方法。org.apache.zookeeper.Watcher
- 該方法是
方法,以保證不會出現并發問題。synchronized
3.5 ZookeeperClient
org.skywalking.apm.collector.client.zookeeper.ZookeeperClient
,實作 Client 接口,Zookeeper 用戶端。
代碼比較簡單,胖友自己閱讀了解。
4. collector-cluster-standalone-provider
collector-cluster-standalone-provider.ClusterStandaloneDataMonitor
,基于 H2 的 叢集管理實作。該實作是單機版,建議僅用于 SkyWalking 快速上手,生産環境不建議使用。項目結構如下 :
大體實作和
collector-cluster-zookeeper-provider
差不多,差異在對 DataMonitor 的實作類 ClusterStandaloneDataMonitor 上。
在 ClusterStandaloneDataMonitor 裡,實際并未使用 H2Client ,而是基于記憶體,胖友可以自己檢視下。
5. collector-cluster-redis-provider
collector-cluster-redis-provider
:基于 Redis 的叢集管理實作。目前暫未完成。