Git Product home page Git Product logo

dapper-translation's Introduction

Dapper,大规模集群的跟踪系统 作者:Benjamin H. Sigelman, Luiz Andr´e Barroso, Mike Burrows, Pat Stephenson, Manoj Plakal, Donald Beaver, Saul Jaspan, Chandan Shanbhag

  • 概述: 当代互联网的服务通常是搭建在大规模分布式集群上。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千个节点,横跨很多台物理机上。因此,用来帮助理解系统行为、用于分析性能问题的工具在这样一个环境下就显得很必要了。 在这里我们要介绍一下Dapper的设计理念,Dapper是Google生产环境下的分布式跟踪系统。我们会介绍我们如何设计一个低损耗、对应用透明的、满足遍布在大规模集群需求的跟踪系统。Dapper参考了一些其他分布式系统的理念包括Magpie和X-Trace,但是一些关键性的设计点致使Dapper能成功应用在我们的生产环境中,比如使用采样率,把代码植入限制在非常小范围的Lib包的引入。 发表这篇论文最主要的目的汇报一下我们的构建和部署的经验以及两年来的使用经验,自从Dapper一流的监控功能对开发者和运维团队的提供的帮助。Dapper从一个独立的跟踪组件开始,但最终进化成一个包含了促生出多种多样的工具(其中的一部分甚至已经不是由Dapper团队开发的了)的监控平台。我们描述了一些分析工具是使用Dapper搭建的,分享出这些工具在google内部的分析数据,以及使用用例和迄今为止的一些讨论内容。

  • 介绍 我们开发Dapper是为了给Google的开发者们提供更多的关于复杂分布式系统行为的信息。这样的系统有一个特殊的作用,因为大规模的低端服务器为互联网的各种服务提供了一个特殊的又经济划算的平台。在这个生产环境中理解分布式系统的行为需要观察这些横跨了不同的应用、不同的节点之间的彼此关联的动作。 下面举一个跟搜索相关的例子来阐述哪些挑战是Dapper需要处理的。一个前段服务可能对上百台查询节点发起了一个Web查询的请求,每一个查询都有自己的Index。这个查询可能会被发送到很多其他的子系统,这些子系统分别用来处理广告、进行拼写检查或是查找一些像图片、视频或新闻这样的特殊结果。最终的结果会从这些服务的结果中进行筛选,最后汇总到页面上。我们把这中搜索模型称为“全局搜索”(universal search)。总的来说,这一次全局搜索有可能调用上千个节点和多种多样的服务。而且,真正做搜索的这个用户对查询耗时是很敏感的,而查询耗时可能由于任何一个子系统的低效导致。如果一个工程师想查找这个低效的潜在原因,他可能只知道这是个问题,但是不知道这个问题是哪个服务调用造成的,或者为什么这个调用会表现的不尽如人意。首先这个工程师可能不能准确的定位到这次全局搜索是调用了哪个服务,因为新的服务甚至服务上的某个组成部分都有可能在任何一周被上线或修改过,而且这个服务有可能是直接对外的那部分也有可能是一些例如针对性能或安全认证方面的服务。第二,你不能苛求这个工程师对所有参与这次全局搜索的服务都了如指掌,这每一个服务都有可能是不同的团队开发并且维护的。第三,这些暴露出来的服务或节点有可能同时还被其他客户端使用着,所以一个这个全局搜索的性能问题有可能是其他应用造成的。举个例子,一个后台服务可能要应付各种各样的请求类型,或是一个使用效率很高的数据库库(Bigtable)可能正被很多很多应用使用着。 上面这个案例归结为对于Dapper的两个基础需求:无所不在的部署,以及持续监控。无所不在很是重要,因为在使用跟踪系统的过程中即便是一个很小的部分违背监控到,那么整个跟踪系统的可用性都会受到冲击。另外,监控应该是7x24的,因为通常是一些罕见或和非常见行为出现的状况,这些状况恰恰是不可重现的。那么,从这两个需求可以直接推出三个具体的设计目标: 1.低成本:跟踪系统应该有着对在线服务可以忽略不计的性能影响。在一些高度优化的服务,即使是很小的监测间接成本是很容易看到,并有可能迫使部署团队将跟踪系统关闭。 2.应用程序级别的透明度:程序员不应该需要知道跟踪系统的。一个为了能发挥作用需要依赖应用级别开发者的主动合作的跟踪系统是非常脆弱的,往往因内嵌的跟踪系统组件的错误或遗漏导致应用问题,才无法满足对跟踪系统无所不在的要求。这在一个快节奏的发展是特别重要,尤其像我们这样的环境。 3.可度量性:它需要处理Google的至少在未来几年的服务和集群的规模。 额外的设计目标是为跟踪数据产生之后可以迅速的利用到数据分析中,理想情况是一分钟之内。尽管跟踪分析系统一小时前的旧数据还是相当有价值的,提供新鲜的信息可以更快地反应生产异常。 真正的应用程序级别的透明度,这可能是我们最挑战性的设计目标,是通过限制核心代码至无所不在的线程的小语库(a small corpus of ubiquitous threading这让人怎么翻译)、控制流和RPC库代码。系统的可扩展性和性能降低开销得益于利用自适应 采样,这将在第4.4节中描述的。展示结果的系统也包含一些收集跟踪的数据的代码、用来图形化的工具以及用来分析大规模跟踪数据的库和API。虽然Dapper自身有时是足够让开发人员查明表现异常的来源,但是它的目的不是要取代所有其他的工具。我们已经发现,Dapper的全系统的数据往往侧重性能方面的调查,以便其他工具可以适用在本地。

  1. 贡献的总结 具有分布式系统的跟踪工具的设计空间参照了一些以前的优秀文章,其中的Pinpoint、Magpie和X-Trace和Dapper最为相近。这些系统往往在其发展的早起在研究文献中被描述过,才会有机会 清楚地评估这个重要的设计选择。由于Dapper已经在大规模生产和经营 多年,我们觉得这将是最合适的时机把这篇论文重点放在Dapper的部署告诉了我们什么,我们的设计设计是如何实践的,以及以什么样的方式它才会是最有用的。Dapper,作为为开发性能分析 工具以及Dapper自身作为监测工具提供的平台,它的价值是我们可以在回顾评估中找出一些意想不到的结果。 虽然Dapper在许多高层次的设计**上与Pinpoint和Magpie有异曲同工之妙,但我们的实现包含了许多在这个领域中的新的贡献。例如,我们对于低消耗来说采样率是必要的,特别是在高度优化的而且往往是对延迟相当敏感的Web服务中。或许更令人惊讶的是,我们发现即便是1/1000的采样率也可以提供许多常见用途的总以用来展现信息的跟踪数据。 我们的系统的另一个重要的特征是我们能实现的应用程序级的透明程度。我们的组件在软件堆中被限制到在足够低的水平,即使是规模大如Google网页搜索的分布式系统也可以进行跟踪而无需额外的注释。虽然由于我们的部署系统有幸是一定程度的同质化的,导致更容易做到这点(透明性),但是我们证明了这是实现这种程度的透明度的充分条件(汗...)。

2.Dapper的分布式跟踪 分布式的跟踪组件需要记录在一次特定的请求后系统中完成的所有的工作记录下的信息。举个例子,图1展现的是一个和5个服务器相关的一个服务,包括:前段(A),两个中间层(B和C),以及两个后端(D和E)。当一个用户作为这个用例的发起人发起一个请求时,首先到达前段,然后发送两个RPC到服务器B和C。B会发上做出反应,但是C需要和后端的D和E交互之后再返还给A,这反过来又响应最初的请求。一个简单而有用的分布式跟踪的需求就是为每一个消息在每个服务器上发送和接收收集消息的标识符和时间戳。 两个类别的解决方案已经被提出来用来汇总此信息,以便可以将所有记录条目与一个给定的发起者(例如,图1中的RequestX),黑盒和基于注解的监控方案。黑盒方案[1,15,2](这里指本论文的引用,会在文章结尾处列出)假定这里没有额外的信息除了上文所述的这些内容(id,timestamp),使用统计回归技术来推断两者之间的关系。基于注解的方案[3,12,9,16]依赖于应用程序或中间件明确地标记一个全局标识符,每一条记录连接这些消息记录的请求。虽然黑盒计划比注解的方法更轻便,他们需要更多的数据,以获得足够的精度,因为他们依赖于统计推论。基于标注的方案最主要的缺点是,很明显,需要组件的程序开发。在我们的环境中,因为所有的应用程序使用相同的线程模型,控制流和RPC系统中,我们发现,可以限制组件至一个很小的通用库中,并实现了监测系统的应用对开发人员是有效和透明的。 我们倾向于认为,Dapper的跟踪架构是嵌套RPC的树形结构。然而,我们的核心数据模型不限制在 我们的特定的RPC框架,我们还跟踪其他行为如在Gmail的SMTP会话,外界的HTTP请求,和外部对SQL服务器的查询。从形式上看,我们的Dapper跟踪模型使用的树形结构,跨度以及标注。

2.1跟踪树和段 在Dapper跟踪树结构中,树节点是整个架构的基本单元,整个架构又是对段的引用。它的边缘表示的段和它的父段跨度的因果关系。跨度在整个树形结构中是相对独立的,虽然一个跨度也是一个简单的日志记录了开始和结束时间,任何RPC相关的时间数据、零个或多个特定应用程序的标注的相关内容会在在2.3节中讨论。 我们在图2中说明了段在一个大的跟踪操作中是什么样的。Dapper记录了人类可读的段的名字,以及每个段的ID和父段ID,以重建在一次追踪过程中不同段之间的关系。如果一个段没有父ID被称为根段。所有段都挂在一个特定的跟踪上,也共用一个跟踪id(在图中未示出)。所有这些ID概率唯一的64位整数。在一个典型的Dapper的跟踪中,我们希望为每一个RPC对应到一个单一的段上,而且每一个额外的组件层都对应一个跟踪树型结构的层级。 图3给出了一个更详细的典型的Dapper跟踪段的日志事件的视图。在图2中这种特殊的段表述了两个“Helper.Call”的RPC。段的开始和结束时间,以及任何RPC的时间信息都被Dapper的RPC库组件记录下来。如果应用程序所有者选择在跟踪中增加他们自己的注释(如图中“foo”的注释),这些信息也会和其他段信息一样记录下来。 记住,任何一个段可以包含来自多个主机的信息,这些也要记录下来。事实上,每一个RPC段包含 从客户端和服务器过程的注释,使得链接连个主机的段会成为最常见的形式(这里的意思是,比如有一次调用,我们称为段A,是从C1节点对C2节点的调用,那么这个A就连接C1和C2,它就能获取到C1和C2两端的信息)。由于客户端和服务器上的时间戳来自不同的主机,我们必须考虑到时间偏差。在我们的分析工具,我们利用了这个事实:RPC客户端发送一个请求之后,服务器端才能接收到,对于响应也是一样的(服务器先响应,然后客户端才能接收到这个响应)。这样一来,服务器端的RPC就有一个时间戳的一个上限和下限。

2.2组件的要点 Dapper可以以对应用开发者近乎零干涉的成本对分布式控制路径进行跟踪,完全依赖于基于少量通用库的组件。如下: @当一个线程在处理跟踪控制路径的过程中,Dapper把这次跟踪的上下文的在ThreadLocal中进行存储。追踪上下文是一个小而且容易复制的容器承载了段的属性比如跟踪ID和其他段ID。 @当计算过程被推迟或是异步的,大多数Google开发者使用一个通用控制流库来回调和放入线程池或其他executor。Dapper确保所有这样的回调可以存储这次跟踪的上下文,而当回调函数被触发时,这次跟踪的上下文会与适当的线程关联上。在这种方式下,用来在异步后重建这次跟踪的Dapper的id可以透明的跟踪异步控制路径(In this way, the Dapper ids used for trace reconstruction are able to follow asynchronous control paths transparently.这的意思可能是用了一个唯一标示来辅助构建异步调用的路径)。 @几乎所有的Google的进程间通信是建立在一个用C++和Java开发的RPC框架上。我们使用该框架定义RPC中所有的段。段的ID和跟踪的ID会从客户端发送到服务器。像那样的基于RPC的系统被广泛使用在谷歌中,这是一个重要的监测点。当他们的发展成熟找到了自己的用户群之后,我们计划构建非RPC通信框架。

Dapper的跟踪数据是独立于语言的,很多在生产环境中的跟踪结合了用C++和Java写的进程的数据。在3.2节中,我们讨论应用程序的透明度时我们会把这些理论的落地进行讨论。

2.3标注 上述要点足够推导出复杂的分布式系统跟踪详细,使得Dapper的核心功能在不改动Google应用的情况下可用。然而,Dapper还允许应用程序开发人员在Dapper跟踪的过程中添加额外的信息,以监控更高级别的系统行为,或帮助调试问题。我们允许用户通过一个简单的API定义时间戳的标注,核心的示例代码入图4所示。这些标注可以添加任意内容。为了保护Dapper的用户意外的过分热衷于日志的记录,独立的跟踪段有一个可配置的总标注量的上限。应用程序级的标注是不能够用应用程序的行为来取代结构段或RPC的信息。 除了简单的文本标注,Dapper也支持的key-value的Map标注,让开发人员更多的跟踪能力,如保持计数器,二进制消息记录和在一个进程内的跟踪请求上传输任意用户定义的数据。键值对的标注方式用来在分布式追踪的上下文中定义特定于应用程序的等价类型。

2.4采样率 低开销的是Dapper的一个关键设计目标,因为如果这个工具价值未被证实但又对性能有所影响的话,服务运营人员不愿意部署它也是可以理解的。况且,我们想让开发人员使用标注的API,而不用担心额外的开销。我们还发现,某些类别的Web服务是对组件的性能损耗十分敏感的。因此,除了使Daper的的收集工作对基本组件的性能消耗尽可能地小,我们有进一步控制消耗的办法,那就是只记录很多跟踪中的一小部分的。我们将在4.4节中讨论这个跟踪的更多细节。

2.5跟踪的收集 Dapper的跟踪记录和收集管道是一个分三个阶段的过程中(参见图5)。首先,段数据 写入(1)本地日志文件。然后Dapper的守护进程和收集组件把这些数据从生产环境的主机中拉出来(2),最终写到(3)独特的区域型Dapper Bigtable仓库中(比如咱们的HBASE)。一次跟踪被设计成Bigtable中的一行,每一列相当于一个段。Bigtable的支持稀疏表格布局正适合这种情况,在这里,因为每一次跟踪可以有任意的段。跟踪数据收集的平均延迟--也就是说,从应用中的二进制数据传输到**仓库(Bigtable)所花费的时间,不多于15秒。98的百分比延迟是随着时间的推移双峰分布的(bimodal),约75%的时间,98%的收集延迟是少于两分钟的,但其余约25%的时间可以长达数小时(这句话挺绕的,最好看看原文,我也翻译不出来)。 Dapper还提供了一个API来简化访问我们仓库中的跟踪数据。Google的开发人员用这个API,以构建通用和特定应用程序的分析工具。第5.1节包含更多关于它的使用的的信息

2.5.1带外(out-of-band)跟踪收集 Dapper系统带需求树自身进行跟踪记录和收集带外数据。(The Dapper system as described performs trace logging and collection out-of-band with the request tree itself) 这样做是为两个不相关的原因。首先,带内收集方案--这里跟踪数据会以RPC响应头的形式被返回--可以影响应用程序网络动态。在Google里的许多规模较大的系统中,成千上万的段并不少见。然而,RPC回应大小--甚至是接近大型分布式的跟踪的根节点的这种情况下-- 仍然是比较小的:通常小于10K。在这种情况下,带内Dapper的跟踪数据会让应用程序数据和倾向于使用后续分析结果的数据量相形见绌。除此之外,带内收集方案假定所有的RPC是完美 嵌套的。我们发现,在所有的后端的系统返回的最终结果之前,有许多中间件会把结果返回给他们的调用者。带内收集系统是无法解释这种非嵌套的分布式执行模式的(这段的翻译还是好好看看原文吧,太晦涩了,不过大概意思应该是这样,带内(in-band)可能指的是系统内自己的收集,(out-of-band)可能指的是作为独立于组件的数据收集方式)。

2.6安全和隐私考虑 记录一定量的RPC有效负载信息将丰富Dapper的跟踪能力,因为分析工具能够在有效载荷数据中找到相关的模式,这写模式可以解释被监控系统的表现异常。然而,有几种情况是有效载荷数据可能包含的一些不应该透露给未经授权用户的内部信息,包括工程师在做性能调试工作的情况。 由于安全和隐私问题是不可忽略的,dapper中的虽然存储RPC方法的名称,但在这个时候不记录任何有效载荷数据。相反,应用程序级别的标注提供了一个方便的可选机制:应用程序开发人员可以在段中选择关联那些为以后分析提供价值的数据。 Dapper还提供了一些安全上的好处,是它的设计者事先没有预料到的。通过跟踪公开的安全协议参数,Dapper可以通过相应级别的认证或加密,来监视应用程序是否满足安全策略。例如。Dapper还可以提供信息,以基于策略的的隔离系统按预期执行,例如支撑敏感数据的应用程序不与未经授权的系统组件进行了交互。这样的测算提供了比源码审核更强大的保障。

3.Dapper部署状况 Dapper作为我们生产环境下的跟踪系统已经超过两年。在本节中,我们会针对系统状态展现出一些东西,把重点放在Dapper如何满足了我们的目标——无处不在的部署和应用程序级别的透明度。

3.1Dapper运行库 也许Dapper代码中中最关键的部分,就是关于基础RPC、线程控制和流程控制的库,其中包括段的创建,采样率的设置,以及把日志写入本地磁盘。除了做到轻量级,这段代码更需要稳定和健壮,因为它与海量的应用对接,维修和bug修复变得困难。核心代码是由未超过1000行的C++和不超过800行Java代码实现的。实现键值对的标注还添加了额外的500行代码。

3.2生产环境下的涵盖面 Dapper的渗透可以总结为两个方面:一方面是可以创建Dapper跟踪的生产进程(比如那些连接到Dapper运行库部分),和生产环境下的节点在运行Dapper跟踪收集守护进程。Dapper的守护进程是我们基本的服务器映像(basic machine image),使它存在于Google几乎所有的服务器上。这很难确定精确的Dapper-ready进程部分,因为过程即便不产生跟踪信息Dapper也是无从知晓的。尽管如此,考虑到无处不在Dapper组件的植入库,我们估计几乎每一个Google的生产进程都是 支持跟踪的。 在某些情况下Dapper的是不能正确的跟踪控制路径的。这些通常源于使用非标准的控制流​​,或是Dapper的错误的把段与段之间的联系归到不相关的事件上。Dapper提供了一个简单的库来帮助开发者手动控制跟踪传播作为一种变通方法。目前有40个C++应用程序和33个Java应用程序需要一些手动控制的追踪传播,不过这只是上前的跟踪中的一小部分。也有一个很小一部分程序使用的非组件性质的通信库库(比如原生的TCP Socket或SOAP RPC),因此不能直接支持Dapper的跟踪。但是这些应用可以单独接入到Dapper中,如果需要的话。 考虑到生产环境的安全,Dapper的跟踪也可以关闭。事实上,早起它默认就是关闭的,直到我们对Dapper的稳定性和低开销有了足够的信心之后才把它开启。Dapper的团队偶尔会执行审查寻找跟踪配置的变化,来看看那些服务关闭了Dapper的跟踪。但这种情况不多见,而且通常是源于对监控对性能消耗的担忧。经过了对实际性能消耗的进一步调查和测量,所有这些关闭Dapper的改变至今都已经恢复,不过这些已经不重要了。

3.3跟踪标注的使用 程序员倾向于使用特定于应用程序的标注无论是作为一种分布式调试日志文件或通过一些应用程序特定的功能进行分类跟踪。例如,所有的Bigtable的请求的都标注了被访问的表的名称。目前,70%的Dapper段和90%的所有Dapper跟踪至少有一个应用程序指定的标注。 41个Java应用和68个C++应用中都添加自定义的标注为了更好地理解应用程序中的段在他们的服务中的行为。值得注意的是,迄今为止我们的Java开发者比C++开发者更多的在每一个跟踪段上采用标注的API。这可能是因为我们的Java工作负载往往是更接近最终用户;这些类型的应用程序经常处理更广泛的请求组合,因此具有比较复杂的控制路径。

4.处理跟踪的消耗 跟踪系统的成本由两部分组成:正在被监控的系统在生成追踪和收集追踪数据的消耗导致系统性能下降,以及需要使用一部分资源来存储和分析跟踪数据。虽然你可以说一个有价值的跟踪组件的植入引起一部分性能损耗是值得的,我们相信如果基本损耗能达到可以忽略的程度那对跟踪系统最初的推广会由极大的帮助。 在本节中,我们会展现一下三个方面:Dapper组件操作的消耗,跟踪手机的消耗,以及Dapper对生产环境负载的影响。我们还介绍了Dapper可调节的采样率机制如何帮我们平衡对低消耗的需要以及对跟踪代表性的需要。

4.1生成跟踪的消耗 跟踪生成的开销是Dapper性能影响中最关键的部分,因为收集和分析可以更容易地在紧急情况下被关闭。Dapper运行库中最重要的跟踪生成消耗在于创建和销毁段和标注,并记录到本地磁盘供后续的收集。根段的创建爱你和销毁需要消耗平均204纳秒的时间,而同样的操作在其他段上需要消耗176纳秒。时间上的差别主要在于需要在跟段上给一次跟踪分配一个全局唯一的ID。 如果一个段没有被采样的话,那么这个段的额外的标注成本几乎可以忽略不计,他由在Dapper运行期对ThreadLocal查找操作构成,这平均只消耗9纳秒。如果这个段被计入采样的话,会用一个String进行标注--在图4中有展现--平均需要消耗40纳秒。这些数据都是在2.2GHz的x86服务器上采集的。 在Dapper运行期写入到本地磁盘是最昂贵的操作,但是他们的可见消耗大大减少,因为写入日志文件和操作相对于被跟踪的应用系统来说都是异步的。不过,日志写入的操作如果在大流量的情况,尤其是每一个请求都被跟踪的情况下就会变得可以察觉到。我们记录了在4.3节展示了一次Web搜索的负载下的性能消耗。

4.2跟踪收集的消耗 读出跟踪数据也会对正在被监控的负载产生干扰。表1展示最坏情况下,Dapper收集日志的守护进程在高于实际情况的负载基准下进行测试得到的cpu使用率。在生产环境下,跟踪数据处理中,这个守护进程从来没有超过0.3%的单核cpu使用率,而且只有很少量的内存使用(以及堆碎片的噪音)。我们还限制了Dapper守护进程为内核scheduler最低的优先级,以防在一台高负载的节点上cpu竞争的发生。 Dapper还是一个带宽资源的轻量级的消费者,每一个段在我们的仓库中传输至占用了平均426的byte。作为网络行为中的极小部分,Dapper的数据收集在Google的生产环境中的网络流量只占用了0.01%的网络资源。

4.3对生产环境负载下的影响 利用大量的服务器的高吞吐量的线上服务的请求,是对有效跟踪最多的需求之一;这种情况需要生成大量的跟踪数据,并且他们对性能的影响最最敏感的。在表2中我们用集群下的网络搜索服务作为例子,我们衡量Dapper对性能的影响的延迟和吞吐量,调整了采样率。 我们看到,虽然吞吐量的影响不是很显着,为了避免明显的延迟,跟踪的采样还是必要的。 然而,延迟和吞吐量的带来的损失在把采样率调整到小于1/16之后就全部在实验误差范围内。在实践中,我们发现即便采样率调整到1/1024仍然是有足够量的跟踪数据的用来跟踪大量的服务。保持Dapper的性能损耗基线在一个非常低的水平是很重要的,因为它为那些应用提供了一个宽松的环境使用完整的标注API而无惧的性能损失。使用较低的采样率有额外的好处,可以让持久到硬盘中的跟踪数据在垃圾回收机制处理之前保留更长的时间,这样为Dapper的收集组件给了更多的灵活性。

4.4可变采样 任何给定进程的Dapper的消耗和每个进程单位时间的跟踪的采样率成正比。Dapper的第一个生产版本在Google内部的所有进程上使用统一的采样率,为1/1024。这个简单的方案是对我们的高吞吐量的线上服务来说是非常有用,因为感兴趣的事件仍然很有可能经常出现,并且通常足以被捕捉到。 然而,在较低的采样率和较低的传输负载下可能会导致错过重要事件,而想用较高的采样率就需要能接受的性能损耗。这样的系统的解决方案需要覆盖默认的采样率,这需要手动干预的,这种情况我们试图避免在dapper中出现。 我们在部署可变采样的过程中,参数化配置采样率时,不是使用一个统一的采样方案,而是使用一个采样期望率来标识单位时间内采样的追踪。这样一来,低流量低负载自动提高采样率,而在 高流量高负载的情况下会降低采样率,使损耗一直保持在控制之下。实际使用的采样率会随着跟踪本身记录下来,这有利于从Dapper的跟踪数据中准确的分析。

4.5积极的采样 新的Dapper用户往往觉得低机率--在高吞吐量的服务下经常低至0.01%--将会不利于他们的分析。我们在Google的经验使我们相信,对于高吞吐量服务,积极的调整采样并不妨碍最重要的分析。如果一个显着的操作在系统中出现一次,他就会出现上千次。低吞吐量的服务--也许是每秒请求几十次,而不是几十万--可以负担得起跟踪每一个请求,这是促使我们下决心使用自适应采样率的原因。

4.6在收集过程中额外的采样 上述采样机制被设计为尽量减少与Dapper运行库协作的应用程序中明显的性能损耗。Dapper的团队还需要控制写入**资料库的数据的总规模,因此为达到这个目的,我们结合的第二轮的采样。 目前我们的生产集群每天产生超过1TB的采样跟踪数据。Dapper的用户希望生产环境下的进程的跟踪数据从被记录之后能保存至少两周的时间。逐渐增长的追踪数据的密度的必须和Dapper**仓库所消耗的服务器及硬盘存储进行权衡。对请求的高采样率还带来Dapper收集器令人不快的接近写入吞吐量的上线。 为了维持物质资源的需求和渐增的Bigtable的吞吐之间的灵活性,我们在收集系统自身上增加了额外的采样率的支持。我们充分利用所有段都来自一个特定的跟踪并分享同一个跟踪ID这个事实,虽然这些段有可能横跨了数千个主机。对于在收集系统中的每一个段,我们用hash算法把跟踪ID转成一个标量Z,这里0<=Z<=1。如果Z比我们收集系统中的系数低的话,我们就保留这个段信息,并写入到Bigtable中。反之,我们就抛弃他。通过在采样决策中的跟踪ID,我们要么保存、要么抛弃整个跟踪,而不是处理跟踪内的段。我们发现,这额外的配置参数使管理我们的收集管道变得简单多了,因为我们可以很容易地在配置文件中调整我们的全局写入率这个参数。 如果整个跟踪和收集系统只使用一个采样率参数确实会简单一些,但是这就不能应对快速调整在所有部署的节点上的运行期采样率配置的这个要求。我们选择了运行期采样率,这样就可以优雅的去掉我们无法写入到仓库中的多余数据,我们还可以通过调节收集系统中的第二个采样率系数来调整这个运行期采样率。Dapper的管道维护变得更容易,因为我们可以直接增加或减少我们的全局覆盖率和写入速度,通过修改我们的第二次采样率的配置。

5通用的Dapper工具 几年前,当Dapper还只是个原型的时候,它只有能再Dapper开发者耐心的支持下使用。从那时起,我们已经迭代的建立了收集组件,编程接口,和基于Web的交互式用户界面,帮助Dapper的用户独立解决自己的问题。在本节中,我们会总结一下哪些的方法我们用了,哪些没有,我们还提供关于这些通用的分析工具的基本的使用信息。

5.1Dapper Depot API Dapper的“Depot API”或称作DAPI,提供在Dapper的区域仓库中对分布式跟踪数据一个直接访问。DAPI和Dapper跟踪仓库被设计成串联的,而且DAPI意味着对Dapper仓库中的元数据暴露一个干净和直观的的接口。我们使用了一下推荐的三种方式去暴露这样的接口: 通过跟踪ID来接入:DAPI可以读取任何一个跟踪信息通过他的全局唯一的跟踪ID。 大量访问:DAPI可以利用的MapReduce提供对上亿条Dapper跟踪数据的并行读取。用户重写一个虚拟函数,它接受一个Dapper的跟踪信息作为其唯一的参数,该框架将在用户指定的时间窗口中调用每一次收集到的跟踪信息。 索引访问:Dapper的仓库支持一个符合我们通用调用模板的唯一索引。该索引根据通用请求跟踪特性(commonly-requested trace features)进行绘制来识别Dapper的跟踪信息。因为跟踪ID是根据伪随机的规则创建的,这是最好的办法去访问跟某个服务或主机相关的跟踪数据。

所有这三种访问模式把用户指向不同的Dapper跟踪记录。正如第2.1节所述的,Dapper的由段组成的跟踪数据是用树形结构建模的,因此,跟踪数据的数据结构,也是一个简单的遍历树由段组成。段 通常用RPC调用通信,在这种情况下,RPC的时间信息是可用的。时间戳的应用标注也是可以通过段的结构来访问的。 选择一个合适的自定义索引时DAPI设计中最具挑战性的部分。压缩存储需要一个索引只比实际数据小26%,所以消耗是巨大的。最初,我们部署了两个索引:第一个是主机索引,另一个是服务名的索引。然而,我们对主机索引并没有足够的兴趣,来证明他们的存储消耗。当用户对每一台主机感兴趣的时候,他们也会对特定的服务感兴趣,所以我们最终选择把两者相结合,成为一个综合索引,它允许以服务名称,主机,和时间戳的顺序进行有效的查找。

5.1.1DAPI在Google内部的使用 DAPI在谷歌的使用有三类:使利用DAPI的持续的线上Web应用,维护良好的可以再控制台上调用的基于DAPI的工具,可以被写入、运行不过大部分已经被忘记了的一次性分析工具。我们知道的有3个持久性DAPI的应用程序,8个额外的按需的基于DAPI分析工具,以及使用DAPI框架构建的约15~20一次性的分析工具。在这之后的工具就这是很难说明了,因为开发者可以构建、运行和丢弃这些项目,而不需要Dapper团队的技术支持。

5.2Dapper的用户接口 绝大多数用户使用发生在基于web的用户交互接口。篇幅有限,我们不能列出每一个特点,而只能把典型的用户工作流在图6中展示。 1:用户描述的他们关心的服务和时间,和其他任何他们可以用来区分跟踪模板的信息(比如,段的名称)。他们还可以指定与他们的搜索最相关的成本度量(比如,服务等待时间)。 2:一个性能概要的大表格,对应确定的服务关联的所有分布式处理图表。用户可以把这些执行图标排序成他们想要的,并选择一种图去展现出更多的细节。 3:一旦某个单一的分布式执行部分被选中后,用户能看到关于执行部分的的图形化描述。被选中的服务被高亮展示在该图的中心。 4.在创建那些与分支做通信的部分之后,这些分支是在步骤1中选中的性能度量空间,Dapper的用户界面会提供了一个简单的直方图。在这个例子中,我们可以看到一个大致的所选执行部分的分布式的延迟分布图。用户还会看到一个关于具体的跟踪信息的列表,展现跟踪信息在直方图中被划分为的不同区域。在这个例子中,用户点击在第二个实例跟踪信息,然后用户会看到这个跟踪信息的详细视图。 5.绝大多数Dapper的使用者最终的会检查某个跟踪情况希望能收集一些信息去了解系统行为的根源所在。我们没有足够的空间来做跟踪视图的审查,但我们使用由一个全球性的时间轴(在上方可以看到),并能够 展开和折叠树形结构的交互方式,这也很有特点。分布式跟踪树的连续层用内嵌的不同颜色的矩形表示。每一个RPC的段被从时间上分解为一个服务器进程中的消耗(绿色部分)和在网络上的消耗(蓝色部分)。用户注释不会显示在这个截图中,但他们可以选择性地一段接一段的包括在全局时间轴上。 为了让用户查询实时数据,Dapper的用户界面能够直接与Dapper每一台生产环境下的服务器上的守护进程进行交互。在该模式下,不可能指望能看到上面所说的系统级的图表展示,但仍然可以很容易选择一个单独的跟踪基于性能和网络相关的信息。在这种模式下的操作,可在几秒钟内查到实时的数据。 根据我们的记录,大约有200个不同的Google工程师在一天内使用的Dapper的UI;在一周的过程中,大约有750-1000不同的用户。这些数字每个月都是连续的(from month to month modulo internal announcements of new featurres)。通常用户会发送特定跟踪的连接,这将不可避免地在跟踪检查中产生很多一次性的,持续时间较短的交互。

6经验 Dapper在Google被广泛应用,一部分直接通过Dapper的用户界面,另一部分间接地通过对DapperAPI的二次开发或者建立在使用这些api的应用上。在本节中,我们并不打算罗列出每一种已知的Dapper使用方式,而是试图覆盖Dapper使用方式的“basisi vector”,并努力来说明什么样的应用是最成功的。

6.1在开发中使用Dapper 谷歌AdWords系统是围绕一个大型的关键词定位准则和相关文字广告的数据库搭建的。当新的关键字或广告被插入或修改时,它们必须通过服务策略术语的检查(如检查不恰当的语言),这个过程如果使用自动复查系统来做的话会更加有效。 当轮到重新从头设计一个广告审查服务时,这个团队使用Dapper迭代的从第一个系统原型开始,并且,最终一直维护着他们的系统。Dapper帮助他们从以下几个方面改进了他们的服务: 性能:开发人员跟踪的过程针对请求延迟的目标和定位易优化的机会。Dapper也被用来确定在关键路径上不必要的串行请求--通常来源于不是开发者自己开发的子系统--并促使团队持续修复他们。 正确性:广告审查服务围绕大型数据库系统搭建。系统同时具有只读副本策略(数据访问廉价)和读写的主策略(访问代价高)。Dapper被用来在很多种情况中确定,哪些查询是无需通过主策略访问而可以采用副本策略访问。它现在可说明哪些主策略被直接访问,并保障重要的系统不变量。 理解性:广告审查查询跨越了各种类型的系统,包括BigTable,上述的数据库,多维索引服务,以及其他各种C++和Java后端服务。Dapper的跟踪用来评估总查询成本,对促进重新对业务的设计,用以在他们的系统依赖上减少负载。 测试:新的代码版本会经过一个Dapper跟踪的QA过程,用来验证正确的系统行为和性能。许多问题会在这个过程中被发现,无论是广告审查系统自身的代码或是他的依赖包。 广告审查团队在Dapper标注API上进行了广泛的使用。Guice[13]开源的AOP框架用来在重要的软件组件 上标注“@Traced”。这些跟踪信息可以进一步被标注,包含:重要子路径的输入输出大小、基础信息、其他调试信息,所有这些信息将会额外发送到日志文件中。 同时,我们也发现了一些广告审查小组在使用方面的不足。比如:他们想对他们所有的跟踪标注在交互时间上进行搜索,然而这就必须跑一个自定义的MapReduce或进行每一个跟踪的手动检查。另外,在Google还有一些其他的系统在谷歌从通用调试日志中收集和集中信息,把那些系统的海量数据和Dapper仓库整合也是有价值的。 总的来说,虽然广告审查团队评估,通过使用Dapper的跟踪平台的数据分析,他们的服务延迟性已经优化了两个数量级。

6.1.1与异常监控的集成 Google维护了一个从运行进程中不断收集并集中异常信息报告的服务。如果这些发上在Dapper跟踪采样的上下文中的话样,相应的跟踪和段的ID也会作为元数据记录在异常报告中。异常监测服务的前段,会提供一个从特定的异常信息的报告到他们各自的分布式跟踪的链接。广告审查团队使用这个功能可以了解更大氛围的bug上下文。通过暴露基于简单的唯一ID构件接口,Dapper平台被集成到其他事件监测系统会相对容易。

5.2解决延迟的长尾效应 由于大量的移动部件、代码库的量、部署的范围,调试一个像全文搜索那样服务(第一节里提到过)是非常 具有挑战性的。在这节,我们描述了我们在减轻全文搜索的延迟分布的长尾效应上做的各种努力。Dapper能够验证端到端的延迟的假设,更具体地说,对于搜索请求的关键路径。当一个系统不仅涉及数个子系统而是几十个开发团队的情况下,即使是我们最好的和最有经验的工程师也经常判断错误了端到端性能较差的根本原因到底在哪。在这种情况下,Dapper可以提供急需的数据,而且可以对许多重要的性能问题得到得出结论。 调试长尾延迟的工程师可以建立一个小型库,根据DAPI跟踪对象来推断关键路径的层级结构。这些关键路径的结构可以被用来诊断问题,并且为全文搜索提供可优先处理的预期的性能改进。Dapper的这项工作导致了下列发现: *在关键路径上的短暂的网络性能退化不影响系统的吞吐量,但它可能会对延迟异常值产生极大的影响。在图7中可以看出,大部分的全局搜索的缓慢的跟踪都来源于关键路径的网络性能退化。 *许多问题和代价很高的查询模式来源于一些意想不到的服务之间的交互。一旦发现,往往容易纠正它们,但是Dapper出现之前想找出这些问题是相当困难的。 *通用的查询从Dapper之外的安全日志仓库中收取,并使用Dapper唯一的跟踪ID,加入与Dapper的仓库。然后,该映射用来建立关于这个实例查询在全局搜索中通过每一个子系统时表现缓慢的列表。

6.3推断服务依赖 在任何给定的时间内,Google内部的一个典型的计算集群是一个汇集了成千上万个逻辑“jobs”的主机,许许多多的处理器在执行一个共同的方法。Google维护着许多这样的集群,当然,事实上,我们发现在一个集群上计算着的这些jobs通常依赖于其他的集群。由于jobs之间的依赖是动态改变的,所以不可能仅从配置信息上推断出所有这些服务之间的依赖。不过,除了其他方面的原因之外,在公司内部的各个流程需要准确的服务依赖关系信息,以确定瓶颈所在,以及计划服务的迁移。Google的名为“Service Dependencies”的项目是通过使用跟踪标注和DAPI MapReduce接口来实现自动化服务的依赖归属的。 Dapper核心组件与Dapper跟踪标注一起使用,“Service Dependencies”项目能够推到出Job各自之间的依赖,以及job和其他软件组件之间的依赖。比如,所有的Bigtable的操作会加上与受影响的表名称相关的标记。运用Dapper的平台,Service Dependencies团队就可以自动的推导出依赖于命名的不同资源的服务粒度。

6.4不同服务的网络使用 Google投入了大量的人力和物力资源在他的网络结构伤。毫不奇怪,网络管理员早已将监测信息的访问从各部分的的硬件因袭、自定义工具及仪表盘上的信息建立一个鸟瞰全局的的网络利用率。网络管理员确实可以一览整个网络的健康状况,但是,当遇到问题时,他们很少有可以正确地查找网络负载的工具,可以定位应用程序级别的罪魁祸首。 虽然Dapper不是设计用于链路级监测,但是我们已经发现,它是非常适合去做集群之间网络活动性的应用级任务的分析任务。Google能够利用Dapper这个平台,建立一个不断更新的控制台显示集群之间最活跃​的网络流量的应用程序级别的端点。此外,使用Dapper我们能够为昂贵的网络请求指出的构成原因的跟踪跟踪,而不是限制自己在两个对等的隔离的机器。建立一个基于Dapper API的仪表盘总共不用花超过2周的时间。 6.5分层和共享存储系统 在Google的许多存储系统是由多重独立复杂的层的分布的基础设备组成的。例如,Google的App Engine[5]就是搭建在一个可扩展的实体存储系统上的。该实体存储系统在基于BigTable上公开某些RDBMS功能。 Bigtable的同时使用Chubby[7](分布式锁系统)及GFS。再者,像BigTable这样的系统简化了部署,并更好的利用了计算资源。 在这种分层的系统,并不总是很容易确定最终用户资源的消费模式。例如,来自于一个给定的BigTable单元格的GFS通信量的高度可能产生自主要的一个用户或多个用户,但是在GFS层面,这两种明显的使用场景是很难界定的。而且,对共享服务的竞争可能会同样难于调试,如果缺乏一个像Dapper一样的工具的情况下。 第5.2节中所示的Dapperd的用户界面可以聚合那些调用任意公共服务的多个客户端的跟踪性能信息。这很容易让提供这些服务的源从多个维度给他们的用户排名。(例如,入站的网络负载,出站的网络负载,或服务请求的总时间)

6.6Dapper的灭火功能 Dapper对一些但不是所有灭火任务管用。灭火任务在这里是指一些有一定风险的在分布式系统上的操作。通常情况下,Dapper用户当正在进行灭火任务时需要使用新的数据,并且没有时间写新的DAPI代码或等待周期性的报告运行。 对于那些高延迟,或者更糟糕,在正常负载下都会超时的服务,Dapper用户界面通常会隔离这些延迟瓶颈的位置。通过与Dapper守护进程的直接通信,那些特定的高延迟的跟踪数据可以毫无困难地收集。当出现灾难性故障时,通常是没有必要去看统计数据以确定根本原因,只查看示例跟踪就足够了。 但是,共享的存储服务如所描述在6.5节,要求当用户活动过程中突然中断尽可能快的快汇总信息。对于事件发生之后,共享服务仍然可以利用汇总的的Dapper数据,但直到关于收集到的Dapper数据的大量分析在事发10分钟内完成,否则Dapper都能发挥它本可能发挥的那么大的作用,针对与共享存储服务相关的灭火问题。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.