一、背景

对于分布式在线服务,一个请求需要经过多个系统中多个模块,可能多达上百台机器的协作才能完成单次请求。这种场景下单靠人力无法掌握整个请求中各个阶段的性能开销,更无法快速的定位系统中性能瓶颈。当发生故障时通常需要查看大量日志跨越多个团队来确认问题。

二、举个栗子

程序猿小亮作为一个在职场摸爬滚打多年资深工程师,他可能面临的系统设计是这个样子的,如下图。

(图片来自于网络)

借助良好的系统设计和编码规范,对于一般有问题的请求处理,小亮依据自己对多个系统的了解通过翻阅大量的日志文件(前提是日志输出也需要规范)花费两个小时来定位到问题。随着用户的不断增长系统复杂度也呈现指数增长,小亮的大部分时间都浪费在了团队沟通之类的工作上。小亮的幸福指数也像系统复杂度一样呈现指数下降。

小亮这时可能会想,要是有一个东西能把每次请求经过的系统都记录下来,要是能把每个节点消耗时间、处理类神马的信息也抓出来那这个世界得多么美好。

一个偶然的机会小亮知道了UAVStack其中一个叫做调用链的神奇功能,在对业务代码没有任何侵入的前提下轻松解决了他的难题。下面就让我们一起来开启一段探索UAVStack的神奇之旅。

UAVStack调用链技术栈支持

三、效果展示

轻型调用链展示详情:

重调用链开启以后请求报文体抓取视图:

更多使用技巧和说明请参阅官网:https://uavorg.github.io/documents/uavdoc_useroperation/91.html(用户指南中调用链部分)。

四、具体实现

UAVStack调用链实现分为模型设计、服务端信息收集(轻/重)、方法级信息收集(轻/重)、客户端信息收集(轻/重)、调用链协议设计(轻/重)、调用链上下文传递、调用信息记录及传递、调用数据统计处理等。由于篇幅限制,本期暂时只分享其中的模型设计及实现调用链模型时序图。

五、模型设计

借鉴前人经验并揉合具体业务场景需求,抽象出了如下调用链模型:

调用链元数据:

1)SpanEndpointType:调用类型(Root(“E”),Service(“S”), Client(“C”), Method(“M”));

Root指本条调用链中的第一个节点,即一条调用链的开始位置,可以是一个服务请求,一次httpclient调用等;

Service指当前调用链中非第一个节点且是系统中对外提供的服务,如用户登录服务;

Client指当前调用链中非第一个节点且是当前系统与外部沟通的一种途径,如httpclient、mongoclient等;

Method值当前调用链中非第一个节点且是系统中的一个函数,如日志数出函数等。

2)traceId:调用链唯一标识符;

3)spanId:一条调用链中当前节点的调用顺序(与SpanEndpointType 结合唯一);spanId采用分层设计,形如1.2.1,既能表示调用顺序同时又能反应所才调用链层级;

4)parentId:一条调用链中当前节点的父调用节点。

调用链绘制规则:

1)调用者(服务、web)最初调用(无父调用)记为开始节点E,并生成唯一调用链ID,traceID;

2)系统内应用组件调用(如httpclient,方法调用等),spanId末尾数字加1(若为第一个则末尾加.1);

3)系统间调用(如A服务调用B服务),A服务与B服务span信息只有SpanEndpointType不同(分别对应span的两个端)。

举个栗子

背景介绍:用户小明想通过网络获取一些知识,通过网络他进入了系统O。服务O中部署了服务A和B,A服务使用httpclient与B通讯,B服务先会与redis交互然后和myql交互,最后系统O将小明感兴趣的内容返回给小明;

完成此次请求UAV抽象出如下调用链模型:

1)小明(下图中的调用方)通过门户访问了A服务,此时调用链生成唯一traceId并将当前节点的SpanEndpointType置为N(第一个节点的意思),spanId置为1(当前调用层中的第一个节点),parentId置为E(没有父节点的意思);

2)A服务通过httpclient向B服务发起一次http请求,此时调用链元数据如下traceId(沿用父节点id);1.1(spanId末尾加.1,因为为第一次调用);1(parentId父节点的spanId);C(调用类型记录为C客户端调用);

3)B服务接收到来自于A服务通过httpclient的调用,此时调用链元数据如下traceId(沿用初始调用时id);1.1(spanId沿用传递过来的spanId);1(parentId沿用传递过来的parentId);S(调用类型记录为S服务端处理请求);

4)B服务先查询redis,此时调用链元数据如下traceId(沿用初始调用时id);1.1.1(spanId末尾加.1,因为为第一次调用);1.1(parentId父节点的spanId);C(调用类型记录为C客户端调用);

5)B服务又发起对mysql的查询,此时调用链元数据如下traceId(沿用初始调用时id);1.1.2(spanId末尾数字加1,因为为非第一次调用);1.1(parentId父节点的spanId);C(调用类型记录为C客户端调用);

6)处理结束,调用链将记录的信息进行记录。

调用链时序图

UAVServer:中间件增强框架,提供在中间件的不同生命周期进行劫持的能力,即中间件劫持技术,如tomcat webcontainer启动开始时刻等;

JEEServiceRunGlobalFilterHandler:借助中间件劫持技术延伸出的全局filter,能够拦截所有经过中间件(tomcat等)的请求;

ServiceSpanInvokeChainHandler:调用链中专注处理归为Service类型节点的handler;

ClientSpanInvokeChainHandler:调用链中专注处理归为Client类型节点的handler;

XXAdapter:泛指调用链中所有的adapter,提供在handler(分为Service、Client、Method三种handler,图中省略了Method类型)执行动作before和after时刻操作数据的能力。

实现对用户代码无任何”侵入”的前提下完成调用链的生成,过程大致分为如下几个过程:

1)在JEEServiceRunGlobalFilterHandler的doRepuest中包装解析请求;

2)xxAdapter中的before对数据进行适配;

3)xxHandler处理对应范围内(Service、Client和Method)内请求数据;

4)xxAdapter中的after对数据进行整理或记录;

5)在JEEServiceRunGlobalFilterHandler的doResponse中返回处理过后请求。

六、总结

本文主要目的是让读者对UAVStack的调用链有一个整体的认识,初步了解一条调用链绘制的大致生命周期,具体的实现将在以后的分享中详细介绍。

作者:李崇

调用链系列(1):解读UAVStack中的贪吃蛇的更多相关文章

  1. 调用链系列二、Zipkin 和 Brave 实现(springmvc、RestTemplate)服务调用跟踪

    Brave介绍 1.Brave简介 Brave 是用来装备 Java 程序的类库,提供了面向标准Servlet.Spring MVC.Http Client.JAX RS.Jersey.Resteas ...

  2. 调用链系列三、基于zipkin调用链封装starter实现springmvc、dubbo、restTemplate等实现全链路跟踪

    一.实现思路 1.过滤器实现思路 所有调用链数据都通过过滤器实现埋点并收集.同一条链共享一个traceId.每个节点有唯一的spanId. 2.共享传递方式 1.rpc调用:通过隐式传参.dubbo有 ...

  3. 调用链系列一、Zipkin架构介绍、Springboot集承(springmvc,HttpClient)调用链跟踪、Zipkin UI详解

    1.Zipkin是什么 Zipkin分布式跟踪系统:它可以帮助收集时间数据,解决在microservice架构下的延迟问题:它管理这些数据的收集和查找:Zipkin的设计是基于谷歌的Google Da ...

  4. TypeScript完全解读(26课时)_9.TypeScript完全解读-TS中的类

    9.TypeScript完全解读-TS中的类 创建class.ts文件,并在index.ts内引用 创建一个类,这个类在创建好后有好几个地方都标红了 这是tslint的一些验证规则 一保存就会自动修复 ...

  5. 解读C#中的正则表达式

    本文摘自LTP.NET知识库. regexp规则类包含在System.Text.RegularExpressions.dll文件中,在对应用软件进行编译时你必须引用这个文件: System.Text. ...

  6. 解读typescript中 super关键字的用法

    解读typescript中 super关键字的用法 传统的js,使用prototype实现父.子类继承.如果父.子类有同名的方法,子类去调用父类的同名方法需要用 “父类.prototype.metho ...

  7. 如何解决xx列不在表中

    在连接数据库的程序中常会出现xx列不在表中的问题?那么应该怎么解决呢? 产生此问题的原因有三种: 1.数据表没这个字段2.sql查询没将这个字段查出来3.字段名写错了 还有重要的是一定要检查你的数据库 ...

  8. 描述了say_hello函数的具体内容,调用zend_printf系统函数在php中打印字符串

    下载一个php的源代码包,这里使用的是php 4.0.5版,解压后会看到php的根目录下会有README.EXT_SKEL这样一个文件,打开详细阅读了一下,发现了一个非常好用的工具,这个工具可以帮你构 ...

  9. AutoCAD.NET 不使用P/Invoke方式调用acad.exe或accore.dll中的接口(如acedCommand、acedPostCommand等)

    使用C#进行AutoCAD二次开发,有时候由于C#接口不够完善,或者低版本AutoCAD中的接口缺少,有些工作不能直接通过C#接口来实现,所以需要通过P/Invoke的方式调用AutoCAD的其他DL ...

随机推荐

  1. django执行mysql恢复的时候出现“The request's session was deleted before the request completed. The user may have logged out in a concurrent request, for example.”

    版本: django:2.1.7 python:3.7 mysql:5.7.25 今天在用django做mysql备份和恢复的时候,备份没问题,恢复时出现如下错误提示: The request's s ...

  2. Linux命令学习-history命令

    Linux中,history命令的作用是显示历史记录和执行过的命令. 查看历史所有命令执行记录 history 查看最近的13条历史执行命令 history 13 执行历史记录中,序号为123的命令 ...

  3. C++学习书籍推荐《C++编程思想第二版第二卷》下载

    百度云及其他网盘下载地址:点我 编辑推荐 “经典原版书库”是响应教育部提出的使用原版国外教材的号召,为国内高校的计算机教学度身订造的.<C++编程思想>(英文版第2版)是书库中的一本,在广 ...

  4. 【小家Spring】Spring IoC是如何使用BeanWrapper和Java内省结合起来给Bean属性赋值的

    #### 每篇一句 > 具备了技术深度,遇到问题可以快速定位并从根本上解决.有了技术深度之后,学习其它技术可以更快,再深入其它技术也就不会害怕 #### 相关阅读 [[小家Spring]聊聊Sp ...

  5. 2017-10271weblogic漏洞exp测试及补丁测试

    靶机:weblogic12.1.3.0 战斗机:kali 导弹:burpsuite 1.首先开启kali某端口监听 2.向靶机发送exp 3.查看kali监听 打码保平安~~ 4.打上补丁 5.验证补 ...

  6. 快速掌握mongoDB(四)—— C#驱动MongoDB用法演示

    前边我们已经使用mongo shell进行增删查改和聚合操作,这一篇简单介绍如何使用C#驱动MongoDB.C#驱动MongoDB的本质是将C#的操作代码转换为mongo shell,驱动的API也比 ...

  7. Git命令行之快速入门

    从头开始创建一个版本库,添加一些内容,然后管理一些修订版本. 有两种建立 Git版本库 的基础技术.第一:从头开始创建,用现有的内容填充它.第二:可以克隆一个已有的版本库.这里选择从一个空的版本库开始 ...

  8. Error:Failed to resolve: com.android.support:support-annotations:26.0.2

    异常信息记录: Error:Failed to resolve: com.android.support:support-annotations:26.0.2 <a href="ins ...

  9. Flume框架的学习使用

    Flume框架的学习使用 Flume简介 Flume提供一个分布式的,可靠的,对大数据量的日志进行高效收集.聚集.移动的服务. Flume基于流失架构,容错性强,也很灵活简单 Flume,kafka用 ...

  10. 博弈论基础之sg函数与nim

    在算法竞赛中,博弈论题目往往是以icg.通俗的说就是两人交替操作,每步都各自合法,合法性与选手无关,只与游戏有关.往往我们需要求解在某一个游戏或几个游戏中的某个状态下,先手或后手谁会胜利的问题.就比如 ...