从跟踪中获得更多价值的简单方法很多人似乎认为分布式跟踪没有用处,或者至少在没有极端努力的情况下是没有用的,这对小于FB的公司来说是不值得的。例如,这里有几个公共对话,听起来像是我进行过的一些私人对话。当然,在某个地方有价值,但解锁的费用太高了。
我认为这高估了从跟踪中获得大量价值的工作量。在Twitter,丽贝卡·艾萨克斯(Rebecca Isaacs)能够为如何从跟踪中获得价值制定愿景,并在此基础上执行(在其他一些人的帮助下,包括乔纳森·西姆斯(Jonathan Simms)、尤里·维什涅夫斯基(Yuri Vishnevsky)、鲁本·奥塔(Ruben Oanta)、戴夫·鲁塞克(Dave Rusek)、哈姆迪·阿拉姆(Hamdi Allam)和其他许多人1),这样工作就很容易。这篇文章将描述我们构建的跟踪基础设施,并描述我们发现它很有价值的一些用例。在我们谈到这一点之前,让我们先来了解一下丽贝卡的愿景实现之前的一些背景情况。
在更高的层面上,我们可以说我们有一个面向跟踪视图的系统,并遇到了人们可能预期会出现的所有问题。辛迪·斯里德哈兰(Cindy Sridharan)在本文中更详细地讨论了这些问题。不过,我想更详细地讨论一下我们之间的具体问题,因为我认为看看是什么具体的事情造成了问题是很有用的。
综上所述,这些问题足够有问题,以至于追踪公司多年来一直处于拥有不足的状态,甚至可以说是无人拥有的。一些人确实在业余时间工作,以保持照明或改进事情,但缺乏明显的跟踪价值导致了恶性循环,从跟踪中获得价值的高门槛使其难以在组织上获得资金,这使得跟踪很难变得更有用。
架构实际上是一组踪迹,其中每个踪迹是一组跨度,每个跨度是一组注释。每个不是根跨度的跨度都有一个指向其父跨度的指针,这样就可以确定轨迹的图形结构。
出于本文的目的,我们可以将每个跟踪视为包含所有子RPC的外部请求或请求的子集,它们位于下游,而不是位于请求的顶部。我们还会跟踪一些不需要的东西,比如构建和GIT操作,但为了简单起见,我们将在本文中忽略这些内容,尽管我们将讨论的技术也适用于这些内容。
每个跨度对应于一个RPC,并且每个注释是开发者选择记录在跨度上的数据(例如,RPC有效载荷的大小、跨度时系统中各种队列的队列深度,或者中断RPC的GC暂停的GC暂停时间)。
具有一组(袋子)模式产生的一些问题包括:
执行任何使用轨迹中固有的图表结构信息的查询都需要读取轨迹中的每个跨度并重新构建图表。
因为没有每个跟踪信息的索引或汇总信息,所以对跟踪的任何查询都需要读取跟踪中的每个跨度。
实际上,由于以上两项在查询时以特殊方式执行成本太高,所以人们运行的唯一查询是";的某个变体,给了我几个与简单过滤器";匹配的范围。
直到大约一年半以前,唯一受支持的查看跟踪的方式是转到UI,从组合搜索框+下拉菜单中按服务名称进行筛选,然后查看最近跟踪的列表,您可以在其中单击任何跟踪以获得跟踪视图。每次搜索返回N个最新结果,它不一定代表所有最新结果(出于下面采样部分提到的原因),更不用说代表任何其他时间跨度内的所有结果了。
根据上面在模式部分中讨论的问题,由于在非平凡数量的跟踪上运行查询的成本太高,因此不可能提出这样的问题:我正在查看的任何跟踪是否代表常见跟踪,或者我是否正在查看奇怪的边缘情况?向我显示特定尾部事件的跟踪,例如,何时从服务A到服务B的请求超时,或者何时从服务A到某个后台数据库的写入放大是>;3x"。只向我显示完整的轨迹,即我们没有从轨迹中丢弃跨度的轨迹。
此外,如果您单击的跟踪太大,查询将超时,您将无法查看跟踪--这是缺少任何类型的速率限制逻辑和模式的另一个常见副作用。
有多个地方做出了是否取样的决定。没有列出所有这些地方的文档,这使得在不审核所有代码以找出抽样决策是在哪里做出的情况下,甚至不可能猜测抽样率。
此外,还有多个地方会因为实施而做出无意的抽样决定。跨度从启用了跟踪的服务发送到本地代理,然后发送到收集器服务,然后从收集器服务发送到我们的支持数据库。跨度可以在以下几个点中丢弃:在本地代理中;在收集器中,它会使节点定期崩溃并丢失其所有数据;以及在备份数据库中,它通常会因为热键或高负载而拒绝写入。
在这种设计中,跟踪ID是数据库键,没有中间逻辑来控制写入,这意味着1M跨度跟踪(我们有)将在几秒钟的时间内导致对同一键的1M次写入。另一个问题是数以千计的请求扇出(这在我工作过的每一家科技公司都存在),这可能会在几毫秒内导致数千次使用同一密钥的写入。
另一个抽样问题是,为了避免遗漏不是从内部前端开始的痕迹,在每个RPC中都有导致独立抽样决定的逻辑。如果您在这方面做了计算,如果您有一个像我们这样的面向服务的体系结构,并且您的采样速度听起来可能相当低,比如,您的绝大多数跨度最终将从叶RPC开始,从而导致单跨度跟踪。在非叶RPC中,绝大多数将从叶开始的第二级开始,依此类推。我们的绝大多数负载和存储成本都来自于这些从树叶开始或靠近树叶的几乎无用的痕迹,如果你想要跨跨度进行任何类型的分析以了解整个系统的行为,除了考虑所有其他独立的抽样决策之外,你还必须考虑这种抽样偏差。
没有对时钟偏差进行任何形式的调整(确实有一些调整,但它试图进行局部成对调整,这并没有真正改善情况)。
如果您只是天真地计算了一个跨度所需的时间,即使使用来自单个主机的时钟,您也会得到很多负的持续时间跨度,这当然是不可能的,因为在创建对结果的请求之前不会返回结果。如果你比较不同主机的时间,结果会更糟。
这些问题的解决方案可以归入我认为的两个方面。对于由于收集器节点失效或备份数据库丢失请求而导致的跨度下降等问题,有一些简单的工程解决方案,这些解决方案使用了非常容易理解和广泛使用的技术。对于这对特定的问题,短期的解决办法是进行一些GC调优,将收集器节点的失败率降低约100倍。这总共花了两分钟,然后我们用一个真正的队列替换了收集器节点,该队列可以吸收更大的流量突发,并减慢写入数据库的速度。对于由于在每个RPC上滚动采样骰子而对叶级跨度进行过采样的问题,这基本上是一个面试级问题,有许多解决方案,例如,由于每个跨度都有父指针,我们必须能够知道RPC在相关位置是否有父级,我们可以做出采样决策,并在跨度没有父指针的情况下创建traceID。
另一个目标是构建数据集和工具(并添加注释),以允许用户回答他们可能有的问题。这并不是一个新想法,2010年发表的达珀论文的第5节。
当然,一个主要的不同之处在于,Google在Dapper上构建工具的努力可能比我们在我们的跟踪基础上构建工具上投入的工作多了大约两个数量级,所以我们的很多工具都要粗糙得多,例如,Dapper论文中的图6显示了一个跟踪视图,它显示了一组相关的直方图,这使得跟踪的上下文很容易理解,我们还没有为此做过UI工作,所以类似的视图需要运行一个简单的视图,它显示了一组相关的直方图,这使得我们很容易理解跟踪的上下文,我们还没有为此做过UI工作,所以类似的视图需要运行一个简单的。
在已经完成的工作中,我们所做的最简单、显然是高ROI的事情就是构建一组包含人们可能想要查询的信息的表,这些表的结构使得本质上不需要做大量工作的常见查询不必做很多工作。
TRACE_INDEX高级跟踪级别信息,例如,跟踪是否有根;根是什么;如果相关,命中了哪个请求端点,等等。
人们经常想要查询的ANNO_INDEX&34;标准注释,例如,请求和响应有效负载大小、客户端/服务器发送/接收时间戳等。
每个轨迹的TRACE_GRAPH包含轨迹的图形表示,用于需要图形结构的查询。
仅拥有这组可用SQL查询进行查询的表(或者在Presto SQL不理想的情况下,比如执行某些图形查询时,使用一个烫伤或Spark作业),就足以让跟踪为自己买单,从您可能会因为它会导致数据库性能下降而关闭的功能,转变为具有很高价值的功能。
对于负载较高的此服务,请显示哪个上游服务导致负载。
给我所有对下游服务具有异常写入放大的服务列表X是来自特定服务还是针对特定端点的流量导致异常写入放大?例如,在某些情况下,我们看到来自B&>C的总写入放大没有什么异常,但是当A调用B时,我们看到来自B-&>C的非常高的放大。
显示针对各种请求我们在服务上花费的时间与实际工作的时间。
对于由移动客户端检测确定的具有高延迟的请求,向我展示在后端发生了什么
向我展示此请求的延迟关键路径集(使用我们目前拥有的注释,这有许多问题可能值得他们自己发布)。
显示此服务所依赖的服务的CDF这是一个分布,因为一个特定的服务是否调用另一个服务取决于数据;一个服务平均每1000个调用才调用另一个服务的情况并不少见。
我们已经构建并正在构建其他工具,但是仅仅是能够轻松地对跟踪数据运行查询和聚合,就足以支付我们想要做的所有其他工作。这类似于我们在查看度量数据时所看到的,获取我们已经拥有的数据,并以一种允许人们立即运行任意查询的方式将其公开,这会带来好处。对跟踪这样做不如对度量那样直接,因为数据更丰富,但这并不是一个根本不同的想法。
我认为,除了原始数据之外,有其他东西可供查看对于跟踪也比对度量更重要,因为度量相当于跟踪的原始跟踪视图、度量的仪表板视图(您只需查看图表),这显然是非常直观的。如果这就是你所有的指标,人们不会说这不值得为你的指标投资,因为仪表盘真的很有用!然而,很难看到如何从原始的跟踪视图中获得价值,这就是许多关于跟踪没有价值的评论的来源。度量数据和跟踪数据的复杂性之间的这种差异使得跟踪的更高级别视图的附加值大于度量的附加值。
让我们的数据采用的格式不仅仅是NoSQL DB中的BLOB,还允许我们更容易地在跟踪数据之上构建工具,让不想运行SQL查询的用户从我们的跟踪数据中获得价值。服务依赖项浏览器(Service Dependency Explorer,SDE)就是一个例子,它主要由Yuri Vishnevsky、Rebecca Isaacs和Jonathan Simms在陈一宏的帮助下构建。如果我们尝试查看单个请求的RPC调用图,我们会得到相当大的内容。在某些情况下,调用树的深度可能有数百个级别,并且在某些级别看到20个或更多扇出的情况也并不少见,这使得天真的可视化很难解释。
为了了解SDE是如何工作的,让我们看一个较小的例子,在这个例子中,它相对容易理解正在发生的事情。假设我们有8个服务,A到H,它们彼此调用,如下图所示,我们有服务A调用了10次,服务B总共调用了10次,服务B分别调用了D、D和E 50、20和10次,其中这两个D的区别在于它们是不同的RPC端点(调用),尽管它们是相同的服务,依此类推,如下所示:
如果我们从节点E的角度看SDE,我们将看到以下内容:
我们可以看到直接呼叫者和被呼叫者,E的100%调用来自C,E的100%调用也调用C,我们在调用C(200/10=20)时有20倍的负载放大,这与我们在上面的RPC树中看到的是一样的。如果我们看一下间接被调用者,我们可以看到D有4倍的负载放大(40/10=4)。
如果我们想要查看E下游的C直接调用了什么,我们可以选择它,然后我们将获得指向C的直接后代的箭头,在本例中是E的每个间接被调用者。
对于更复杂的示例,我们可以查看服务D,它在上图的原始树中显示为橙色。
我们在树中看到D三次的事实在摘要框中显示,其中显示我们有3条从前端到D的唯一调用路径,即TFE到D。
我们可以将呼叫展开到D,在本例中,我们可以看到这两个呼叫以及每个呼叫所占流量的比例。
如果我们单击其中一个调用,我们可以看到哪些节点是特定调用的上行和下行依赖关系,Call4如下所示,我们可以看到它从未到达服务C、H和G下游,即使服务D对Call3这样做。类似地,我们可以看到它的上游依赖项由C直接调用,B和E间接调用,而不是A和C调用:
服务或RPC调用在出现异常负载放大的情况下会导致什么负载,无论服务是否普遍如此,或者它是否仅发生在某些调用路径上。
这些都是用户可以从查询我们存储的数据中获得的,但拥有一个带有UI的工具,可以让您实时单击以探索事物,这降低了找到这些东西的障碍。
在上面所示的示例中,服务数量很少,因此您可以从更常用的节点海洋视图中获得类似的信息,在该视图中,每个节点都是一个服务,并在可视化上添加一些注释,但是当我们查看真实的跟踪时,显示数千个服务和一个全局节点,这使得我们很难看到发生了什么。丽贝卡的一些早期分析使用了这样的视图,但我们发现,你需要大量的隐性知识才能很好地利用这样的视图,这种视图丢弃了更多的信息,并突出了一些事情,这样对于那些恰好没有正确的隐性知识的用户来说,更容易从查看痕迹中获得价值。
虽然我们在这里演示了RPC计数/负载视图,但我们还可以显示其他内容,如延迟、错误、有效负载大小等。
更广泛地说,如果您设置了基本的分布式跟踪,这只是我们在获得的数据基础上构建的一些东西的简要描述。您可能不想做我们已经做过的事情,因为您可能有一些不同的问题,而且您不太可能遇到下面跟踪到的确切问题集。从与其他公司员工的秘密渠道聊天中,我认为我们遇到的问题并不是独一无二的;如果说有什么不同的话,那就是我们的跟踪基础设施比许多或大多数同行公司(不包括FB/谷歌/亚马逊等巨头)处于更好的状态,因为它基本上是有效的,而且人们可以而且确实使用我们必须调试实际生产问题的跟踪视图。但是,正如他们所说,不快乐的系统也会以自己的方式不快乐。
就像我们之前介绍的指标分析一样,这项工作是逐步完成的。由于跟踪数据比度量数据丰富得多,在编写生成本文中提到的表格的烫手(MapReduce)作业之前,我们花了更多的时间对数据进行临时分析,但个别分析非常有价值,以至于在最初几周清理一些最糟糕的数据质量问题并使用现有基础设施运行(极其痛苦的)临时分析之后,这组项目并没有真正收回成本。
回过头来看关于跟踪基础设施是否有意义的讨论,人们经常指出不同公司在证明购买(而不是构建)决定的合理性方面存在大量失败。我不认为这完全是不合理的,类似项目的基本失败率不应该被忽视。但是,另一方面,所描述的大部分工作并不是特别棘手,除了获得组织的认可和对tracig所能带来的价值有一个清晰的了解之外。
有一件事有点超出了这篇文章的范围,可能值得单独发表,那就是,跟踪和度量虽然不是完全正交的,但它们是互补的,只有其中之一会让你对许多问题视而不见。您将以各种方式为此付出高昂的代价:不必要的事件、花在调试事件上的额外时间、由于运行效率低下而导致的通常较高的金钱成本等等。此外,虽然度量和跟踪单独为您提供了比单独使用其中任何一个更好的可见性,但有些问题需要同时考虑两者;我做过的一些最有趣的分析涉及(通常使用文字SQL连接)跟踪数据和度量数据的连接。指标和跟踪数据应该以允许它们连接的形式提供。
9请注意,这份相对较长的贡献者名单并不与这项高ROI的工作相矛盾。我估计,在这篇文章中讨论的每一件事情上,只有不到2个人的年的工作量。例如,虽然我花了相当多的时间做使用跟踪基础设施的分析,但我想我在基础设施本身上只花了大约一周的时间。
如果上面的内容不明显,即使我在写这篇文章,我也是一个相当小的贡献者。我之所以把它写下来,是因为我坐在丽贝卡旁边,当时正在做这项工作,她的过程和结果给我留下了超级深刻的印象。
几乎可以肯定,这将是一份不完整的名单,但其他一些人也加入了进来,其中包括摩西,
..