运维那些事之调用链
挑战:云化产品通常采用服务化框架,由一系列服务组成,且服务是可以独立运行的进程,不同服务可使用不同开发语言,可能分布部署在几千台服务器上,甚至可能横跨多个不同的数据中心,服务间使用轻量的通信机制;服务之间存在复杂的调用关系,对运维人员理解系统的行为或分析系统性能带来巨大挑战 如:
(1)业务调用出现问题,如何快速找出哪个服务发生失败?
(2)某个业务调用耗时较长,如何快速找到性能瓶颈点?
(3)如何快速获取某次调用的业务日志进行分析定位?
调用链
任何技术发展重来不都是孤立的,为解决云化技术带来的挑战,第一个分布式跟踪系统(调用链)Dapper最早由Google设计而出,随后被业界各大公司推崇发展至今,产生了一系列实现实体,分布式跟踪业界标准也应运而生。
调用链定义
调用链定义:在系统完成一次业务调用的过程中,把服务之间的调用信息(时间、接口、层次、结果)打点到日志中,然后将所有的打点数据连接为一个树状链条就产生了一个调用链。跟踪系统把过程中产生的日志信息进行分析处理,将业务端到端的执行完整的调用过程进行还原,根据不同维度进行统计分析;从而标识出有异常的服务调用,能够快速分析定界到出异常的服务;同时可根据数据统计分析系统性能瓶颈。
Dapper, a Large-Scale Distributed Systems Tracing Infrastructure 描述了其中的原理和一般性的机制。模型中包含的术语也很多,理解最主要的两个即可:
- Trace:一次完整的分布式调用跟踪链路。
- Span:跨服务的一次调用; 多个 Span 组合成一次 Trace 追踪记录。
下面通过一次用户服务请求来完成调用链过程模拟:
左图为一个和5台服务器相关的一个服务,包括:前端(A),两个中间层(B和C),以及两个后端(D和E)。当一个用户(这个用例的发起人)发起一个请求时,首先到达前端,然后发送两个RPC到服务器B和C。B会马上做出反应,但是C需要和后端的D和E交互之后再返还给A,由A来响应最初的请求。
右表示对应 Span 的管理关系。每个节点是一个 Span,表示一个调用。至少包含 Span 的名、父 SpanId 和 SpanId。节点间的连线下表示 Span 和父 Span 的关系。所有的 Span 属于一个跟踪,共用一个 TraceId。从图上可以看到对前端 A 的调用 Span 的两个子 Span 分别是对 B 和 C 调用的 Span,D 和 E 两个后端服务调用的 Span 则都是 C 的子 Span。
跟踪系统根据用户请求每次生成的全局唯一的ID(TraceId),TraceId 在span间传递,将不同服务的“孤立的”日志串在一起,重组还原出更多有价值的信息。如今调用链系统有很多实现,用的比较多的如 zipkin ,还有已经加入 CNCF 基金会并且的用的越来越多的 Jaeger ,后面会有专题分析。
调用链模型格式
为了能将一系列埋点串接成一个完整的调用链,并区分不同请求的调用链日志信息,同时信息中需要包含请求状态与时长,对于不同业务应用可能需要有特殊的信息记录到日志中;所以调用链日志信息(Span)应包含如下内容:
一次业务请求调用链模型:
调用链日志示例:
下面为原始Json结构跟踪信息
分布式跟踪系统
一个完整的调用链跟踪系统,包括调用链埋点,调用链数据收集,调用链数据存储和处理,调用链数据检索(除了提供检索的 APIServer,一般还要包含一个酷炫的调用链前端)等若干重要组件。如图是 Jaeger 的一个完整实现。
Jaeger-client是对OpenTracing API的实现,生成trace id和span信息同时接收和传递span信息到其他服务,采样功能也是在这里完成,同时将span异步传递个 jaeger-agent;
jaeger-agent被从业务应用中抽出,作为守护进程部署在宿主机或容器中,专门负责向collector异步上报调用链跟踪数据,这样做将业务应用与collector解耦了,同时也减少了业务应用的第三方依赖;
jaeger-collector系统汇聚多发jaeger-agent反馈的跟踪日志信息持久化到数据层,jaeger支持ES和Canssandra两种后端DB;
jaeger-query子系统根据前端关键字通过不同维度关联数据提供jaeger-ui做展现。
后续会专门接收下跟踪系统的业界标准和现在。
系统设计目标
同时业务系统的故障或性能是具有不确定性(发生时间和位置),系统异常或是那些重要的系统行为有可能出现过一次,就很难甚至不太可能重现;这就需要跟踪系统持续的监控收集信息和覆盖服务尽可能广。这就对跟踪系统提出了设计目标:
1.低消耗:跟踪系统对在线服务的影响应该做到足够小。对一些高度优化过的服务,即使一点点损耗也会很容易察觉到,而且有可能迫使在线服务的部署团队不得不将跟踪系统关停。一般方法:增加采样率设置,甚至使用自适应的采样率使跟踪系统变得可伸缩,并降低性能损耗
2.应用级的透明:对于应用的程序员来说,是不需要知道有跟踪系统这回事的。如果一个跟踪系统想生效,就必须需要依赖应用的开发者主动配合,那么这个跟踪系统也太脆弱了,往往由于跟踪系统在应用中植入代码的bug或疏忽导致应用出问题,这样对于已有的系统很难引入跟踪技术。面对当前这样的快节奏的交付模式来说,尤其重要。
一般方法:把核心跟踪代码做的很轻巧,然后把它植入到那些无所不在的公共组件种,比如线程调用、控制流以及RPC库
3.延展性:至少在未来几年的服务和集群的规模,监控系统都应该能完全把控住。
4.跟踪数据产生之后,进行分析的速度要快,理想情况是数据存入跟踪仓库后一分钟内就能统计出来。
写在最后:
一个技术的兴起必然会引起各大公司的追捧和同时推出自己的解决方案,业界调用链系统也迅速发展如:zipkin(Twitter)、Jeager(Uber)、Skywalking(社区)、Pinpoint(社区)、EagleEye(Aliyun)等等,调用链的标准也应运而生OpenTracing、OpenCensus、OpenTelemetry..