浅析淘宝分布式调用跟踪系统

分布式系统为什么需要分布式跟踪?

电商平台由数以百计的分布式服务构成,每一个请求路由过来后,会经过多个业务系统并留下足迹,并产生对各种Cache或DB的访问,但是这些分散的数据对于问题排查,或是流程优化都帮助有限。

对于这么一个跨进程/跨线程的场景,汇总收集并分析海量日志就显得尤为重要。要能做到追踪每个请求的完整调用链路,收集调用链路上每个服务的性能数据,计算性能数据和比对性能指标(SLA),甚至在更远的未来能够再反馈到服务治理中,那么这就是分布式跟踪的目标了。

在业界,twitter的zipkin和淘宝的鹰眼就是类似的系统,它们都起源于Google Dapper 论文,就像历史上Hadoop发源于Google Map/Reduce 论文,HBase源自Google BigTable 论文一样。

这样的系统通常有几个设计目标:

(1)低侵入性——作为非业务组件,应当尽可能少侵入或者无侵入其他业务系统,对于使用方透明,减少开发人员的负担。

(2)灵活的应用策略——可以(最好随时)决定所收集数据的范围和粒度。

(3)时效性——从数据的收集和产生,到数据计算和处理,再到最终展现,都要求尽可能快。

(4)决策支持——这些数据是否能在决策支持层面发挥作用,特别是从DevOps的角度。

(5)可视化才是王道。

先来一个直观感受

数据流转过程:

浅析淘宝分布式调用跟踪系统_第1张图片

图1-1淘宝鹰眼的数据收集和存储

鹰眼的调用链绘制界面:

浅析淘宝分布式调用跟踪系统_第2张图片

图1-2 淘宝鹰眼的调用链

鼠标移动到调用链的每一层点击,可以看到执行时长、宿主机IP、数据库操作、传入参数甚至错误堆栈等等具体信息。

淘宝如何实现的

同一次请求的所有相关调用的情况,在淘宝EagleEye里称作调用链。同一个时刻某一台服务器并行发起的网络调用有很多,怎么识别这个调用是属于哪个调用链的呢?可以在各个发起网络调用的中间件上下手。

在前端请求到达服务器时,应用容器在执行实际业务处理之前,会先执行EagleEye的埋点逻辑(类似Filter的机制),埋点逻辑为这个前端请求分配一个全局唯一的调用链ID。这个ID在EagleEye里面被称为TraceId,埋点逻辑把TraceId放在一个调用上下文对象里面,而调用上下文对象会存储在ThreadLocal里面。调用上下文里还有一个ID非常重要,在EagleEye里面被称作RpcId。RpcId用于区分同一个调用链下的多个网络调用的发生顺序和嵌套层次关系。对于前端收到请求,生成的RpcId固定都是0。

当这个前端执行业务处理需要发起RPC调用时,淘宝的RPC调用客户端HSF会首先从当前线程ThreadLocal上面获取之前EagleEye设置的调用上下文。然后,把RpcId递增一个序号。在EagleEye里使用多级序号来表示 RpcId,比如前端刚接到请求之后的RpcId 是0,那么它第一次调用 RPC 服务A时,会把RpcId改成0.1。之后,调用上下文会作为附件随这次请求一起发送到远程的HSF服务器。

HSF服务端收到这个请求之后,会从请求附件里取出调用上下文,并放到当前线程ThreadLocal上面。如果服务A在处理时,需要调用另一个服务,这个时候它会重复之前提到的操作,唯一的差别就是RpcId会先改成 0.1.1再传过去。服务A的逻辑全部处理完毕之后,HSF 在返回响应对象之前,会把这次调用情况以及TraceId、RpcId都打印到它的访问日志之中,同时,会从ThreadLocal清理掉调用上下文。

如图2-1展示了一个浏览器请求可能触发的系统间调用。

浅析淘宝分布式调用跟踪系统_第3张图片

图2-1一个浏览器请求可能触发的系统间调用

图2-1描述了EagleEye在一个非常简单的分布式调用场景里做的事情,就是为每次调用分配TraceId、RpcId,放在ThreadLocal的调用上下文上面,调用结束的时候,把TraceId、RpcId打印到访问日志。

类似的其他网络调用中间件的调用过程也都比较类似,这里不再赘述了。访问日志里面,一般会记录调用时间、远端IP地址、结果状态码、调用 耗时之类,也会记录与这次调用类型相关的一些信息,如URL、服务名、消息topic等。

很多调用场景会比上面说的完全同步的调用更为复杂,比如会遇到异步、单向、广播、并发、批处理等等,这时候需要妥善处理好ThreadLocal上的调用上下文,避免调用上下文混乱和无法正确释放。另外,采用多级序号的RpcId设计方案会比单级序号递增更容易准确还原当时的调用情况。

最后,EagleEye分析系统把调用链相关的所有访问日志都收集上来,按TraceId汇总在一起之后,就可以准确还原调用当时的情况了。

浅析淘宝分布式调用跟踪系统_第4张图片

图2-2一个典型的调用链

如图2-2所示,就是采集自淘宝线上环境的某一条实际调用链。调用链通过树形展现了调用情况。调用链可以清晰地看到当前请求的调用情况,帮助问题定位。如上图,mtop应用发生错误时,在调用链上可以直接看出这是因为第四层的一个(tair@1)请求导致网络超时,使最上层页面出现超时问题。这种调用链,可以在EagleEye系统监测到包含异常的访问日志后,把当前的错误与整个调用链关联起来。问题排查人员在发现入口错误量上涨或耗时上升时,通过EagleEye查找出这种包含错误的调用链采样,提高故障定位速度。

调用链数据在容量规划和稳定性方面的分析

如果对同一个前端入口的多条调用链做汇总统计,也就是说,把这个入口URL下面的所有调用按照调用链的树形结构全部叠加在一起,就可以得到一个新的树结构(如图2-3所示)。这就是入口下面的所有依赖的调用路径情况。

浅析淘宝分布式调用跟踪系统_第5张图片

图2-3 对某个入口的调用链做统计之后得到的依赖分析

这种分析能力对于复杂的分布式环境的调用关系梳理尤为重要。传统的调用统计日志是按固定时间窗口预先做了统计的日志,上面缺少了链路细节导致没办法对超过两层以上的调用情况进行分析。

例如,后端数据库就无法评估数据库访问是来源于最上层的哪些入口;每个前端系统也无法清楚确定当前入口由于双十一活动流量翻倍,会对后端哪些系统造成多大的压力,需要分别准备多少机器。有了EagleEye的数据,这些问题就迎刃而解了。

 

http://express.ruanko.com/ruanko-express_79/tech-overnight3.html

你可能感兴趣的:(浅析淘宝分布式调用跟踪系统)