一、SkyWalking是一款 分布式追蹤系統,隨着微服務架構的流行,一些微服務架構下的問題也會越來越突出,比如一個請求會涉及多個服務,而服務本身可能也會依賴其他服務,整個請求路徑就構成了一個網狀的調用鏈,而在整個調用鏈中一旦某個節點發生異常,整個調用鏈的穩定性就會受到影響。skywalking通過使用字節碼增強技術實現對特定方法的監控,並收集數據用於分析。
二、名詞解釋
注:關於更詳細的名詞解釋,可以查看官網文檔 https://skyapm.github.io/document-cn-translation-of-skywalking/
1、trace:指的是整個微服務中的調用鏈路,通過traceid實現串聯。

2、tracesegment:在openTracing規范中沒有提到tracesegment,這個概念是在Skywalking中新增的,其概念可以理解為一個線程,其類型有跨進程和跨線程。
LeafSpan
. 例如 通過 JDBC 訪問 DB, 讀取 Redis/Memcached 被歸類為 ExitSpan.
為了實現分布式追蹤, 需要綁定跨進程的追蹤, 並且上下文應該在整個過程中隨之傳播. 這就是 ContextCarrier 的職責.
以下是有關如何在 A -> B
分布式調用中使用 ContextCarrier 的步驟.
- 在客戶端, 創建一個新的空的
ContextCarrier
. - 通過
ContextManager#createExitSpan
創建一個 ExitSpan 或者使用ContextManager#inject
來初始化ContextCarrier
. - 將
ContextCarrier
所有信息放到請求頭 (如 HTTP HEAD), 附件(如 Dubbo RPC 框架), 或者消息 (如 Kafka) 中 - 通過服務調用, 將
ContextCarrier
傳遞到服務端. - 在服務端, 在對應組件的頭部, 附件或消息中獲取
ContextCarrier
所有內容. - 通過
ContextManager#createEntrySpan
創建 EntrySpan 或者使用ContextManager#extract
來綁定服務端和客戶端.
讓我們通過 Apache HttpComponent client 插件和 Tomcat 7 服務器插件演示, 步驟如下:
- 客戶端 Apache HttpComponent client 插件
span = ContextManager.createExitSpan("/span/operation/name", contextCarrier, "ip:port"); CarrierItem next = contextCarrier.items(); while (next.hasNext()) { next = next.next(); httpRequest.setHeader(next.getHeadKey(), next.getHeadValue()); }
- 服務端 Tomcat 7 服務器插件
ContextCarrier contextCarrier = new ContextCarrier(); CarrierItem next = contextCarrier.items(); while (next.hasNext()) { next = next.next(); next.setHeadValue(request.getHeader(next.getHeadKey())); } span = ContextManager.createEntrySpan(“/span/operation/name”, contextCarrier);
四、上線文快照ContextSnapshot
除了跨進程, 跨線程也是需要支持的, 例如異步線程(內存中的消息隊列)和批處理在 Java 中很常見. 跨進程和跨線程十分相似, 因為都是需要傳播上下文. 唯一的區別是, 跨線程不需要序列化.
以下是有關跨線程傳播的三個步驟:
- 使用
ContextManager#capture
方法獲取 ContextSnapshot 對象. - 讓子線程以任何方式, 通過方法參數或由現有參數攜帶來訪問 ContextSnapshot
- 在子線程中使用
ContextManager#continued
五、上下文管理器 (ContextManager)
ContextManager 提供所有主要 API.
- 創建 EntrySpan
public static AbstractSpan createEntrySpan(String endpointName, ContextCarrier carrier)
根據操作名稱(例如服務名稱, uri) 和 上下文載體 (ContextCarrier) 創建 EntrySpan.
- 創建 LocalSpan
public static AbstractSpan createLocalSpan(String endpointName)
根據操作名稱(例如完整的方法簽名)創建 (e.g. full method signature)
- 創建 ExitSpan
public static AbstractSpan createExitSpan(String endpointName, ContextCarrier carrier, String remotePeer)
根據操作名稱(例如服務名稱, uri), 上下文載體 (ContextCarrier) 以及對等端 (peer) 地址 (例如 ip + port 或 hostname + port) 創建 ExitSpan.