Dapper,大规模分布式系统的跟踪系统

编译自 Dapper, a Large-Scale Distributed Systems Tracing Infrastructure 做者:Benjamin H. Sigelman, Luiz Andre Barroso, Mike Burrows, Pat Stephenson, Manoj Plakal, Donald Beaver, Saul Jaspan, Chandan Shanbhaghtml

背景前端

如今的互联网服务大可能是经过复杂的大规模分布式集群实现的。Google生产环境中的各类应用是由不一样的团队使用不一样的编程语言在不一样的软件模块集上开发实现的。这些应用可能分布在几千台服务器上,横跨多个不一样的数据中心。git

传统跟踪系统每每是整个应用系统的一部分,侵入性强,监控代码段的植入可能致使系统故障,监控间隔的设定也每每会影响总体性能。github

所以,Google内部开发了Dapper,其设计初衷是追踪在线服务系统的请求处理过程。一次搜索请求每每会通过不一样机器甚至不一样集群上的多个子系统的处理。请求处理出现异常后,须要快速发现问题,并准肯定位到出现问题的环节。web

因为异常没法预料且难以重现,所以必须持续跟踪系统行为。此外,跟踪要覆盖全面,避免遗漏重要环节。编程

所以,Dapper须要作到低损耗、对应用透明性且可扩展;同时产生的跟踪数据须要能够被快速分析,帮助用户实时获取在线服务状态。缓存

实现方法服务器

低损耗:采样跟踪,并对收集的跟踪数据二次采样微信

对应用的透明性:修改线程、控制流、RPC等基础库代码,植入跟踪代码。Google的应用使用的是相同的线程、控制流、RPC等基础库代码,因此仅修改基础款代码就可以实现跟踪功能。网络

  • 在跟踪线程处理的过程当中,Dapper会将一个trace context关联到线程本地存储中。trace context中包含了span的相关属性,好比trace和span id。
  • 对于异步线程处理过程,Google开发人员采用通用的控制流库实现回调,将异步线程调度到一个线程池或执行器中进行调用。Dapper保证全部回调都会保存建立者的trace context;同时当该回调被调用时,该trace context也会被关联到对应的线程。这样,Dapper就能够实现这种异步处理过程的跟踪。

植入代码的功能主要包括span建立、采样、本地磁盘日志写入。由于这部分代码会被不少应用所依赖,维护和bug修复难度高,所以须要很是稳定和健壮;同时还要足够轻量。这部分代码的C++实现总共不到1000行,Java实现不到800行。

Dapper支持用户直接获取Tracer对象,并输出自定义信息,用户能够输出本身任意想输出的内容。为防止过分输出,Dapper设置了可配置参数的上限。

跟踪过程当中会产生一个全局惟一ID(在Dapper中是一个64位整数),用于标记该请求。Dapper的一个trace(跟踪过程)其实是一颗树,树中的节点被称为一个span,根节点被称为root span,见下图。

一个span可能包含来自多个主机的信息。实际上,每一个RPC span都包含了来自客户端和服务端的信息。对于客户端的时间与服务端的差别,能够根据“RPC是在服务端接收到请求前由客户端发起的,针对该RPC的响应则是由服务端在客户端接收到前发出的"这一事实肯定服务端响应时间戳的上下限。

Dapper的整个数据收集过程以下图所示:

首先将span数据写入本地日志文件,而后将数据收集并写入Bigtable,每一个trace记录在表中记录为一行。Bigtable的稀疏表结构很是适合存储trace记录,由于每条记录的span数量是任意的。

整个收集过程是out-of-band的,独立于请求处理过程,从而避免影响请求处理。

Dapper提供API,容许用户直接访问跟踪数据。Google开发人员能够基于API开发通用的或针对具体应用的分析工具,从而极大地提升了Dapper的功能和应用范围。

跟踪消耗

若是产生的消耗太高,跟踪系统便会被弃用,所以低消耗很是重要。采样能够减小消耗,但简单的采样可能致使采样结果不具备表明性。Dapper经过自适应采样机制知足性能和表明性要求。

对Dapper来讲,数据收集和分析能够临时关掉,但数据生成必须一直进行,所以trace的生成消耗是最关键的。其中,span和annotation的建立和销毁消耗最大。因为须要产生一个全局惟一的trace id,根span的建立和销毁平均须要204ns;而普通span的建立和销毁只须要176ns。若是span没有被采样到,那么对其添加annotation的开销(约9ns)基本能够忽略;若是被采样到的话,则平均开销是40ns。上述测试是在2.2GHZ的x86服务器上进行的。

本地磁盘写入是Dapper运行库中消耗最高的操做,但能够异步化、批量化,所以基本上只会对吞吐量高的应用产生影响。

Dapper后台进程读出跟踪数据也会产生消耗。但Dapper守护进程的CPU开销始终在0.3%如下,内存占用也不多。

此外也会产生的网络消耗,但因为每一个span平均只有426字节大小,网络消耗只占整个产品系统流量的0.01%不到。

对于每一个请求均可能产生大量跟踪数据的应用来讲,Dapper会经过采样减小消耗。最初,Dapper从每1024个请求中选择一个进行跟踪,这种模式适用于请求量高的服务,能够跟踪到有价值的信息;但对于负载不高的服务,这种方式可能会致使采样频率太低,遗漏重要信息。最后,Dapper选择以时间为采样单位,在单位时间内进行固定次数的采样,从而有效地控制采样频率和消耗。

应用

用户能够经过DAPI(Dapper“Depot API”)直接访问跟踪数据。DAPI提供以下几种访问方式:

  • 指定trace id进行访问;
  • 大规模批量访问。用户能够经过MapReduce job并行访问,只须要实现一个以Dapper trace为参数的虚函数,在该函数内完成本身的处理便可,框架负责为用户指定时间段内的全部trace调用该函数;
  • 经过索引访问。Dapper会为跟踪数据创建索引,用户可经过索引进行查询。因为trace id是随机生成的,所以用户一般须要经过服务名或机器名进行检索(实际上Dapper是按照(服务名,机器名,时间戳)进行索引的)。

大部分用户都是经过一个交互式web接口来使用Dapper的,典型流程以下图所示:

1.用户输入感兴趣的服务和时间窗口,选择相应的跟踪模式(图中为span名称)以及关心的度量参数(图中为服务延迟)

2.页面会展现指定服务的全部分布式执行过程的性能摘要,用户能够根据须要对这些执行过程排序,而后选择其中一个详细查看

3.选定某个执行过程后,页面会展现关于该执行过程的图形化描述,用户可点击选择本身关心的过程

4.系统根据用户在1中选择的度量参数以及在3中选择的具体过程,在页面上展现直方图。上图中的直方图展现了getdocs的延迟分布,用户可点击右侧的example,选择具体的执行过程进行查看

5.显示关于该执行过程的具体信息,上方是时间轴,用户可展开或折叠下方执行过程,查看该执行过程各个组成部分的开销,其中绿色表明处理时间,蓝色表明网络耗时。

总结

在开发过程当中,Dapper能够用于改善性能(分析请求延迟、发现关键路径上没必要要的串行化),进行正确性检查(用户请求是否正确发送给了服务提供者),理解系统(请求处理可能依赖不少其余系统,Dapper帮助用户了解整体延迟,从新设计最小化依赖),测试(新代码release前要经过Dapper跟踪测试,验证系统行为和性能)。

与异常监控系统进行集成。若是异常发生在采样到的Dapper tracer上下文中,那么相应的trace和span id还会被做为异常报告的元数据;前端的异常监控服务也会提供相应连接指向跟踪系统,从而帮助用户了解异常发生时的状况。

解决长尾延迟,帮助用户分析复杂系统环境下的延迟问题。网络性能的瞬时降低不会影响系统的吞吐率,但对延迟有很大影响。不少开销昂贵的查询模式是由未预料到的服务间的交互形成的,Dapper可以更好地发现这种问题。

帮助用户进行服务间依赖的推理。Google维护了很是多的集群,每一个集群承载了各类各样的任务,而任务间可能存在依赖关系。但各个任务须要精确知道其所依赖的服务信息,才能帮助发现瓶颈或进行服务的移动。服务间的依赖关系复杂且处于动态变化中,单纯依赖配置文件很难进行判断。而Dapper的trace信息和DAPIMapReduce接口则能够自动肯定服务间依赖关系。

帮助网络管理员对跨集群的网络活动进行应用层面的分析,帮助发现某些昂贵的网络请求开销的产生缘由。

不少存储系统都是共享的。例如,GFS有不少用户,有些用户是直接访问GFS,有些则可能经过Bigtable对GFS进行访问。若是没有Dapper,这种共享式系统将很难调试。经过Dapper提供的数据,共享服务的owner能够方便地根据各项指标(好比网络负载,请求耗时)对用户进行排序。

Dapper将跟踪数据开放给用户后,激发了用户创造力,发现了不少意料以外的用途。没有跟踪功能的应用只须要用新的库从新编译程序,即可得到跟踪功能,迁移很是方便。

待改进之处

合并产生的影响。咱们一般假设各类子系统会一次处理一个请求。可是某些状况下,请求会被缓存,而后一次性地在一组请求上执行某个操做(好比磁盘写入)。在这种状况下,被追踪的请求拿到的并非其自己的处理过程。

对批量处理进行跟踪。虽然Dapper是为在线服务系统而设计,初衷是理解用户发送请求给Google后产生的一系列系统行为,但离线的数据处理也有这样的需求。所以,能够将trace id与某些有意义的工做单元进行关联,好比输入数据里的一个key(或者是key range)。

寻找根本缘由。Dapper能够迅速找到系统短板,但每每没法高效地寻找根本缘由。例如,某个请求变慢的缘由可能并不在其自身,而是由于在它以前已经有不少请求在排队。用户能够在应用层将某些参数(好比队列大小)交给跟踪系统。

记录内核级信息。不少工具能够进行内核执行过程的跟踪和profiling,但直接将内核级信息捆绑到一个应用层的trace context中很难优雅地实现。折中的解决方案是在应用层获取内核活动参数的快照,而后将快照与活动span关联起来。

Dapper的实现 受Dapper启发,不少厂商纷纷开发了本身的跟踪系统,例如宜信的UAVStack、阿里的鹰眼、Twitter的Zipkin、大众点评的cat以及京东的hydra。

参考资料

  1. Dapper, a Large-Scale Distributed Systems Tracing Infrastructure
  2. https://bigbully.github.io/Dapper-translation/
  3. https://www.cnblogs.com/rongfengliang/p/6209301.html

微信扫一扫,关注该公众号

相关文章
相关标签/搜索