net core 微服务框架 Viper 调用链路追踪

1、Viper是什么?

  Viper 是.NET平台下的Anno微服务框架的一个示例项目。入门简单安全稳定高可用全平台可监控。底层通讯可以随意切换thrift grpc 自带服务发现、调用链追踪、Cron 调度、限流、事件总线、CQRS 、DDD、类似MVC的开发体验,插件化开发

  一个不可监控的微服务平台是可怕的,出了问题 难以准确定位问题的根源, Anno则提供了一套完整的监控体系,包括链路追踪服务占用的系统资源、系统自身 CPU、内存、硬盘使用率实时可监控等等。

github:
//github.com/duyanming/Viper
文档地址:
//duyanming.github.io/

体验地址:(体验用户为anno 密码123456 同一时间一个用户只能在一个终端登录用户多的时候可能发生强制退出的情况,稍后登录体验)
//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:
//github.com/duyanming/Viper
文档地址:
//duyanming.github.io/

体验地址:(体验用户为anno 密码123456 同一时间一个用户只能在一个终端登录用户多的时候可能发生强制退出的情况,稍后登录体验)
//140.143.207.244/

 

关于Viper的更多内容,随后更新。敬请关注。开源不易,感谢Star。

Tags: