随着美团点评的业务发展,公司的分布式系统变得愈来愈复杂,咱们亟需一个工具可以梳理内部服务之间的关系,感知上下游服务的形态。好比一次请求的流量从哪一个服务而来、最终落到了哪一个服务中去?服务之间是RPC调用,仍是HTTP调用?一次分布式请求中的瓶颈节点是哪个,等等。html
MTrace,美团点评内部的分布式会话跟踪系统,其核心理念就是调用链:经过一个全局的ID将分布在各个服务节点上的同一次请求串联起来,还原原有的调用关系、追踪系统问题、分析调用数据、统计系统指标。这套系统借鉴了2010年Google发表的一篇论文《dapper》,并参考了Twitter的Zipkin以及阿里的Eagle Eye的实现。
那么咱们先来看一下什么是调用链,调用链其实就是将一次分布式请求还原成调用链路。显式的在后端查看一次分布式请求的调用状况,好比各个节点上的耗时、请求具体打到了哪台机器上、每一个服务节点的请求状态,等等。它能反映出一次请求中经历了多少个服务以及服务层级等信息(好比你的系统A调用B,B调用C,那么此次请求的层级就是3),若是你发现有些请求层级大于10,那这个服务颇有可能须要优化了。前端
如上图所示,红框内显示了一次分布式请求通过各个服务节点的具体IP,经过该IP就能够查询一次分布式请求是否有跨机房调用等信息,优化调用链路的网络结构。mysql
再好比上图,红框部分显示的是系统调用的瓶颈节点,因为该节点的耗时,致使了整个系统调用的耗时延长,所以该节点须要进行优化,进而优化整个系统的效率。这种问题经过调用链路能很快发现下游服务的瓶颈节点;可是假如没有这样的系统,咱们会怎样作呢?首先我会发现下游服务超时形成了个人服务超时,这时我会去找这个下游服务的负责人,而后该负责人发现也不是他本身服务的问题,而是他们调用了其余人的接口形成的问题,紧接着他又去找下游的服务负责人。咱们都知道跨部门之间的沟通成本很高的,这么找下去会花费大量的没必要要时间,而有了MTrace以后,你只须要点开链路就能发现超时问题的瓶颈所在。sql
咱们再来看下上面这张图,红框部分都是同一个接口的调用,一次请求调用相同的接口10几回甚至是几十次,这是咱们不想看到的事情,那么整个系统能不能对这样的请求进行优化,好比改为批量接口或者提升整个系统调用的并行度?在美团点评内部咱们会针对这样的链路进行筛选分析,而后提供给业务方进行优化。后端
经过MTrace不只能作上述这些事情,经过它的特性,还能携带不少业务感兴趣的数据。由于MTrace能够作到数据和一次请求的绑定以及数据在一次请求的网络中传递。好比一些关键的异常log,通常服务的异常log颇有多是由于上游或者下游的异常形成的,那就须要咱们手动地对各个不一样服务的异常log作mapping。看此次的异常log对应到上游服务的哪一个log上,是否是由于上游传递的一些参数形成了该次异常?而经过MTrace就能够将请求的参数、异常log等信息经过traceId进行绑定,很容易地就把这些信息聚合到了一块儿,方便业务端查询问题。网络
业务端每每有这样的需求,它但愿一些参数能在一次分布式请求一直传递下去,而且能够在不一样的RPC中间件间传递。MTrace对该类需求提供了两个接口:架构
put(map<String, String> data) putOnce(map<String, String> data)
以下图所示app
以上的两种接口能够用于业务自定义传递数据,好比经过传递一个服务标识,用于AB test,下游的全部服务获取到test的标识就会走test的策略,即上游服务能够传递一些参数,控制全部下游服务的逻辑。固然业务也能够经过该接口传递一些临时性的数据。框架
主要分为三层:数据埋点上报、数据收集计算、数据前端展现。异步
分布式调用链跟踪系统设计目标:
全局惟一,64位整数,用于标识一次分布式请求,会在RPC调用的网络中传递。
签名方式生成:0, 0.1, 0.1.1, 0.2。用于标识一次RPC在分布式请求中的发生顺序和嵌套层次关系,好比0.2就是0节点服务调用的第二个服务。
业务端自定义埋点,业务感兴趣的想上传到后端的数据,好比该次请求的用户ID等。
提供统一的SDK,在各个中间件中埋点,生成traceID等核心数据,上报服务的调用数据信息。
业内有些系统是使用注解的方式实现的埋点,这种方式看似很优雅,可是须要业务方显式依赖一些AOP库,这部分很容易出现问题,由于AOP方式太过透明,致使查问题很麻烦,并且业务方配置的东西越多越容易引发一些意想不到的问题,因此咱们的经验是尽可能在各个统一的中间件中进行显式埋点,虽然会致使代码间耦合度增长,可是方便后续定位问题。其次,为了整个框架的统一,MTrace并不是仅支持Java一种语言,而AOP的特性不少语言是不支持的。
Agent仅仅会转发数据,由Agent判断将数据转发到哪里,这样就能够经过Agent作数据路由、流量控制等操做。也正是因为Agent的存在,使得咱们能够在Agent层实现一些功能,而不须要业务端作SDK的升级,要知道业务端SDK升级的过程是很缓慢的,这对于整个调用链的系统来讲是不可接受的,由于MTrace整个系统是针对庞大的分布式系统而言的,有一环的服务缺失也会形成必定的问题。
目前MTrace支持的中间件有:
Client Send : 客户端发起请求时埋点,须要传递一些参数,好比服务的方法名等
Span span = Tracer.clientSend(param);
Server Recieve : 服务端接收请求时埋点,须要回填一些参数,好比traceId,spanId
Tracer.serverRecv(param);
ServerSend : 服务端返回请求时埋点,这时会将上下文数据传递到异步上传队列中
Tracer.serverSend();
Client Recieve : 客户端接收返回结果时埋点,这时会将上下文数据传递到异步上传队列中
Tracer.clientRecv();
上图CS、SR为建立上下文的位置,CR、SS为归档上下文的位置。
上下文归档,会把上下文数据异步上传到后端,为了减轻对业务端的影响,上下文上报采用的是异步队列的方式,数据不会落地,直接经过网络形式传递到后端服务,在传递以前会对数据作一层压缩,主要是压缩比很可观,能够达到10倍以上,因此就算牺牲一点CPU资源也是值得的。具体上报的数据如图所示:
咱们在SDK与后端服务之间加了一层Kafka,这样作既能够实现两边工程的解耦,又能够实现数据的延迟消费。咱们不但愿由于瞬时QPS太高而引发的数据丢失,固然为此也付出了一些实效性上的代价。
调用链路数据的实时查询主要是经过Hbase,使用traceID做为RowKey,能自然的把一整条调用链聚合在一块儿,提升查询效率。
离线数据主要是使用Hive,能够经过SQL进行一些结构化数据的定制分析。好比链路的离线形态,服务的出度入度(有多少服务调用了该服务,该服务又调用了多少下游服务)
前端展现,主要遇到的问题是NTP同步的问题,由于调用链的数据是从不一样机器上收集上来的,那么聚合展现的时候就会有NTP时间戳不一样步的问题,这个问题很难解决,因而咱们采起的方式是前端作一层适配,经过SpanId定位调用的位置而不是时间,好比0.2必定是发生在0.1这个Span以后的调用,因此若是时间出现漂移,就会根据SpanId作一次校订。即判断时间顺序的优先级为最高是spanid,而后是时间戳。
核心概念:调用链;
用途:定位系统瓶颈,优化系统结构、统计系统指标、分析系统数据;
架构:埋点上报、收集计算、展现分析。
分布式会话跟踪系统主要的特色就是能关联服务之间的联动关系,经过这层关系能够延伸出来不少有意义的分析数据,统计数据。为优化系统结构,查询系统瓶颈问题带来了极大的便利。
[1] 分布式会话跟踪系统架构设计与实践
http://tech.meituan.com/mt-mtrace.html
[2] 分布式调用跟踪系统调研笔记
http://ginobefunny.com/post/learning_distributed_systems_tracing/
[3] 分布式调用跟踪与监控实战
https://yq.aliyun.com/articles/75338
[4] 惟品会Microscope——大规模分布式系统的跟踪、监控、告警平台
http://blog.csdn.net/alex19881006/article/details/24381109
[5] #研发解决方案介绍#Tracing(鹰眼)
http://www.cnblogs.com/zhengyun_ustc/p/55solution2.html
[6] 从宏观到微观——天机与鹰眼联手
http://www.cnblogs.com/zhengyun_ustc/p/m2m.html
[7] 分布式系统调用跟踪实践
https://t.hao0.me/devops/2016/10/15/distributed-invoke-trace.html
[8] 微服务架构下,如何实现分布式跟踪?
http://www.infoq.com/cn/articles/how-to-realize-distributed-tracking
[9] LTrace-链家全链路跟踪平台设计实践