分布式调用跟踪系统架构设计与实践

0、前言

随着美团点评的业务发展,公司的分布式系统变得愈来愈复杂,咱们亟需一个工具可以梳理内部服务之间的关系,感知上下游服务的形态。好比一次请求的流量从哪一个服务而来、最终落到了哪一个服务中去?服务之间是RPC调用,仍是HTTP调用?一次分布式请求中的瓶颈节点是哪个,等等。html

一、简介

MTrace,美团点评内部的分布式会话跟踪系统,其核心理念就是调用链:经过一个全局的ID将分布在各个服务节点上的同一次请求串联起来,还原原有的调用关系、追踪系统问题、分析调用数据、统计系统指标。这套系统借鉴了2010年Google发表的一篇论文《dapper》,并参考了Twitter的Zipkin以及阿里的Eagle Eye的实现。
那么咱们先来看一下什么是调用链,调用链其实就是将一次分布式请求还原成调用链路。显式的在后端查看一次分布式请求的调用状况,好比各个节点上的耗时、请求具体打到了哪台机器上、每一个服务节点的请求状态,等等。它能反映出一次请求中经历了多少个服务以及服务层级等信息(好比你的系统A调用B,B调用C,那么此次请求的层级就是3),若是你发现有些请求层级大于10,那这个服务颇有可能须要优化了。前端

1.1 网络优化

如上图所示,红框内显示了一次分布式请求通过各个服务节点的具体IP,经过该IP就能够查询一次分布式请求是否有跨机房调用等信息,优化调用链路的网络结构。mysql

1.2 瓶颈查询

再好比上图,红框部分显示的是系统调用的瓶颈节点,因为该节点的耗时,致使了整个系统调用的耗时延长,所以该节点须要进行优化,进而优化整个系统的效率。这种问题经过调用链路能很快发现下游服务的瓶颈节点;可是假如没有这样的系统,咱们会怎样作呢?首先我会发现下游服务超时形成了个人服务超时,这时我会去找这个下游服务的负责人,而后该负责人发现也不是他本身服务的问题,而是他们调用了其余人的接口形成的问题,紧接着他又去找下游的服务负责人。咱们都知道跨部门之间的沟通成本很高的,这么找下去会花费大量的没必要要时间,而有了MTrace以后,你只须要点开链路就能发现超时问题的瓶颈所在。sql

1.3 优化链路

咱们再来看下上面这张图,红框部分都是同一个接口的调用,一次请求调用相同的接口10几回甚至是几十次,这是咱们不想看到的事情,那么整个系统能不能对这样的请求进行优化,好比改为批量接口或者提升整个系统调用的并行度?在美团点评内部咱们会针对这样的链路进行筛选分析,而后提供给业务方进行优化。后端

1.4 异常log绑定

经过MTrace不只能作上述这些事情,经过它的特性,还能携带不少业务感兴趣的数据。由于MTrace能够作到数据和一次请求的绑定以及数据在一次请求的网络中传递。好比一些关键的异常log,通常服务的异常log颇有多是由于上游或者下游的异常形成的,那就须要咱们手动地对各个不一样服务的异常log作mapping。看此次的异常log对应到上游服务的哪一个log上,是否是由于上游传递的一些参数形成了该次异常?而经过MTrace就能够将请求的参数、异常log等信息经过traceId进行绑定,很容易地就把这些信息聚合到了一块儿,方便业务端查询问题。网络

1.5 透明传输数据

业务端每每有这样的需求,它但愿一些参数能在一次分布式请求一直传递下去,而且能够在不一样的RPC中间件间传递。MTrace对该类需求提供了两个接口:架构

put(map<String, String> data)
putOnce(map<String, String> data)
  • put 接口:参数能够在一次分布式请求中一直传递。
  • putOnce 接口:参数在一次分布式请求中只传递一级。

以下图所示app

  • 左侧绿色部分是put接口,service中调用了put接口传递了uid=123456这个参数,它会在网络中一直传递,能够在服务A中经过get("uid")的方式获取参数值,也能够在服务C中经过get("uid")的方式获取参数值。
  • 右侧蓝色部分是putOnce接口,service中调用了putOnce接口传递pid=11111,它只会传递一级,能够在服务B中经过get("pid")的方式获取参数值,可是在服务D中就获取不到pid的值了。

以上的两种接口能够用于业务自定义传递数据,好比经过传递一个服务标识,用于AB test,下游的全部服务获取到test的标识就会走test的策略,即上游服务能够传递一些参数,控制全部下游服务的逻辑。固然业务也能够经过该接口传递一些临时性的数据。框架

二、系统架构

主要分为三层:数据埋点上报、数据收集计算、数据前端展现。异步

分布式调用链跟踪系统设计目标:

  • 低侵入性 – 做为非业务组件,应当尽量少侵入或者无侵入其余业务系统,对于使用方透明,减小开发人员的负担;
  • 灵活的应用策略 – 能够(最好随时)决定所收集数据的范围和粒度;
  • 时效性 – 从数据的收集和产生,到数据计算和处理,再到最终展示,都要求尽量快;
  • 决策支持 – 这些数据是否能在决策支持层面发挥做用,特别是从 DevOps 的角度;
  • 可视化才是王道。

2.1 基本概念

traceId

全局惟一,64位整数,用于标识一次分布式请求,会在RPC调用的网络中传递。

spanId

签名方式生成:0, 0.1, 0.1.1, 0.2。用于标识一次RPC在分布式请求中的发生顺序和嵌套层次关系,好比0.2就是0节点服务调用的第二个服务。

annotation

业务端自定义埋点,业务感兴趣的想上传到后端的数据,好比该次请求的用户ID等。

2.2 数据埋点

埋点SDK

提供统一的SDK,在各个中间件中埋点,生成traceID等核心数据,上报服务的调用数据信息。

  • 生成调用上下文;
  • 同步调用上下文存放在ThreadLocal, 异步调用经过显式调用API的方式支持;
  • 网络中传输关键埋点数据,用于中间件间的数据传递,支持Thrift, HTTP协议。

业内有些系统是使用注解的方式实现的埋点,这种方式看似很优雅,可是须要业务方显式依赖一些AOP库,这部分很容易出现问题,由于AOP方式太过透明,致使查问题很麻烦,并且业务方配置的东西越多越容易引发一些意想不到的问题,因此咱们的经验是尽可能在各个统一的中间件中进行显式埋点,虽然会致使代码间耦合度增长,可是方便后续定位问题。其次,为了整个框架的统一,MTrace并不是仅支持Java一种语言,而AOP的特性不少语言是不支持的。

Agent

  • 透传数据,用做数据转发;
  • 作流量控制;
  • 控制反转,不少策略能够经过agent实现,而不须要每次都升级业务代码中的SDK。

Agent仅仅会转发数据,由Agent判断将数据转发到哪里,这样就能够经过Agent作数据路由、流量控制等操做。也正是因为Agent的存在,使得咱们能够在Agent层实现一些功能,而不须要业务端作SDK的升级,要知道业务端SDK升级的过程是很缓慢的,这对于整个调用链的系统来讲是不可接受的,由于MTrace整个系统是针对庞大的分布式系统而言的,有一环的服务缺失也会形成必定的问题。

目前MTrace支持的中间件有:

  • 公司内部RPC中间件
  • http中间件
  • mysql中间件
  • tair中间件
  • mq中间件

数据埋点的四个阶段:

  • 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资源也是值得的。具体上报的数据如图所示:

咱们以前在数据埋点时遇到了一些问题:

  • 异步调用
    • 异步IO形成的线程切换,不能经过ThreadLocal传递上下文。
    • 显式的经过API进行埋点传递,切换前保存,切换后还原。
    • 提供封装好的ThreadPool库。
  • 数据量大,天天千亿级别的数据
    • 批量上报
    • 数据压缩
    • 极端状况下采样

2.3 数据存储

Kafka使用

咱们在SDK与后端服务之间加了一层Kafka,这样作既能够实现两边工程的解耦,又能够实现数据的延迟消费。咱们不但愿由于瞬时QPS太高而引发的数据丢失,固然为此也付出了一些实效性上的代价。

实时数据Hbase

调用链路数据的实时查询主要是经过Hbase,使用traceID做为RowKey,能自然的把一整条调用链聚合在一块儿,提升查询效率。

离线数据Hive

离线数据主要是使用Hive,能够经过SQL进行一些结构化数据的定制分析。好比链路的离线形态,服务的出度入度(有多少服务调用了该服务,该服务又调用了多少下游服务)

2.4 前端展现

前端展现,主要遇到的问题是NTP同步的问题,由于调用链的数据是从不一样机器上收集上来的,那么聚合展现的时候就会有NTP时间戳不一样步的问题,这个问题很难解决,因而咱们采起的方式是前端作一层适配,经过SpanId定位调用的位置而不是时间,好比0.2必定是发生在0.1这个Span以后的调用,因此若是时间出现漂移,就会根据SpanId作一次校订。即判断时间顺序的优先级为最高是spanid,而后是时间戳。

三、总结

核心概念:调用链;
用途:定位系统瓶颈,优化系统结构、统计系统指标、分析系统数据;
架构:埋点上报、收集计算、展现分析。

分布式会话跟踪系统主要的特色就是能关联服务之间的联动关系,经过这层关系能够延伸出来不少有意义的分析数据,统计数据。为优化系统结构,查询系统瓶颈问题带来了极大的便利。

四、Refer

[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-链家全链路跟踪平台设计实践

https://mp.weixin.qq.com/s/CAC1zG0nX3yMKqwuL2d2jQ

相关文章
相关标签/搜索