歡迎光臨
每天分享高質量文章

分散式鏈路追蹤 SkyWalking 原始碼分析 —— Collector Cluster 叢集管理

本文主要基於 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 保證實時性

贊(0)

分享創造快樂