分散式追蹤 & APM 系統 SkyWalking 源碼分析
1. 概述
本文主要分享 Agent DictionaryManager 字典管理。先來簡單了解下字典的定義和用途:
字典實際上是一個 Map 映射。目前 Agent 上有兩種字典:應用編碼與應用編號的映射,操作名與操作編號的映射。
應用的定義:例如,Tomcat 啟動的應用,或者程序里訪問的 MongoDB 、MySQL 都可以認為是應用。
操作的定義:例如,訪問的 URL 地址,Mongo 的執行操作。
Agent 在每次上傳調用鏈路 Segment 給 Collector 時,Segment 裡面需要包含應用和操作相關信息。考慮到減少網路流量,應用編號少於應用編號,操作編號少於操作名。
Agent 字典,會定時從 Collector 【同步】需要( 需要的定義,下文代碼會看到 )的字典。
Advertisements
下面,我們分成兩個小節,分別從 API 的實現與調用,分享代碼的具體實現。
2. Collector 同步相關 API
Collector 同步相關 API 相關有四個介面:
2.1 應用的同步 API
2.2 操作的同步 API
API 處理的流程大體如下:
2.1 應用的同步 API
應用的同步 API ,實際使用的是應用的註冊 API。
2.2 操作的同步 API
我們先來看看 API 的定義,DiscoveryService,如下圖所示:
整體代碼和 「2.1 應用的同步 API」 非常相似,所以本小節,更多的是提供代碼的鏈接地址。
2.2.1 ServiceNameDiscoveryServiceHandler#discovery(…)
Advertisements
ServiceNameDiscoveryServiceHandler#discovery(ServiceNameCollection,
StreamObserver<ServiceNameMappingCollection>)
,根據操作名數組,查找操作編號數組。
2.2.2 IServiceNameService#getOrCreate(…)
org.skywalking.apm.collector.agent.stream.service.register.IServiceNameService
,繼承Service 介面,操作名服務介面。
定義了 #getOrCreate(applicationId, serviceName) 介面方法,根據應用編號 + 操作名字,獲取或創建操作名( ServiceName ),並獲得操作編號。
org.skywalking.apm.collector.agent.stream.worker.register.ServiceNameService
,實現 IServiceNameService 介面,操作名服務實現類。實現了 #getOrCreate(applicationId, serviceName)方法。
2.2.3 Graph#start(ServiceName)
在 #createServiceNameRegisterGraph() 方法中,我們可以看到 ServiceName 對應的Graph<ServiceName>對象的創建。教學資料加QQ:1728804959
org.skywalking.apm.collector.agent.stream.worker.register.ServiceNameRegisterRemoteWorker ,繼承 AbstractRemoteWorker 抽象類,操作名註冊遠程 Worker 。
org.skywalking.apm.collector.agent.stream.worker.register.ServiceNameRegisterSerialWorker ,繼承 AbstractLocalAsyncWorker 抽象類,非同步保存應用 Worker 。
相同於 Application ,ServiceName 的操作編號,從
"1"
雙向遞增。ServiceNameEsRegisterDAO#save(ServiceName)
2.2.4 ServiceName
org.skywalking.apm.collector.storage.table.register.ServiceName ,操作名。例如記錄在 ES 如下圖:
3. Agent 調用同步 API
在 《SkyWalking 源碼分析 —— 應用於應用實例的註冊》「3. Agent 調用註冊 API」 一文中,在 【第 170 至 173 行】的代碼,我們可以看到,AppAndServiceRegisterClient 會定時從 Collector 同步所有字典信息。
3.1 DictionaryManager
org.skywalking.apm.agent.core.dictionary.DictionaryManager ,字典管理器。目前管理有兩種字典:
ApplicationDictionary
OperationNameDictionary
3.1 ApplicationDictionary
org.skywalking.apm.agent.core.dictionary.ApplicationDictionary
,應用字典。教學資料加QQ:1728804959
INSTANCE
枚舉屬性,單例。
applicationDictionary
屬性,應用編碼與應用編號的映射。
unRegisterApplications
屬性,未知應用編碼集合。Agent 會定時從 Collector 同步。這也是文章開頭說的,「需要」的定義。
#find(applicationCode)
方法,根據應用編碼,查詢應用編號。
第 57 行:根據應用編碼,從
applicationDictionary
中,查詢應用編號。
第 58 至 59 行:當應用編號查找到時,返回 Found 。Found 會在下文詳細解析。
第 61 至 64 行:當應用編號查找不到時,添加到
unRegisterApplications
中,返回 NotFound 。NotFound 會在下文詳細解析。
#syncRemoteDictionary(ApplicationRegisterServiceGrpc.ApplicationRegisterServiceBlockingStub)
方法,調用 「2.1 應用的同步 API」 ,從 Collector 同步
unRegisterApplications
對應的應用編號集合。
3.2 OperationNameDictionary
org.skywalking.apm.agent.core.dictionary.OperationNameDictionary
,操作名字典。
和 ApplicationDictionary 基本類似,胖友點擊 代碼 ,自己閱讀理解。
3.2 PossibleFound
在分享 PossibleFound 之前,我們先來看一段代碼,了解該類的意圖:
我們在使用
XXXXDictionary#find(xxx)
方法時,返回的會是 Found 或者 NotFound 。這兩個類本身是互斥的,並且繼承 PossibleFound 。在 PossibleFound 提供
#doInCondition(method01, method02)
方法,優雅的處理兩種情況。
org.skywalking.apm.agent.core.dictionary.PossibleFound ,抽象類,代碼如下:
found
屬性,是否找到。
value
屬性,找到的結果。
org.skywalking.apm.agent.core.dictionary.Found 實現 PossibleFound 類,
found = true
並且
value
為找到的值。
org.skywalking.apm.agent.core.dictionary.NotFound 實現 PossibleFound 類,
found = false
並且
value
不賦值。
#doInCondition(Found, NotFound)
方法,根據查找結果,執行不同的邏輯,【無返回】。
第一個參數,PossibleFound.Found 介面,Found 時的處理邏輯介面。
第二個參數,PossibleFound.NotFound 介面,NotFound 時的處理邏輯介面。
#doInCondition(FoundAndObtain, NotFoundAndObtain)
方法,根據查找結果,執行不同的邏輯,【有返回】。
第一個參數,PossibleFound.FoundAndObtain 介面,Found 時的處理邏輯介面。
第二個參數,PossibleFound.NotFoundAndObtain 介面,NotFound 時的處理邏輯介面。