分布式服务拆分以后,系统的结构必然会变得更为复杂,单个业务功能需要调用的服务链条也会越来越长,那么在实际工作中如何快速定位线上故障的根源在哪里,这就需要引入一项额外的技术了,分布式调用跟踪技术。
为什么需要分布式调用跟踪?
这个问题的答案,想必每个人的心中都有自己的理解,总的来说就是分布式技术以及面向服务的架构技术导致我们大型系统的服务数量非常巨大,不同的微服务模块可能是有不同的技术团队在维护,一个请求可能会涉及十几个服务的协同处理,牵扯到多个技术团队的业务系统。
如果服务请求失败,对于应用层的用户来讲,并不能一眼看出爆出的错误或者提示背后的问题到底出在哪里,需要定位具体是哪个服务引起的问题,或者说哪个环节导致的响应异常,如果没有调用链路追踪,那么我们通常的做法是从调用链的入口,逐层排查日志,然后根据日志去找对应的出错的服务维护团队的负责人,然后那个服务再查看自己的日志,来确定是否是自己的问题,如果不是,那么下层的服务哪里出了问题,再跟下层的服务开发人员进行反馈,进一步查看问题的根源。这样的处理方式是非常低效,耗时耗力。
链路追踪的业务场景
分布式调用跟踪技术就是解决上面场景的问题,即通过调用链的方式,把一次请求调用过程完整的串联起来,这样就实现了对请求调用路径的监控和跟踪。
分布式调用链其实就是将一次分布式请求还原成调用链路,显式的在后端查看一次分布式请求的调用情况,比如各个节点上的耗时,请求具体打到了那个节点,每个服务节点的请求状态等。
一般而言,以下场景可以应用分布式链路追踪。
1需要快速定位故障的情况,
2需要各个调用环节的性能分析相关数据
3各个调用环节的可用性和持久层依赖等,通过分析各个环节的平均时延,QPS等信息,可以分析出系统的薄弱环节,对一些模块能够做针对性的调整,能够使整个系统更加的健壮等。
4数据分析,调用链是一条完整的业务日志,能够用来对用户行为路径进行分析和汇总。
分布式调用链路追踪实现原理
技术实现总有理论支撑,主要是参考Google的Dapper论文,分布式调用跟踪是一种全链路日志,主要的设计基于Span日志格式,下面简单介绍下这个日志的结构。
Dapper是用Span来表示一个服务调用开始和技术的时间,也就是时间区间,并记录了Span的名称以及每个Span的ID和父级ID,如果一个Span没有父Id则被称之为Root Span。
一个请求到达应用后所调用的所有服务,以及所有服务组成的调用链就像一个树形结构,追踪这个调用链路得到的树结构称之为Trace,所有的Span都挂在一个特定的Trace上,共用一个TraceID。
在一次Trace中每个服务的第一次调用,就是一个Span,每一个Span都有一个ID作为唯一标识,同样,每一次Trace都会生成一个TraceId在Span中作为追踪标识,另外再通过一个parentSpanId,表明本次调用的发起者。
当Span有个上面三个标识后,就可以很清晰地将多个Span进行梳理串联,最终归纳出一条完整的跟踪链路。
确定了日志格式以后,接下来就是对日志的采集和解析,日志的采集和存储有许多开源的工具可以选择,一般来说,会使用离线+实时的方式去存储日志,主要是分布式系统日志采集的方式,典型的解决方案如Flume结合Kafka等MQ,日志存储到HBASE等存储系统中,然后就是根据场景或者业务需求,进行相关的展示和分析了。
常用的工具选型
Google的Dapper Twitter的ZIPkin 淘宝的鹰眼EagleEye等
我们公司用的是pinpoint。