• 调用链监控工具之CAT上


    业界在实践链路调用工具时,思路基本都来源于Google 2010年发表的一篇Dapper的论文,论文发表后Twitter就开发了一款Zipkin的链路调用工具,后续陆续又有多款链路调用工具开源出来。尽管这些分布式追踪系统有着相似的API语法,但各种语言的开发人员依然很难将他们各自的系统(使用不同的语言和技术)和特定的分布式追踪系统进行整合。故后来又出现了一个组织Open Tracing,OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加或更换追踪系统的实现。OpenTracing提供了用于运营支撑系统的和针对特定平台的辅助程序库。程序库的具体信息请参考详细的规范。在学习链路调用工具前,需要先理解一些链路追踪的术语定义:

     Trace:一次分布式调用的链路追踪
    Span:一个方法(局部或远程)调用踪迹
    Annotation:附着在Span上的日志信息
    Sampling:采样率

    如下图所示,每一次链路调用会生成一个tid(traceId),不同的服务间,会生成新的sid(spanId),上一个服务调用的sid是下一个服务的pid(parentId).

    在众多链路追踪工具中,大部分是来源于Google Dapper的思路,例如Zipkin,Skywaking等,也有些工具并不是采用Google Dapper的思路,例如CAT,CAT实际是借鉴了eBay CAL的思路。CAT 是基于Java开发的实时应用监控平台,为美团点评提供了全面的实时监控告警服务。下面是对其中使用比较广泛的链路追踪工具的简单比较,红色字体是该工具的优势点。

    此篇博客重点介绍CAT的使用,上面介绍了链路追踪的一些基本概念,接下来将重点介绍如何使用CAT完成链路追踪。要使用CAT首先需要部署CAT服务,部署CAT服务可以通过拉取源代码构建war包,也可以直接通过官网下载war包。CAT服务端部署步骤官网有详细的步骤,需要注意两个点,第一:官网提醒需要使用mysql5.6或者5.7,亲测过如果Mysql不使用5.x版本,CAT服务无法正常启动起来,本人在部署CAT服务时,使用的JDK是1.8,Mysql5.7,Tomcat8.x。另外,需要注意一个点,有些操作系统对根目录只有只读权限,在部署CAT服务端时,可以通过环境变量的方式修改CAT_HOME地址。在启动tomcat服务前,先执行如下脚本

    1. export CAT_HOME=/data/appdatas/cat/
    2. CATALINA_OPTS="$CATALINA_OPTS -server -DCAT_HOME=$CAT_HOME

    自定义的CAT_HOME目录如下所示,该目录下存放client.xml,datasource.xml,server.xml文件。

    client.xml文件中server ip填入本机IP地址,因为CAT服务部署是单机本地部署,非集群部署,故填写本机一个IP地址即可。

    DataSource.xml中修改成本机安装的Mysql的用户名和密码即可,Server.xml文件内容如下所示:

    通过tomcat下启动服务时,可以观察自定义CAT_HOME目录是否生效,这个会影响CAT服务是否能成功启动。如下所示,可以看到自定义目录生效。

    启动过程日志存放在tomcat目录下logs目录。访问http://localhost:8080,如果出现tomcat的猫说明tomcat自身已经启动成功。

    tomcat启动成功后,访问CAT服务(http://localhost:8080/cat),如果CAT服务启动出现问题,可查看CAT_HOME/data/appdatas/cat 目录,会有相应的启动日志,可通过日志排查原因。如果在Dashboard中显示服务正常文字,说明CAT服务部署成功,如下图所示:

    进入CAT服务后,点击Config菜单,可以进行相关配置,如果是本机部署,客户端路由配置中将IP地址相关的地方修改成本机的IP地址,并提交。

    官网给出的服务端部署文档写的非常详细,对于本机单机部署而言,还是比较简单的,总结步骤如下所示:

    • 安装的软件清单:JDK7或者JDK8,Mysql5.6或者Mysql5.7,Tomcat8.x
    • 拉取源码生成war包或者从官网直接下载war包,下载3.1.0版本及以上的war包,war包放到tomcat的webapps目录下
    • 创建/data/appdatas/cat目录,并修改datasource.xml,client.xml,server.xml,将文件放入目录
    • 创建cat database,并初始化数据库数据,初始化脚本在源码中:script/CatApplication.sql
    • 启动tomcat,登陆cat服务,查看cat服务是否成功启动
    • 提交新的客户端路由信息

    上面介绍了服务端的部署,接下来看看客户端如何接入。客户端接入非常简单,首先是在客户端的pom.xml文件中添加cat-client的依赖。

    1. <dependency>
    2. <groupId>com.dianping.cat</groupId>
    3. <artifactId>cat-client</artifactId>
    4. <version>${cat.version}</version>
    5. </dependency>

    接着在源代码的resources/META-INF/cat目录下放入client.xml文件,该文件中server ip修改成部署CAT服务的机器的IP,对于本机部署而言就是本机IP。resources/META-INF目录下放入app.properties文件,文件内容“app.name=应用名称”,client.xml文件内容如下所示:

    另外,需要注意一点,如果是自定义CAT_HOME目录,只在服务端部署时生效,客户端的日志目录(/data/applogs/cat)是写死的,除非修改客户端源代码,再生成新的jar包,引入到项目中。所以如果对操作系统根目录只有只读权限,那么可以通过添加软链接的方式。否则,可能影响生成链路信息。以下是Mac创建软链接的过程

    1.sudo vi /etc/synthetic.conf
    2.进行文件映射 or 软连接,如:中间用Tab键隔开
    data    Users/taoli/data/applogs/cat
    3.重启电脑
    4.查看系统根目录就能看到data目录了

    客户端集成的Demo地址,该Demo编写了四个服务,模拟服务间调用。依次启动服务,并访问最外层的UI服务,连续访问几次后,在CAT服务上查看生成的链路调用信息,服务调用关系如下: 

    在CAT服务上查看Transaction信息,可以查看服务调用的响应时间,QPS等信息,点击Log View,可以看服务间的详细调用关系以及不同阶段的耗时信息。

    Log View里面的链路信息如下所示,可以查看到服务之间调用关系以及每一步调用的耗时。

    Problem报表可以查看发生异常的信息,例如错误的接口URL,错误量等信息。

    点击Lg(SampleLinks)还可以查看到详细的报错信息,如下图所示:

    更多关于报表的使用可以查看官网信息,除了监控信息查看,CAT还可以配置告警。CAT的一大优势也是支持丰富的报表信息。上面演示了CAT进行链路监控的效果,接下来分析Demo代码,从代码层面理解Java客户端如何与CAT集成。客户端集成都是以new transaction的方式完成,如下所示

     Demo代码中先分析"acme-financial-ui"这个服务,这个服务中编写了CatServletFilter,这个Filter中把请求中的头信息读取出来,存放到catContext中,便于后面传递到下一个服务,这里编写Filter是假设还有其他服务会调用UI服务。

    除此之外还编写了CatRestInterceptor,这个Interceptor的作用是从catContext中读取存放的信息,放到请求的header中,传递到下一个服务。因为acme-financial-ui这个服务调用Back-office这个服务是通过RestTemplate完成的,因为添加了CatRestInterceptor,那么所有的RestTemplate调用都会有添加的header信息,这样服务间的链路标识信息就传递下去了。

     下面是创建配置类,让CatServletFilter生效的代码。

    下面是把CatRestInterceptor设置到RestTemplate对象上的代码。

    back-office服务的代码和UI服务的代码相同,Account服务和Customer服务因为没有再调用其他服务,即没有用restTemplate调用其他服务,故这两个服务中只添加CatServletFilter即可,无需添加CatRestInterceptor即可,如下图所示。总结而言:埋点需要完成的核心实际就是把服务间的调用信息传递下去,传递方式是:通过servletFilter读取发送过来的请求的header信息,存入CatContext,调用下一个服务时,再从CatContext中读取信息存入request的header中传递下去。

    为了更清晰的理解传递的链路信息,这里把Filter拦截存储的信息打印出来,整理如下。例如通过postman调用接口“http://localhost:8081/start”,也就是从UI这个服务发起服务调用。可以看到,因为UI服务没有被其他任何服务调用,所以Filter拦截到的信息都是null。另外,服务是由UI这个服务发起的,所以catContextRoot都是acme-financial-ui-c0a83209-461821-2015,对于back-office服务而言,Parent信息也是acme-financial-ui-c0a83209-461821-2015,并生成了child信息,传递给后面的Account和Customer服务,是Account和Customer服务的Parent信息。

    再回到前面的TraceId和SpanId的概念,这里acme-financial-ui-c0a83209-461821-2015就是traceId,各个服务新生成的Id就是spanId,同时上一个服务的childId是下一个服务的parentId。再发起一个新的接口调用,会生成新的TraceId信息。

    以上就是对CAT链路工具的学习和理解。

  • 相关阅读:
    cudnn-windows-x86_64-8.6.0.163_cuda11-archive 下载
    【BOOST C++ 11 时钟数据】(1)计时码表(11-13)
    飞腾2000+按通道分配内存
    [鹏程杯2023]复现
    Spring之BeanFactory与ApplicationContext区别、实例化Bean的三种⽅式、延迟加载(lazy-Init )
    jupyter使用tensorflow遇到的问题
    Javac多模块化编译
    【Linux】命名管道
    Springboot学习笔记——1
    【MySQL】数据类型
  • 原文地址:https://blog.csdn.net/qiaotl/article/details/126734397