--- title: Zeroc Ice RPC框架中的攔截器與Elastic APM分散式資料追蹤技術結合 tags: Ice, ElasticAPM --- # Zeroc Ice RPC框架中的攔截器與Elastic APM分散式資料追蹤技術結合 ## 前言: 此文件中會使用到RPC、AOP、APM、Distributed data trace等技術與專有名詞,文中會簡單描述其作用,詳細原理與工具說明如果有不清楚的地方請自行google。 當服務端收到客戶端的一次請求操作,可能需要經過多個系統、多個處理邏輯、多個中間件、多台不同的服務容器/設備互相協助處理才完成,這一系列的調用請求中可能是同步執行處理的;可能是異步執行處理的,那麼究竟要完成一個客戶發出的請求需要經過多少操作?跨過多少服務?先後調用的順序為何?每個業務邏輯單元花費多少時間或效能?隨著分散式服務架構與系統模型日趨複雜化的情況下,傳統的單機效能監測與日誌系統已無法有效的發揮效用,而是需要一個能追蹤整個調用過程的追蹤紀錄來協助團隊找出問題、精進效能。 ## 目錄: [TOC] ## 目標: 使用非侵入式的方式追蹤應用邏輯的運作與遠程調用的整體紀錄、並且將追蹤紀錄(TraceID)繼續往後傳遞並結合整個調用過程的紀錄,可以用來發現應用邏輯中是否有瓶頸作業、可以改善效能的區塊、併發與同步程序的運作狀況,並且不影響應用邏輯的開發過程,可以讓開發人員專心在應用邏輯的開發上。 ## 實現方式: 將Ice的攔截器加上Elastic APM的追蹤功能並起打包成一個可直接引用且盡可能不影響應用邏輯的工具方便給應用端開發上使用。 - 攔截器+APM示意圖: ![](https://i.imgur.com/FAWd6Vj.png) 此攔截器完成後,在每個要被調用的Ice物件啟動前先注入攔截器,完成注入之後再加入Ice服務,啟動此服務後會在被調用時觸發攔截器並開始業務邏輯的追蹤程序,藉此完成分散式資料追蹤 **Distributed data trace** - 運作示意圖: ![分散式追蹤範例圖](https://whyjava.files.wordpress.com/2019/04/distributed-tracing.jpg) ## 使用技術簡介: ### 1. [ZeroC Ice](https:// "https://doc.zeroc.com/") Zeroc ICE ( Internet Communications Engine ),一個物件導向式的RPC(Remote Procedure Call)框架,支持不同語言間的服務調用,使用Ice統一調用語言Slice定義服務接口並轉換成對應語言並實作其應用邏輯之後由Ice保證資料通訊的安全與可靠性。 Ice運作的架構圖: ![](https://doc.zeroc.com/ice/files/3.7/14026204/15073649/1/1434992569000/Ice_Client_and_Server_Structure.gif) 要使用Ice跟其支援的程式語言結合前需要定義服務接口,Ice有提供一個共通語言Slice供使用者自行定義要交換的資料格式,使用Slice語言定義要通訊的服務接口,並且使用Ice提供的編譯器轉成該語言可使用的資料格式。 Ice也準備了API來讓使用者可以針對通訊過程進行管理動作,在本次的範例中使用了Ice框架提供的**攔截器介面**,並使用此介面與**Elastic APM**結合,以達到分布式資料追蹤的功能。 ### 什麼是攔截器(Interceptor)? 在物件導向語言(OOP)中為了能將共用邏輯(Log、偵錯、追蹤)單獨抽出,發展出了AOP(Aspect-oriented programming)設計模式,此模式運作下實務上會是在指定的物件、方法、業務邏輯外包裝一個共通的物件用來攔截此物件、方法、業務被調用前、執行中、調用後的資料變化與運作紀錄等***需要被記錄但是與業務邏輯沒有直接關連的訊息。*** ![](https://www.edureka.co/blog/wp-content/uploads/2019/01/Java-.jpg) ### 2. [Elastic APM](https://www.elastic.co/guide/en/apm/get-started/current/index.html)(以下簡稱APM) Elastic APM為一款基於Elastic Stack建構的APM(Application performance management)服務,用途為收集有關傳入請求,數據庫查詢,對緩存的調用,外部HTTP請求等的響應時間的詳細性能信息。這樣可以輕鬆快速地找出並解決性能問題。 APM還會自動收集未處理的錯誤和異常。錯誤主要根據堆棧跟踪進行分組,因此您可以在新錯誤出現時識別它們,並密切注意特定錯誤發生的次數。 - 架構圖: ![](https://www.elastic.co/guide/en/apm/get-started/current/images/apm-architecture-cloud.png) - APM符合[OpenTrancing](https://www.elastic.co/blog/distributed-tracing-opentracing-and-elastic-apm)格式,主要是追蹤Tracing的相關資料。 ![](https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltd249957e822769f9/5c98d61beb3c40e859703c1a/blog-opentracing-elastic-apm-2.png) ### 3.什麼是OpenTracing? 由Google提出的一個使用於分佈式追蹤的格式規範,APM使用的資料格式是遵循此規範,[Open Trancing](https://opentracing.io/)的基本概念和基本資料模型來自Google的Dapper論文。關鍵概念包括跟踪(Trace)和跨度(span)。 **OpenTracing 示意圖** ![OprnTracing 示意圖](https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltf922d3d931f16598/5c98d5fcd3c73ef55e9ea9c2/blog-opentracing-elastic-apm-6.png) ### 4. APM的資料結構: ### [Elastic APM Data Model](https://www.elastic.co/guide/en/apm/get-started/current/apm-data-model.html),在官方文件有下面四種標準定義 - **Spans** - 包含指定程式碼路徑執行的訊息,量測活動的開始與結束,並且跟其他Span有父子關係 - StackTrace示意圖 ![](https://i.imgur.com/ikKfmIe.png) - **Transactions** - 在APM中為一種特殊的Span並且包含其他與其關聯的屬性,在APM中被視為最高水平工作,依照官方給的範例,Transaction可能為 - 請求到您的服務器 - 批處理作業 - 後台工作 - 自定義交易類型 - Transaction示意圖 ![](https://i.imgur.com/dPO4aT6.png) - **Errors** - 有關Exception發生的原始訊息或是有關Log發生異常時創建的訊息,並且會記錄對應的Transaction Id與相關環境資料 - 錯誤追蹤示意圖 ![](https://i.imgur.com/qoTARVf.png) - **Metrics** - APM Agent會自動抓取主機的相關資料,包含系統基本資料、CPU、記憶體等資訊 - Metric 示意圖 ![](https://i.imgur.com/As1m523.png) 每個Span中也可以包含使用者自行定義的[標籤(Label)](https://www.elastic.co/guide/en/apm/get-started/current/metadata.html) ### C# 此Ice攔截器與APM搭配的實作這次是使用在C#上,以下節錄維基百科對於C#的說明: - C#是微軟推出的一種基於.NET框架的、物件導向的進階程式語言。C#是一種由C和C++衍生出來的物件導向的程式語言。它在繼承C和C++強大功能的同時去掉了一些它們的複雜特性,使其成為C語言家族中的一種高效強大的程式語言。C#以.NET框架類別館作為基礎,擁有類似Visual Basic的快速開發能力。C#由安德斯·海爾斯伯格主持開發,微軟在2000年發布了這種語言,希望藉助這種語言來取代Java。C#已經成為Ecma國際和國際標準組織的標準規範。 - 詳細關於C#資料請參考微軟[官方文件](https://docs.microsoft.com/zh-tw/dotnet/csharp/) --- # 測試紀錄 ### 1. 測試架構 ##### **呼叫端 <---> 中間層 <---> 被呼叫端** * 三端皆使用C#+Ice來建置 * 攔截器加在中間層與被呼叫端 * 攔截器使用APM的PublicAPI工具設監控點(.net Core只能使用此模式) * 中間層與被呼叫端使用Async模式 ### 2. APM架設 * 使用三個容器於本機運作(Kibana+Elasticsearch+APM),皆使用預設值執行 1. APM版本 7.8.1 2. Elasticsearch版本 7.8.1 3. Kibana版本 7.8.1 ![Elastic tool container](https://i.imgur.com/GaBVTwk.png) ### 3. APM運作結果 結論: 1. StackTrace在執行時間小於5000us的情況下不會有值(預設值) 2. Ice中間件的運作架構上自帶攔截器,在Ice產生的介面中直接使用Ice的攔截器取得傳入的上下文,並使用此上下文傳遞APM Transaction參數 3. 為確保Transaction啟動時不會抓到現有已存在的其他Transaction資料,啟動時需要加入第四參數為true **[語法範例]** ![語法範例](https://i.imgur.com/qZpfOkP.png) 4. APM的Transaction代表的是該服務的某段業務邏輯運作時間,下面可以繼續堆疊Transaction/Span,在Span中才會有Stacktrace資料,Transaction主要是宣告這段業務邏輯的運作時間。 5. 每組Transaction必須確保是獨立的Traceid,否則在異步呼叫時資料會錯亂,此TraceID在預設啟動的狀態下會抓取C#中`System.Diagnostics.Activity`中產生的值,此作業在[MSDN](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.activity.current?view=netcore-3.1)中有說明會跨Task ( This flows across async calls. ),所以在異步呼叫時會發生APM無法正確關閉Transaction/Span的狀況,導致Traceid跨多筆Transaction,[請參考此文件](https://hackmd.io/@qEEgpA_LSdqDPbbuwphNGw/HkPM1w9Gv)內有問題發現與排除過程記錄。 - **[錯亂的資料]** ![](https://i.imgur.com/90f3Mhd.png) - **[Transaction/Span traceId]** ![](https://i.imgur.com/TwW6giJ.png) - **[每組交易只應該有單獨的Trace id]** ![](https://i.imgur.com/BzOJnwi.png) 6. 每個APM紀錄一定是由Transaction開頭,開始堆疊的Timeline則沒有限制下面為transaction/span,span下方則是可以繼續接span/Transaction。 - **[span堆疊圖]** ![span堆疊圖](https://i.imgur.com/KQFSszC.png) - **[Span子從關係]** ![Span子從關係](https://i.imgur.com/U0Ok54y.png) 7. 跨服務器的對應則是導出一組序號,並且在另外一台服務起使用APM的API將連結建立,並且會開啟一組新的Transaction跟在主要的Transaction下 - **[跨服務器表示]** ![跨服務器表示](https://i.imgur.com/o6FjUwT.png) ### 問題紀錄 1. [APM Traceid重複問題檢查](https://hackmd.io/@qEEgpA_LSdqDPbbuwphNGw/HkPM1w9Gv) 2. 攔截器中,被攔截目標如果為同步模式使用`Task.ContinueWith()`無法正常執行 - Ice攔截器在同步與非同步運作下傳回的任務模式內容不同 1. 同步傳回值:`null` 2. 非同步傳回值:`Task<OutputStream>` - 在此狀況下加入判斷來確認為何種呼叫: ``` if (TaskResult == null) { span.End(); transaction.End(); } else { result.ContinueWith((T) => { span.End(); transaction.End(); }); } ``` --- # 參考資料 [ZeroC Ice](https:// "https://doc.zeroc.com/") [Elastic APM](https://www.elastic.co/guide/en/apm/index.html) [Open Trancing](https://opentracing.io/) [MSDN C# Activity](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.activity.current?view=netcore-3.1) [APM Traceid重複問題檢查](https://hackmd.io/@qEEgpA_LSdqDPbbuwphNGw/HkPM1w9Gv) [DTD 圖示來源參考](https://shekhargulati.com/2019/04/08/a-minimalistic-guide-to-distributed-tracing-with-opentracing-and-jaeger/)