net core 微服務框架 Viper 呼叫鏈路追蹤

杜燕明發表於2020-10-25

1、Viper是什麼?

  Viper 是.NET平臺下的Anno微服務框架的一個示例專案。入門簡單安全穩定高可用全平臺可監控。底層通訊可以隨意切換thrift grpc 自帶服務發現、呼叫鏈追蹤、Cron 排程、限流、事件匯流排、CQRS 、DDD、類似MVC的開發體驗,外掛化開發

  一個不可監控的微服務平臺是可怕的,出了問題 難以準確定位問題的根源, Anno則提供了一套完整的監控體系,包括鏈路追蹤服務佔用的系統資源、系統自身 CPU、記憶體、硬碟使用率實時可監控等等。

github:
https://github.com/duyanming/Viper
文件地址:
https://duyanming.github.io/

體驗地址:(體驗使用者為anno 密碼123456 同一時間一個使用者只能在一個終端登入使用者多的時候可能發生強制退出的情況,稍後登入體驗)
http://140.143.207.244/

如果對Viper不瞭解可以看:

  1、 net core 微服務 快速開發框架 Viper 初體驗

  2、打不死的小強 .net core 微服務 快速開發框架 Viper 限流

2、Viper呼叫鏈追蹤 

  當我們進行微服務架構開發時,通常會劃分出多個微服務,各服務之間通過RPC進行呼叫。一個業務操作,可能需要多個微服務的協同才能完成,在業務呼叫鏈路上任何一個微服務出現問題或者網路出現問題,都會導致業務失敗。隨著業務越來越複雜,微服務之間的協作也越來越多,越來越複雜。如果不能直觀的看到整個呼叫鏈路,那麼我們就無法快速、準確的定位問題、解決問題,有甚者出現服務之間出現死迴圈呼叫拖垮整個叢集。這樣我們不僅不能嚐到微服務給我們帶來的好處,反而引入了一堆更復雜的問題。因此對於一個微服務系統鏈路追蹤是必要的。

   Viper為服務之間呼叫提供了一套完善的鏈路追蹤體系。通過Viper可以清晰的看到一個呼叫鏈(一次業務操作)經過了哪些微服務、每個服務消耗多少時間、是否出現異常、處理結果如何等等。通過鏈路追蹤體系可以分析整個業務的狀態,比如那個服務或者業務操作耗時異常需要優化,快速定位問題解決問題。從而更好的為整個微服務體系服務。

  不僅如此還可以幫助公司新入職員工梳理梳理業務脈絡,明白自己所處在的業務環節、預測系統可能發生的隱患,早發現早解決,防患於未然。

鏈路追蹤列表:

  單個鏈路追蹤示例:

  下面這個呼叫鏈路為:

   

   整個呼叫鏈路花費22毫秒,最後兩個呼叫為並行。

 

3、Viper&Anno 遠端過程呼叫(RPC)

  Anno 框架底層Rpc採用了成熟的 thrift(首選推薦)grpc他們都有著高效能跨語言的特點,因此Anno框架也是一個跨語言的,可以輕鬆實現混合程式設計的框架。目前支援.net core、.net framework、java,更多的實現期待大家共同努力一起貢獻。

  Thrift是一種介面描述語言和二進位制通訊協議,它被用來定義和建立跨語言的服務。它被當作一個遠端過程呼叫(RPC)框架來使用,是由Facebook為“大規模跨語言服務開發”而開發的。目前託管在Apache,更多詳細可翻閱網上資料。

  

  grpc 是一個高效能、開源和通用的 RPC 框架,面向移動和 HTTP/2 設計。目前提供 C、Java 和 Go 語言版本,分別是:grpc, grpc-java, grpc-go. 其中 C 版本支援 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支援.

  gRPC 基於 HTTP/2 標準設計,帶來諸如雙向流、流控、頭部壓縮、單 TCP 連線上的多複用請求等特。這些特性使得其在移動裝置上表現更好,更省電和節省空間佔用。

 

以Thrift為例來了解Anno框架

  Anno框架的 Thrift介面描述檔案:

namespace csharp Anno.Rpc   #  名稱空間
struct Micro {   #  服務資訊
    1: string ip
    2: i32 port
    3: i32 timeout
    4: string name
    5: string nickname
    6: i32 weight
  }
service BrokerService {  #  Provider服務
    string broker(1:map<string,string>  input)
}
service BrokerCenter {  #  註冊中心
    bool add_broker(1:map<string,string>  input)
    list<Micro> GetMicro(1:string  channel)
    string Invoke(1:map<string,string>  input)
}

服務之間通訊的介面為 string broker(1:map<string,string> input),服務之間通訊採用的是 Thrift的 二進位制傳輸。

/// <summary>
    /// Engine 常量
    /// </summary>
    public static class Eng
    {
        /// <summary>
        /// 名稱空間
        /// </summary>
        public const string NAMESPACE = "channel";
        /// <summary>
        ////// </summary>
        public const string CLASS = "router";
        /// <summary>
        /// 方法
        /// </summary>
        public const string METHOD = "method";
    }
channel、router、method此三個引數是遠端過程呼叫過程中的必須引數
以外掛 Anno.Plugs.LogicService為例
namespace Anno.Plugs.LogicService
{
    using Anno.CommandBus;

    public class PlatformModule : BaseModule
    {
        --------------省略-------------------
        /// <summary>
        /// 獲取使用者功能
        /// </summary>
        /// <returns></returns>
        [AnnoInfo(Desc = "獲取使用者功能")]
        public ActionResult GetFunc()
        {
            return _platformQuery.GetFunc(Profile);
        }
    }
}    
channel 對應:Anno.Plugs.Logic
router  對應:Platform
method  對應:GetFunc

保留關鍵字:TraceId,PreTraceId,AppName,AppNameTarget,GlobalTraceId,TTL,X-Original-For
TraceId:一次Rpc呼叫成為一個span,這個呼叫的唯一標識為TraceId
PreTraceId:服務之間相互呼叫的時候PreTraceId用來標識父子關係的父TraceId
AppName:當前服務名稱
AppNameTarget:目標服務名稱
GlobalTraceId:一次使用者操作或者是系統人物成為一個呼叫鏈,這個呼叫鏈的唯一標識為GlobalTraceId
TTL:跨越的服務次數
X-Original-For:web呼叫的時候的使用者IP 

2、Viper呼叫鏈追蹤體系解析 

  Viper的呼叫鏈式內嵌在 Anno.Rpc.Client中的,Rpc呼叫之前建立追蹤物件sys_trace記錄Request引數,呼叫完成之後完善響應Response結果並且把追蹤物件sys_trace寫入記憶體佇列中。然後定時定量傳送到追蹤伺服器。

虛擬碼如下:

   /// <summary>
    /// 追蹤佇列池
    /// </summary>
    public static class TracePool
    {
     //記憶體佇列
private static ConcurrentQueue<sys_trace> TraceQueue { get; set; } = new ConcurrentQueue<sys_trace>();      //業務處理後推送追蹤物件到記憶體佇列 TraceQueue public static void EnQueue(sys_trace trace, string result) { if (trace != null) { trace.UseTimeMs = (DateTime.Now - trace.Timespan).TotalMilliseconds; trace.Response = result; TraceQueue.Enqueue(trace); } }
     //建立追蹤物件
public static sys_trace CreateTrance(Dictionary<string, string> input) { return new sys_trace() { Timespan = DateTime.Now, InputDictionary = input }; } /// <summary> /// 批量傳送呼叫鏈到 追蹤伺服器(定時任務會定時呼叫TryDequeue) /// </summary> internal static void TryDequeue() { if (TraceQueue.IsEmpty) { return; } List<sys_trace> traces = new List<sys_trace>(); ReTryDequeue: while (!TraceQueue.IsEmpty && traces.Count < 100) { TraceQueue.TryDequeue(out sys_trace trace);
   ------------轉換追蹤物件--------------
if (trace.Rlt) { trace.Response = null; } traces.Add(trace); } if (traces.Count <= 0) { return; } Dictionary<string, string> inputTrace = new Dictionary<string, string> { {Const.Enum.Eng.NAMESPACE, "Anno.Plugs.Trace"}, {Const.Enum.Eng.CLASS, "Trace"}, {Const.Enum.Eng.METHOD, "TraceBatch"}, {"traces", Newtonsoft.Json.JsonConvert.SerializeObject(traces)} };
       //傳送追蹤資料 Connector.BrokerDns(inputTrace);
if (!TraceQueue.IsEmpty) { traces.Clear(); goto ReTryDequeue; } } }

  

Viper

github:
https://github.com/duyanming/Viper
文件地址:
https://duyanming.github.io/

體驗地址:(體驗使用者為anno 密碼123456 同一時間一個使用者只能在一個終端登入使用者多的時候可能發生強制退出的情況,稍後登入體驗)
http://140.143.207.244/

 

關於Viper的更多內容,隨後更新。敬請關注。開源不易,感謝Star。

相關文章