分布式追踪系统
- 使用 Zipkin 和 Brave 实现分布式系统追踪(基础篇) - 推酷
- OpenZipkin · A distributed tracing system
- Twitter zipkin 分布式跟踪系统的设计与实现 - 马宏的世界 - 博客频道 - CSDN.NET
- openzipkin/brave: Java distributed tracing implementation compatible with Zipkin backend services.
- openzipkin/zipkin: Zipkin is a distributed tracing system
- zipkin - liaokailin的专栏 - 博客频道 - CSDN.NET
- #研发解决方案介绍#Tracing(鹰眼) - 旁观者 - 博客园




淘宝如何实现的:
在前端请求到达服务器时,应用容器在执行实际业务处理以前,会先执行 EagleEye 的埋点逻辑(相似 Filter 的机制),埋点逻辑为这个前端请求分配一个全局惟一的调用链ID。这个ID在 EagleEye 里面被称为 TraceId,埋点逻辑把 TraceId 放在一个调用上下文对象里面,而调用上下文对象会存储在 ThreadLocal 里面。调用上下文里还有一个ID很是重要,在 EagleEye 里面被称做 RpcId。RpcId 用于区分同一个调用链下的多个网络调用的发生顺序和嵌套层次关系。对于前端收到请求,生成的 RpcId 固定都是0。html
当这个前端执行业务处理须要发起 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 清理掉调用上下文。如图6-1展现了一个浏览器请求可能触发的系统间调用。mysql

图6-1-一个浏览器请求可能触发的系统间调用git
图6-1描述了 EagleEye 在一个很是简单的分布式调用场景里作的事情,就是为每次调用分配 TraceId、RpcId,放在 ThreadLocal 的调用上下文上面,调用结束的时候,把 TraceId、RpcId 打印到访问日志。相似的其余网络调用中间件的调用过程也都比较相似,这里再也不赘述了。访问日志里面,通常会记录调用时间、远端IP地址、结果状态码、调用耗时之类,也会记录与此次调用类型相关的一些信息,如URL、服 务名、消息topic等。不少调用场景会比上面说的彻底同步的调用更为复杂,好比会遇到异步、单向、广播、并发、批处理等等,这时候须要妥善处理好 ThreadLocal 上的调用上下文,避免调用上下文混乱和没法正确释放。另外,采用多级序号的 RpcId 设计方案会比单级序号递增更容易准确还原当时的调用状况。github
最后,EagleEye 分析系统把调用链相关的全部访问日志都收集上来,按 TraceId 汇总在一块儿以后,就能够准确还原调用当时的状况了。redis
图6-2-一个典型的调用链sql
如图6-2所示,就是采集自淘宝线上环境的某一条实际调用链。调用链经过树形展示了调用状况。调用链能够清晰地看到当前请求的调用状况,帮助问题定 位。如上图,mtop应用发生错误时,在调用链上能够直接看出这是由于第四层的一个(tair@1)请求致使网络超时,使最上层页面出现超时问题。这种调用链,能够在 EagleEye 系统监测到包含异常的访问日志后,把当前的错误与整个调用链关联起来。问题排查人员在发现入口错误量上涨或耗时上升时,经过 EagleEye 查找出这种包含错误的调用链采样,提升故障定位速度。mongodb
调用链数据在容量规划和稳定性方面的分析数据库
若是对同一个前端入口的多条调用链作汇总统计,也就是说,把这个入口URL下面的全部调用按照调用链的树形结构所有叠加在一块儿,就能够获得一个新的树结构(如图6-3所示)。这就是入口下面的全部依赖的调用路径状况。后端

图6-3-对某个入口的调用链作统计以后获得的依赖分析
这种分析能力对于复杂的分布式环境的调用关系梳理尤其重要。传统的调用统计日志是按固定时间窗口预先作了统计的日志,上面缺乏了链路细节致使没办法对超过两层以上的调用状况进行分析。例如,后端数据库就没法评估数据库访问是来源于最上层的哪些入口;每一个前端系统也没法清楚肯定当前入口因为双十一活动流量翻倍,会对后端哪些系统形成多大的压力,须要分别准备多少机器。有了 EagleEye 的数据,这些问题就迎刃而解了。


- 埋点
- 实现线程内 trace 上下文传递,即服务器内部的方法互调时不须要强制在方法形参中加 Message 参数;
- 实现 trace 埋点逻辑自动织入功能,即业务开发人员不须要在方法中打印 trace 日志,只须要给该方法加注解标识 ;
- 原理:
- 利用 Javaagent 机制,执行 main 方法以前,会先执行 premain 方法,在该方法中将字节码转换器载入 instrumentation,然后 jvm 在加载 class 文件以前都会先执行字节码转换器。
- 字节码转换器中的逻辑为,识别出注解 trace 的类及方法,并修改该方法字节码,织入埋点逻辑。进入方法时会初始 trace 上下文信息,并存储在线程的 threadLocals 中,退出方法会打印 trace 日志并清空该方法的上下文。
- 数据聚合
- 应用层 trace 日志经过 flume agents 实时发送至 flume collector;
- 数据存储
- 服务端分别经过 hdfs-sink 和 hbase-sink,实时录入至 hbase、hdfs;
- hdfs 有 tmp 临时文件存放实时聚合过来的数据,每5分钟生成一个 done 文件;
- 数据分析和统计
- load 程序每 4 分钟检查 done 文件并存放至 hive 表 hkymessage 指定分区;
- 分析程序每5分钟执行一次, 将生成统计数据入库, 结果集数据以下:
数据格式:{5个分层的5个响应时段请求个数合集} {5个分层5-10s和大于10s散点数据合集} 当前5分钟最后一次请求rootid 统计时间
- 数据展现
- 基于 Python 的 Django