在应用A调用应用B、C的HSF服务,或者发送Notify消息时,TraceId被包含在EagleEye上下文中,随网络请求到达应用B、C、D、E之中,并放置在线程ThreadLocal内,因此后续调用到的这些系统都会有EagleEye这次请求的上下文。这些系统再发起网络请求时,也类似的携带了上下文信息的。
RpcId
为了区别同一个调用链下多个网络调用的顺序和嵌套层次,EagleEye还需要传输和记录RpcId。
RpcId用0.X1.X2.X3.....Xi来表示,Xi都是非负整数,根节点的RpcId固定从0开始,第一层网络调用的RpcId是0.X1,第二层的则为0.X1.X2,依次类推。例如,从根节点发出的调用的RpcId是0.1、0.2、0.3,RpcId是0.1的节点发出的RpcId则为0.1.1、0.1.2、0.1.3。如下图所示。
通过RpcId,可以准确的还原出调用链上每次调用的层次关系和兄弟调用之间的先后顺序。
例如上图应用 G 的两次调用0.2.1.1和0.1.2.1,可以看出对 DB 的访问0.2.1.1源于 C 到 G 的调用0.2.1,对 Tair 的访问0.1.2.1源于B 到 G 的调用0.1.2。
很多调用场景会比上面说的完全同步的调用更为复杂,比如会遇到异步、单向、广播、并发、批处理等等,这时候需要妥善处理好ThreadLocal上的调用上下文,避免调用上下文混乱和无法正确释放。另外,采用多级序号的RpcId设计方案会比单级序号递增更容易准确还原当时的调用情况。
中间件埋点
EagleEye 需要在网络调用中间件中埋点,实现TraceId/RpcId等上下文信息的生成、传输,以及调用日志的记录。这些信息记录在ThreadLocal,对应用是透明的,应用也不需要修改方法API来回传递EagleEye的上下文对象。论文网
目前EagleEye在淘宝最常见的中间件HSF、Notify、TDDL、Tair、TFS、tbsession、tengine、metaQ、search都已经加上了EagleEye的埋点,基本涵盖了服务调用、消息通信、数据库存取、缓存数据存取、前端接入等各种场景。越来越多的网络调用中间件会逐步接入到 EagleEye 体系当中。
透明数据传输
EagleEye 本身具备透明传输 TraceId、RpcId 的能力,这个能力通用可以用来传输业务的一些数据。例如,如果希望追加自己的业务信息到调用链上,应用可以通过 EagleEye 提供的 API 进行链路分组、链路打标等,EagleEye 会把这些信息一层层的透明往后端系统传递,而且信息也同样记录在每条调用日志里面。
EagleEye 数据透传的功能,在全链路压测、子帐号信息传递、二套环境项目隔离、强弱依赖检测、敏感操作的前端来源跟踪等场景都起到了不可缺少的重要作用。
整体处理架构
下面是EagleEye从日志生成到抓取、存储、分析、展现的多个系统间交互过程。
首先,EagleEye的埋点日志会输出到统一的日志目录下,与业务无关的RPC日志会写文件eagleeye.log,业务埋点日志会写文件biz-eagleeye.log。
随后,tlog服务器会通过每台应用机器上的哈勃agent实时的不断抓取EagleEye日志,按照日志类型不同,将会有不同的处理方式:
全量原始日志都会直接存到云梯HDFS中;
带有实时标记的EagleEye原始日志,放入HBase中存储;
业务日志有一部分会被直接处理,存储到HBase,有一部分会作为消息发送出去,由感兴趣的业务系统订阅处理。
全量日志存储到 HDFS 之后,EagleEye服务器会每小时创建 MapReduce 任务,在云梯上完成对全量日志的调用链合并、分析以及统计,合并好的调用链依旧保存在HDFS*,分析和统计的结果也输出到HDFS,EagleEye服务器在任务执行完毕之后,会将结果拉取到本地建立索引,并保存到HBase。在保存完毕后,就可以在EagleEye的数据展现页面看到分析结果了。