购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第2章
可观测性和监控之间的调试实践有何不同

在上一章中,我们讨论了通过指标数据类型来进行调试的起源和常见用途。在本章中,我们将更仔细地研究与传统监控工具相关的具体调试实践,以及这些实践和与可观测性工具相关的调试实践有何不同。

传统的监控工具通过对照已知阈值检测系统条件来工作,这些阈值将提示是否存在已知设定条件的错误。这是一种非常被动的方式,因为只能发现已知可能出现问题的错误。

相反,可观测性工具的工作原理是通过迭代探索性调查来系统地确定性能问题可能发生的位置和原因。可观测性使我们能够主动识别任何故障模式,无论是之前已知的还是未知的。

本章将重点了解基于监控的故障问题分析的局限性。首先,我们介绍如何通过监控工具分析生产环境中软件的性能问题。然后,我们检查这些基于监控方法的制度化的行为。最后,我们展示可观测性实践如何使团队能够识别先前已知和未知的问题。

2.1 监控数据如何用于调试

《牛津英语词典》将监控定义为在一段时间内观察和检测(某物)的进展或质量,并且保持系统持续监测。传统的监控系统只是通过分析指标来做到这一点:根据指标在时间上的变化趋势来分析应用程序的性能,然后报告一定时间间隔内性能的汇总指标。监控系统收集、汇总和分析指标,以筛选分析已知的各种情况,从而判断是否发生了一些令人不安的趋势变化。

这种监控数据有两个主要消费者:机器和人类。机器使用监控数据来决定检测到的情况是应该触发告警还是应该提示故障恢复。指标是以一定时间间隔记录的系统状态的具体数值表示。与查看物理仪表一样,我们或许可以通过分析一个指标,来查看特定资源在特定时刻是否被过度利用或未充分利用。例如,CPU利用率目前可能达到90%。

但是这种行为会改变吗?仪表上显示的数值是上升还是下降?指标在判断系统的总体状态方面是有用的。通过了解指标随时间推移的趋势值,可以深入了解影响软件性能的系统行为。监控系统收集、汇总和分析指标,以筛选已知的模式,而人们总是通过指标的趋势来判断这些问题是否出现。

如果在接下来的两分钟内CPU利用率继续保持在90%以上,那么很多人希望收到这种情况的报警。显而易见的是,对机器来说,指标拥有的只是一个数值。通过指标判断系统状态,检测结果永远是二元的。在不满足条件的间隔和相关的数值下,机器不会触发报警。在大于某个间隔和相关的数值时,机器将触发报警。这个阈值到底是多少由人来决定。

当监控系统检测到人类认为重要的趋势时,会发送报警。同样,如果在预先配置的时间跨度内CPU利用率降至90%以下,监控系统将认为触发报警的错误条件不再适用,通常会通知系统已经恢复。这是一个非常基本的系统,也是我们常用的排查故障的方法。

在这种模式下,人们一般非常默契地用同一种方式来调试故障。这些指标数据会被记录到时序数据库(TSDB),通过一个图形系统来展示执行指标数据的趋势图表。通过各种各样的图表的组合来表示各种复杂的指标数据,我们把这些组合称为仪表盘。

我们通常为每一个系统服务设置一个静态的仪表盘,工程师常通过这些仪表盘来了解各种系统的运作状态。这是构建仪表盘的初衷:概述一组指标如何追踪并显示值得注意的趋势。但是,对于发现调试时新出现的问题,仪表盘是一种糟糕的选择。

当第一次构建仪表盘时,我们并不一定清楚哪些系统指标需要关注。因此,构建一个仪表盘来显示任何给定服务的关键指标是相对容易的。如今,存储成本相对便宜,数据处理能力非常强大,我们能收集到的这些关于系统的数据几乎是无限的。现代服务通常会收集非常多的指标,以至于不可能将它们全部放入同一个仪表盘中。然而,这并没有阻止许多工程团队尝试将所有这些都纳入一个单一的视图。毕竟,这是仪表盘的承诺!

为了让所有内容都适合仪表盘,我们通常会汇总指标并计算其平均值。这些汇总值可能会传达特定的信息——例如,集群的CPU平均值高于90%。但是,这些汇总的数值并不能告诉我们更多的信息,让我们了解在相应的系统中发生了什么——它们不会告诉你是哪些过程导致了这种状况。为了缓解这个问题,一些供应商在他们的仪表盘界面上增加了“过滤器”和“下钻”,让你可以更深入探索并缩小可视化,以提供更多分析故障的能力。

但是,当你使用仪表盘进行故障分析时,会天然受制于你根据各种条件预设的这些仪表盘。在此之前,你需要基于一组特定的维度进行分解。这必须提前完成,以便仪表盘工具可以为这些列创建相应的索引,从而满足你的分析需求。这种索引还受高基数数组的严格限制。如果你使用的是这种基于指标的工具,那么就不可能通过多个图表加载具有高基数数据的仪表盘。

用户需要完成这种基于数据来设定相关仪表盘的任务。在整个故障排查过程中,任何发现系统出现新的系统状态的努力都受到了开始故障排查之前各种设定的限制。例如,在故障排查过程中,你可能会发现对主机实例类型分组统计CPU利用率更有效。但你也许不能这样做,因为你没有提前添加必要的标签。

在这方面,使用指标来确定系统当前状态一直是一种被动方法。然而,总体上看,尽管有诸多限制,软件行业似乎已经习惯于依赖仪表盘进行故障排查。这主要是由于多年来行业内一直认为指标是最佳的故障排查工具。因为我们已经习惯了这种默认的故障方式,所以并没有在意这种方式是否可以真正定位故障。

2.1.1 使用仪表盘时的故障排查行为

负责管理生产服务的运维工程师应熟悉以下场景。如果你是这样的工程师,来看看你是否也在工作环境中预先设定了这些假设。如果你不是在生产环境中进行运维的工程师,那么请分析一下以下场景,以了解前文描述的限制类型。

这是新的一天的早晨,工作日才刚刚开始。你走到办公桌前,首先要做的事情之一就是浏览一组准备好的仪表盘。你希望的仪表盘系统是一个大屏,通过它可以快速地看到应用程序系统的各个方面、它的各种组件以及它们的健康状态。还有一些高阶的仪表盘来展示一些重要的业务指标——你可以看到你想看到的,例如,你的应用程序是否创造了新的流量记录?你的应用程序是否不在App Store的排行榜上了?以及各种各样需要关注的重要情况。

你瞥一眼这些仪表盘,寻找熟悉的情况,让自己放心,你的一天就这样开始了,没有任何需要“紧急救火”的状况。仪表盘展示了一些图表,你其实不知道这些图表实际上显示了什么。然而,随着时间的推移,你深信这些图表提供给你的预测能力。例如,如果屏幕底部的图表变成红色,你就应该放下手头的工作,在情况变得更糟之前立即开始诊断。

也许你不知道所有图表实际测量的是什么,但它们相当可靠地帮助你预测在你非常熟悉的生产服务中发生的问题。当曲线图转向某一特定方向时,你几乎获得了一种特异的预测能力。如果顶部图形的左上角下降,而右下角图形稳定增长,则是消息队列存在问题。如果中间的直方图每隔五分钟出现一次峰值,并且背景比正常情况下红了几个饱和度,那么数据库查询就出问题了。

就在这时,当你浏览一个具体的图表时,你注意到缓存层存在一个问题。仪表盘上没有任何东西清楚地显示“你的主要缓存服务器正在走向出现故障的边缘”。但是,你已经非常了解你的系统,通过破译屏幕上的各种显示,你可以立即采取行动,做一些通过可用数据根本无法清楚说明的事情。你以前见过这种模式的问题,根据上一次故障的经验,你知道这种特定的指标组合说明缓存存在问题。

看到这种情况,你快速打开系统的缓存组件的仪表盘,以确认你的怀疑。你的怀疑被证实了,然后你马上解决了问题。类似地,你可能在脑中记录了多种发现问题的模式组合。随着时间的推移,你学会了通过阅读特定生产环境中服务的各种细微的模式来预测问题的来源。

2.1.2 通过直觉进行故障排查的局限性

许多工程师都非常熟悉这种故障排查方法。问问自己,在整个排查问题的过程中,在你跳转于系统的各种组件时,你依赖了多少直觉?通常,作为一个行业,我们重视这种直觉,多年来它给我们带来了很多好处。现在问问你自己:如果使用同样的仪表盘工具,但面对的是完全不同的应用程序,用不同的语言编写,使用不同的架构,你能猜到同样的答案吗?当左下角变成蓝色时,你是否知道自己应该做什么,或者是否有必要采取行动?

显然,这个问题的答案是否定的。通过仪表盘看到的各种系统问题在不同的应用程序堆栈中是非常不同的。然而,在行业里,这是我们与系统交互的主要方式。从历史上看,工程师一直依赖于静态的仪表盘,这些仪表盘上密集分布着数据,当出现问题时,工程师通常通过一到两个图表中数据的差异进行判断。但当我们发现新的问题时,我们开始看到使用它们的局限性。让我们看看下面的几个例子。

例1:相关性不足

工程师添加了一个数据库索引,并且想知道是否实现了更快的查询速度。他们还想知道是否发生了其他意想不到的结果。他们可能会问以下问题:

・ 一个特定查询(已知是一个痛点)扫描的行比以前少吗?

・ 查询规划器选择新索引的频率是多少,用于哪些查询?

・ 写延迟是整体上升、平均上升,还是第95或99百分位数上升?

・ 与之前的查询规划相比,使用这个索引的查询速度更快还是更慢?

・ 与新索引一起使用的还有哪些其他索引(假设索引交叉)?

・ 这个索引是否使其他索引过时,使得我们可以删除那些索引并回收一些存储容量?

这只是一些示例问题,他们可以问更多的问题。但是,一般情况下他们提供了一个仪表盘和相应的图表,用于显示平均CPU负载、内存使用情况、索引计数器以及主机和运行数据库的许多其他内部统计数据。它们不能按用户、查询、目标或源IP,或者任何类似的东西进行分割或分解。他们所能做的就是基于时间戳仔细观察这些大范围的变化,并冒险进行复杂的猜测。

例2:不深入

工程师发现了一个无意中导致数据过期的bug,并想知道它是影响了所有用户还是只影响了一部分分片。相反,他们在仪表盘中能够看到的是磁盘空间以可疑的速度下降……就在一个数据分片上。他们迅速地假设这个问题仅限于那个分片,然后继续,而没有意识到由于进行了同步导入操作,磁盘空间似乎在另一个分片上保持稳定。

例3:在工具间跳跃

工程师会在特定的时间看到错误的高峰。他们开始在仪表盘上翻页,同时寻找其他指标中的峰值,他们找到了一些,但无法分辨哪些是错误的原因,哪些造成了影响。所以跳转到日志工具,并开始查找错误。一旦找到错误的请求ID,就会转向链路工具,并将错误ID复制粘贴到链路工具中。(如果这个请求没有被追踪,他们就会一遍又一遍地重复,直至捕获到一个被追踪的请求。)

随着时间的推移,这些监控工具可以更好地检测更细粒度的问题——如果你有一个健壮的传统,总是在宕机后进行复盘,并为下一次判断添加更多的自定义指标。通常情况下,在一次故障发生以后,值班工程师会根据自己的需要添加关注这个故障的指标,并开始追踪这个指标。他们会发布一个变更来创建这个指标,并开始收集它。当然,这其实已经太晚了,你后面添加的变更已经无法改变上一次故障了——你无法回到过去并第二次捕获该自定义指标,除非再遇到一次完全相同的场景——但如果该场景发生了,那么故事会继续,下次你就会确定了。

前面示例中的工程师可能会返回并为每个查询系列、每个集合的到期率、每个分片的错误率等添加自定义指标。(他们可能会发疯,为每个查询族的锁使用情况、每个索引的命中、执行时间的存储桶等都添加自定义指标,然后发现他们需要在监控上花费巨大的成本。)

2.1.3 传统的监控基本上是被动的

前面的方法是完全被动的,但许多团队都接受这种方式——这就是故障排查的简单方法。我们通常发现,这是在用一种遥测的方式玩打地鼠游戏,总是在事后追赶。这也是非常昂贵的,因为参数工具倾向于基于线性扩展的方式去自定义各种指标。许多团队热情地将所有的精力都投入自定义指标中,但是当他们看到所花费的巨额成本时又会考虑优化,并最终选择删除其中的大部分指标。

你的团队也是这样吗?为了帮助确定这一点,当你在一周内维护生产服务时,请注意这些指标:

・ 当生产中出现问题时,你是否根据系统信息的实际可见踪迹来决定你需要在哪里进行诊断?或者你是跟随你的直觉来定位这些问题吗?你是从上次找到答案的地方开始吗?

・ 你是否依赖于你对该系统及其过去问题的专业熟悉程度?当你使用故障排查工具来诊断问题时,你是在探索性地寻找线索吗?还是想证实你的猜测?例如,如果延迟非常慢,而你有几十个数据库和队列都可能会产生延迟,那么你能够使用数据来确定延迟到底来自哪里吗?或者你猜它一定是由你的MySQL数据库造成的,然后去检查你的MySQL图表以确认你的预感?

你有多少次会凭直觉直接找到一个解决方案,然后试图确认它是正确的,并据此进行下去——但实际上却错过了真正的问题,因为这个被确认的假设只是一个症状或一个结果,而不是原因?

・ 你的故障排查工具是否为你的问题提供了精确的答案,并引导你获得了直接的答案?还是需要你基于对系统的熟悉程度来进行翻译,以得到你真正需要的答案?

・ 你有多少次在不同的工具之间跳转,依靠自己在不同的来源之间携带上下文,试图将观察结果给关联起来?

・ 最重要的是,你团队中最厉害的故障排查者总是那个在此工作时间最长的人吗?这是一个致命的问题,你的大部分关于你系统的知识不是来自一个大众化的方法,如某种工具,而是来自某个人的亲身实践经验。

猜测并不总是正确的。相关性不是因果关系。你想了解的具体问题和可用于提供答案的仪表盘之间通常存在巨大的脱节。你不可能有信心单纯通过仪表盘来确定因果关系。

如果预设的逻辑本身就存在一定的局限,那么情况会变得更糟。依赖这样的系统,你无法找到你本就不知道要找的东西。你也不可能知道这些本来你就不知道的情况。

从历史上看,工程师必须将各种数据来源的结果与他们对系统形成的直觉拼接在一起,用来诊断问题。在行业里,我们已经接受这是正常运维行为。但是,随着系统的复杂性不断增加,超出了任何个人或团队能够直观理解各种动态组件的能力,引入超越这种被动和限制性的方法的必要性变得很明显。

2.2 可观测性如何实现更好的调试

正如在上一节中看到的,监控是一种被动的方法,最适合用于检测已知的问题和解决过去遇到过的情况;监控这种方法是以告警和中断的概念为中心的。相反,可观测性让你沿着任何维度或各种组合的维度明确地发现任何问题的来源,而不需要事先预测问题可能发生在哪里,以及问题是如何发生的;这种模式则以提问和理解为中心。

让我们从三个方面来比较检查监控和可观测性之间的差异:依靠惯例知识、发现隐藏的问题,以及有信心诊断生产环境中的问题。我们将在接下来的章节中提供更深入的例子来说明这些差异是如何以及为什么出现的。现在,我们将从理论上对这些差异进行比较。

惯例知识是一个组织中的一些人可能知道但其他人不普遍知道的不成文信息。在基于监控的方法中,团队经常围绕着“资历是知识的关键”这一理念:在团队中工作时间最长的工程师通常是团队中最好的调试人员,也可能是最后可以解决问题的人。如果调试都是依靠个人过去遇到问题的各种经验,那么这种偏好就不足为奇了。

相反,实践可观测性的团队倾向于一个完全不同的方式。使用可观测性工具,团队中最好的调试人员往往变成了最好奇的工程师。实践观测能力的工程师有能力通过询问探索性的问题来询问他们的系统,使用发现的答案来引导他们进行进一步的开放式询问(参见第8章)。可观测性最需要的技能是能够跨越不同系统的诊断能力。

当涉及寻找隐藏在复杂系统深处的问题时,这种转变的影响变得最为明显。基于监控的方法,通过直觉和预感,很容易用错误的认知来掩盖问题的真正来源。当发现问题时,会根据他们的行为模式与先前已知问题的相似程度来诊断。这可能导致在不了解问题的实际根源的情况下来解决具体的问题。工程师猜测可能会发生什么,然后立即确认,缓解症状,但从来没有充分诊断为什么会发生在这一个地方。更糟糕的是,通过引入对症状而不是原因的修复,团队现在将面临两个问题而不是一个问题。

可观测性不是依靠专家的预知,而是允许工程师将每一次诊断视为新诊断。当检测到问题时,即使触发条件似乎与过去的问题相似,工程师也应该通过系统层面上提供的线索,一步一步地进行诊断。你可以通过数据来确定正确的结论——每次,一步一步。这种有条不紊的方法意味着任何工程师都可以诊断任何问题,而不需要非常熟悉你本不可能熟悉的复杂系统,通过直观去猜测并制定出相应的解决方案。此外,这种方法提供的客观性意味着工程师可以找到他们试图解决的具体问题的来源,而不是治疗过去类似问题的症状。

通过转变为使用客观方法进行诊断,有助于提高整个团队诊断生产环境问题的信心。在基于监控的系统中,人们需要从一个工具跳到另一个工具,并将它们之间的相关性联系起来,因为数据是预先汇总的,不支持灵活的探索。如果他们想放大或提出新问题,在从查看仪表盘转到查看日志时,他们必须在脑海中携带上下文。当从查看日志转到查看链路时,他们必须再次这样做,然后再跳转回来。鉴于在处理多个数据和真相来源时遇到的固有的不兼容性和不一致性,这种上下文切换很容易出错,令人筋疲力尽,而且往往是不可能的。例如,如果你负责绘制应用程序遇到的TCP/IP数据包和HTTP错误等单元之间的相关性,或者资源匮乏错误和高内存占用率之间的相关性,那么你的调查可能存在高度的转换错误,因此随机猜测可能同样有效。

可观测性工具将遥测数据中的高基数、高维度上下文拉到一个位置,研究人员可以在该位置轻松地进行分割和分解以放大、缩小或跟随“面包屑”来找到最终答案。工程师应该能够稳定而自信地完成调查,而不受持续语境切换的干扰。此外,通过在一个工具中保持这种上下文,通常结合经验和惯例知识的隐性理解反而成为关于系统的明确数据。可观测性允许关键知识从最有经验的工程师的头脑中转移到共享事实中,任何工程师都可以根据需要进行探索。在本书中,我们将探索可观测性工具的更详细功能,你将看到如何发挥这些优势。

2.3 结论

基于监控的调试方法(使用指标和仪表盘,结合专家知识对生产环境中的问题来源进行分类)是软件行业的一种普遍实践。在数据收集有限的初级应用程序架构之前的时代,考虑到遗留系统的简单性,依靠人类的经验和直觉来检测系统问题的诊断实践是有意义的。然而,现代应用基础系统的复杂性和规模已经迅速使这种方法站不住脚了。

基于可观测性的调试方法提供了一种不同的思路。它们帮助工程师能够研究任何系统,无论多么复杂,而不需要依靠经验或熟悉的系统知识所构建的直觉。有了可观测性工具,工程师可以有条不紊地、客观地研究任何问题。通过以开放的方式询问他们的系统,工程师实践可观测性可以找到深层隐藏问题的来源,并自信地诊断生产环境中的问题,而无须考虑他们之前是否了解过这个系统。

接下来,让我们看一个具体的实践,通过查看过去在没有可观测性的情况下对应用程序进行扩展所获得的经验教训,将这些概念联系在一起。 n4A2ngBRzFtIXoc+fAKez0SDhcwcPxVVy/AcLmKeUw0OLyIAVEh/c3hh3ozEK475

点击中间区域
呼出菜单
上一章
目录
下一章
×