本文主要基於 SkyWalking 3.2.6 正式版
- 1. 概述
- 2. collector-cluster-define
- 3. collector-cluster-zookeeper-provider
- 4. collector-cluster-standalone-provider
- 5. collector-cluster-redis-provider
1. 概述
本文主要分享 SkyWalking Collector Cluster Module,負責叢集的管理,即 Collector 節點的註冊於發現。
友情提示:建議先閱讀 《SkyWalking 原始碼分析 —— Collector 初始化》 ,以瞭解 Collector 元件體系。
Cluster Module 在 SkyWalking 架構圖處於如下位置( 紅框 ) :
FROM https://github.com/apache/incubating-skywalking
下麵我們來看看整體的專案結構,如下圖所示 :
collector-cluster-define
:定義叢集管理介面。collector-cluster-standalone-provider
:基於 H2 的 叢集管理實現。該實現是單機版,建議僅用於 SkyWalking 快速上手,生產環境不建議使用。collector-cluster-redis-provider
:基於 Redis 的叢集管理實現。目前暫未完成。collector-cluster-zookeeper-provider
:基於 Zookeeper 的叢集管理實現。生產環境推薦使用
下麵,我們從介面到實現的順序進行分享。
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` 屬性,基礎目錄為
"/skywalking"
。例如說,在 Zookeeper 為根節點的路徑。 - `#createPath(path)` 介面方法,使用 Client 建立路徑。
- `#setData(path)` 介面方法,使用 Client 設定路徑的值。
3. collector-cluster-zookeeper-provider
collector-cluster-zookeeper-provider
,基於 Zookeeper 的叢集管理實現。專案結構如下 :
實際使用時,透過 application.yml
配置如下:
JSON cluster: zookeeper: hostPort: localhost:2181 sessionTimeout: 100000
- 生產環境下,推薦 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#initialize()
方法,初始化 ZookeeperClient ,此時會連線 Zookeeper。
#notifyAfterCompleted()
實現方法,執行啟動完成邏輯。
- 第 88 行 :呼叫
ClusterZKDataMonitor#start()
方法,啟動 ClusterZKDataMonitor 。在本文 「3.4 ClusterZKDataMonitor」 詳細解析。
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)` 方法,順著路徑,逐層建立持久節點。
-
黃色部分,透過呼叫 `#setData(path)` 方法,建立臨時節點,設定 Collector 模組地址。若 Collector 叢集有 N 個節點,則此處會有 N 個臨時節點。
-
開啟
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 的叢集管理實現。目前暫未完成。
【TODO 4003】等實現後來寫寫,基於 Redis Pub Sub 保證實時性