Google 出版了两本关于 SRE(站点可靠性工程)原则、最佳实践和实际应用的书籍1,2。然而,在处理生产事件的紧要关头,团队的实际响应和调试方法通常与理想的最佳实践有所不同。
本文介绍了 2019 年对 Google 工程师如何调试生产问题进行的研究结果,包括工程师在不同组合中使用的工具类型、高层策略和底层任务,以有效地进行调试。本文探讨了用于捕获数据的研究方法,总结了生产调查的常见工程流程,并分享了专家如何调试复杂分布式系统的示例。最后,本文将此研究的 Google 特性扩展到提供一些您可以在组织中应用的实用策略。
本研究开始时,其重点是发展对调试过程的实证理解,总体目标是创建满足 Google 工程师需求的最优产品解决方案。我们希望捕获工程师在调试时需要的数据、他们需要数据的时间、相关团队之间的沟通流程,以及成功的缓解措施类型。假设是,工程师在调试生产事件时试图回答的问题类型以及他们应用的缓解策略存在共性。
为此,我们分析了过去一年的事后分析结果,并提取了每次事件的缓解时间、根本原因和相关的缓解措施。然后,我们选择了 20 起近期事件进行定性用户研究。这种方法使我们能够理解和评估工程师在真实环境中的流程和实践,并深入研究用户行为和模式,而这些行为和模式无法通过分析事后分析文档中的趋势来提取。
第一步是尝试理解用户行为:在最高层面,Google 的端到端调试体验是什么样的?该研究分为以下几个阶段(在接下来的章节中展开说明):
• 阶段 0 – 定义一种方法来细分事件响应者和事件类型人群。
• 阶段 1 – 审核来自实际 Google 事件的一系列事后分析文档。
• 阶段 2 – 对参与这些事件的第一响应者进行深入的用户访谈。
• 阶段 3 – 绘制响应者在这些事件中的历程图,详细说明常见的模式、问题和采取的步骤。
细分研究人群的初步方法旨在确保纳入足够广泛的事件和受访者,从中我们可以捕获全面的数据。
事件响应者
首先,事件响应者(或值班人员)被分为两个不同的群体:SWE(软件工程师),他们通常与产品团队合作;以及 SRE(站点可靠性工程师),他们通常负责许多产品的可靠性。这两个群体根据在 Google 的任期进一步细分。我们发现了不同用户群体的以下行为:
SWE 与 SRE 的心智模型和工具
• SWE 更倾向于在调试工作流程的早期查阅日志,他们在日志中查找可能指示故障发生位置的错误。
• SRE 依赖于更通用的调试方法:由于 SRE 通常为多项服务值班,他们基于系统已知特征应用通用的调试方法。他们查找跨服务健康指标(例如,请求的错误和延迟)的常见故障模式,以隔离问题发生的位置,并且通常只有在仍然不确定最佳缓解策略时才深入研究日志。
事件响应者的经验水平
• 较新的工程师更倾向于使用最近开发的工具,而具有丰富经验(在 Google 运行复杂分布式系统十年或更长时间)的工程师则倾向于使用更多传统工具。直观地说,这个发现是有道理的——人们倾向于使用他们最熟悉的工具,尤其是在紧急情况下。
事件类型
我们还检查了以下维度的事件,并为每个维度发现了一些常见模式:
• 规模和复杂性。问题的爆发半径越大(即,其位置、受影响的系统、受影响的用户旅程的重要性等),问题就越复杂。
• 响应团队的规模。随着更多人参与调查,团队之间的沟通渠道增多,团队之间更紧密的协作和交接变得更加关键。
• 根本原因。值班人员可能会响应映射到六个常见根本问题的症状:容量问题;代码更改;配置更改;依赖项问题(我的系统/服务所依赖的系统/服务已损坏);底层基础设施问题(网络或服务器宕机);以及外部流量问题。我们的调查有意不关注安全或数据正确性问题,因为它们不在本文重点关注的工具范围之内。
• 检测。值班人员通过基于可用性或性能问题的人工或机器检测来了解问题。一些常见的机制包括以下方面的警报:白盒指标;合成流量;SLO(服务级别目标)违规;以及用户检测到的问题。
一旦确定了不同类别的事件,我们阅读了为定性研究确定的 20 起事件的事后分析报告,绘制了响应者在每起事件中采取的步骤。这种方法使我们能够验证影响响应者处理这些事件方式的常见因素以及他们面临的挑战。我们还可以确保为深入分析选择的事件分布在如上所述的各个维度上。
Google 拥有强大的无责事后分析文化。4 团队通常会查看其故障历史记录,以确保其服务持续可靠运行。因此,事后分析文档在内部很容易获得,并且是分析调试行为的宝贵资源。链接到这些事后分析报告的详细聊天记录有助于形成对发生的事情、何时发生以及哪里出错的基本理解。然后,我们可以开始绘制调试历程的原型。未来的研究可以通过应用自然语言处理来进一步验证事件响应聊天中的响应模式,从而扩展这项工作。
为了完善这项研究,我们对这 20 份事后分析报告中确定的第一响应者进行了深入访谈,以便填补事后分析文档中的任何空白。这些数据来源为我们正在绘制的调试历程增添了重要的色彩,并浮现出一组构成整个调试过程的核心构建块。
这项研究使我们能够生成 Google 实际事件调查生命周期的快照。通过绘制每个响应者的历程图,然后汇总这些视图,我们提取了适用于几乎每种事件类型的围绕调试的常见模式、工具和问题。图 1 是对每位受访响应者采取的步骤进行可视化映射的示例。
一个典型的规范调试历程包括图 2 所示并在本节中描述的阶段和子历程。这些构建块在用户调查问题时经常重复出现,并且每个块可能以非顺序且有时是循环的顺序发生。
在检测到缓解阶段,调查通常对时间敏感——尤其是在问题影响最终用户体验时。值班人员总是会尝试在找出根本原因之前缓解问题或“止血”。缓解后,值班人员和开发人员通常会对代码进行更深入的分析,并采取措施防止类似情况再次发生。
值班人员通过警报、客户升级或团队工程师的主动调查发现问题。一个常见的问题是:此问题的严重程度如何?
值班人员的目标是通过检查情况的爆发半径(问题的严重性和影响)并确定是否需要升级(拉入其他团队,通知内部和外部利益相关者)来快速评估情况。随着更多信息的到来,此阶段可能在单个事件中发生多次。
常见问题包括:我应该升级吗?我需要立即解决此问题,还是可以稍后处理?此中断是本地的、区域性的还是全球性的?如果中断是本地的或区域性的,它会变成全球性的吗(例如,金丝雀分析工具包含的发布可能不会触发全球中断,而现在正在您的系统中蔓延的由发布触发的死亡查询可能会)?
值班人员形成关于潜在问题的假设,并使用各种监控工具收集数据以验证或证伪理论。然后,值班人员尝试缓解或修复根本问题。随着值班人员收集数据以验证或证伪关于问题原因的任何假设,此阶段通常在单个事件中发生多次。
常见问题包括:错误和延迟是否出现峰值?需求是否发生变化?此服务有多不健康?(这是误报,还是客户仍在遇到问题?)有问题的依赖项是什么?服务或依赖项中是否发生过生产变更?
值班人员的目标是确定哪种缓解措施可以解决问题。有时,缓解尝试可能会使问题变得更糟,或者对其依赖服务之一造成不利的连锁反应。补救(或完全解决问题)通常需要所有调试步骤中最长的时间。此步骤可能并且经常在单个事件中发生多次。
常见问题包括:应该采取什么缓解措施?您对这是适当的缓解措施有多大信心?此缓解措施是否解决了问题?
值班人员的目标是找出根本问题,以防止问题再次发生。此步骤通常在问题得到缓解且不再对时间敏感后发生,并且可能涉及重大的代码更改。响应者在此阶段编写事后分析文档。
常见问题包括:哪里出错了?问题的根本原因是什么?如何使您的流程和系统更具弹性?
在整个过程中,事件响应者记录他们的发现,与队友一起进行调试,并在需要时与团队外部进行沟通。
在每次访谈中,值班人员都报告说他们开始使用指示给定服务健康状况的时间序列指标,执行广度优先搜索以识别系统中哪些组件已损坏。接受访谈的大多数团队评估了以下项目:
• RPC(远程过程调用)延迟和错误指标(类似于从开源 gRPC 库派生的指标)。
• 外部流量的变化,包括 QPS(每秒查询数)。
• 生产中的变化,例如发布、配置推送和实验。
• 底层作业指标,例如内存和 CPU 消耗。
警报和实时仪表板都使用这些指标。值班人员通常只有在确定某个组件已损坏后才使用日志和跟踪,然后他们需要深入研究特定问题。
一些受访者应用 SRE 最佳实践来调试复杂的分布式系统,有条不紊地排除他们关于可能出错的理论,应用临时缓解措施以防止用户痛苦,并最终成功解决问题并找出导致最初中断的根本原因。
许多其他响应者遇到了意想不到的障碍。一些响应者受到整个堆栈中同时发生的一系列复杂更改的影响。因此,隔离实际问题并找出如何解决问题非常具有挑战性。其他响应者提到流程和意识问题:有些人不完全了解他们的生产工具如何工作,或者应该采取的适当标准行动方案。一些响应者最终无意中将错误的更改应用到生产环境。
以下是一些(匿名的)故事,用于说明成功和有问题的调试会话。这些轶事旨在表明,即使拥有最有经验的工程师、出色的技术和强大的工具,事情也可能而且确实会以意想不到的方式出错。
以下是一个成功调试会话的示例,其中 SRE 遵循最佳实践并在 20 分钟内缓解了服务关键问题。
在参加会议时,SRE 值班人员收到一条页面通知,告知她前端服务器出现 500 服务器错误。当她最初查看服务健康状况仪表板时,寻呼风暴开始,她看到更多警报触发和错误浮出水面。她快速响应并立即确定她的服务不健康。
然后,她确定问题的严重程度,首先问自己有多少用户受到影响。在查看一些错误率图表后,她确认一些位置已受到此中断的影响,并且她怀疑如果不立即解决,情况将显着恶化。这种提问方式被称为分类循环,类似于医疗保健中使用的分类流程(例如,急诊室根据患者的紧急程度或服务类型对患者进行分类)。SRE 需要确定警报是否是噪音,她是否需要立即处理,以及是否将问题升级给其他团队和利益相关者。
现在她知道这是一个真实且相对严重的问题,SRE 开始拉入她团队中的其他人来帮助调查。她还建立沟通渠道,以通知可能受到影响的其他团队,并让他们知道她的团队正在解决中断问题。
然后,她专注于暂时缓解最终用户的问题。她安排一位队友确保流量不会路由到任何不健康的位置,并配置负载均衡器以避免将流量发送到受影响的位置。目前,此操作阻止了问题传播,这使她可以自由地使用监控数据进行更深入的调查。
接下来,她提出一系列问题,以帮助她缩小潜在原因的范围,并找出如何最好地永久缓解问题。她主要使用时间序列指标(例如,Cloud Monitoring 指标3)来帮助快速回答这些问题:
• 缩小调查范围:服务的哪些特定部分不健康?错误来自前端还是后端?是否存在有问题的“切片”数据?数据中是否存在异常值?
• 确定问题的严重程度并排除原因:图表的形状是阶梯状(某些东西突然改变并保持不变)、尖峰状(某些东西改变,然后停止)还是斜坡状(正在发生逐渐发布)?错误率上升的速度有多快?
• 确定严重程度:爆发半径是多少?(如果错误在全球范围内发生,则表明这是一个严重的问题,很可能会对最终用户产生影响。)
• 排除根本原因:问题何时开始?服务或其依赖项中的哪些生产事件与此问题相关联?
缓解问题后,SRE 深入研究日志和跟踪,确认一行新代码导致出现问题的区域中的作业崩溃。她决定回滚到服务的最后一个稳定版本,并在受影响的位置重新上线时验证问题已解决。
以下是一个历程示例,其中 Google 值班人员在调试时遇到了意想不到的障碍,并且应用最佳实践本可以缩短缓解时间。
值班人员收到一条页面通知,告知他服务的整体服务器端可用性 SLO(服务级别目标)从 99.9% 下降到 91%,并且特定用户操作失败。他首先查看指标图表开始他的调查,图表确认了 (1) 错误率开始增加的时间;(2) 错误主要是由超时引起的;以及 (3) 请求持续时间大约等于超时持续时间。然后,他将指标切片到之前识别出的失败用户操作,检查相关的服务器错误和每秒查询数指标,并深入研究服务器日志以查找特定错误。到目前为止,他一直遵循通用的调试实践。
与此同时,后端服务依赖项的另一位值班人员注意到该服务即将达到其配额限制,并怀疑这种情况可能会对调查产生影响。这位值班人员尝试通过配置更改分配一些配额,希望缓解问题。然而,由于对配置推送工具的误解,此更改意外地删除了一个位置的后端服务器,而不是添加配额,这增加了其他位置的错误率。此外,由于他认为此更改是安全的,因此值班人员没有像最佳实践建议的那样密切监控更新配置的发布,并且最初错过了实际容量因删除该位置而减少的指标。此时,值班人员违反了最佳实践,执行了包含完全无关更改的非验证配置的全局推送——删除后端的操作应与添加容量的操作分开。
当这种情况发生时,第一位值班人员深入日志,发现“权限被拒绝”错误在后端服务器被删除时增加。他通过对许多支持后端进行广度优先搜索并分析其聚合日志来做到这一点。在这里,他注意到,当一台服务器被删除时,更多请求被引导到正在经历问题的服务器。只有在深入研究日志并打开许多工具后,他才能够将错误与依赖项中的配置更改联系起来。
更好的工具本可以阻止用户执行意外的更改。工具还可以帮助验证更改实际上会做什么。此外,更好的工具来支持监控系统更改的效果本可以帮助值班人员更早地得出这些结论。
然后,值班人员联系以分享他们的发现。连接后,第一位值班人员回滚了减少容量的配置推送,识别出更改权限错误的后端依赖项,并与后端团队合作以回滚错误的更改。
如果您负责运行分布式服务,您可能会发现自己正在处理与我们采访的团队所经历的情况类似的场景。我们的研究表明,应用以下原则的团队通常能够更快地缓解服务问题。
您需要拥有 SLO 和/或指标,您可以使用它们发出警报,并且可以选择性地进行报告。这些应准确反映用户的痛苦,并允许按故障域进行切片。这些还应与具有明确后续步骤和指向最重要信息的链接的警报相关联。
一旦您具备了 SLO 和准确监控的先决条件,您就需要能够快速确定用户痛苦的严重程度和总爆发半径。您还应该知道如何根据问题的严重程度设置适当的沟通渠道。
记录一组对您的服务安全有效的缓解策略可以帮助值班人员暂时修复面向用户的问题,并为您的团队赢得识别根本原因的关键时间。有关实施通用缓解措施的更多信息,请参阅 Jennifer Mace 的“使用通用缓解措施减少服务中断的影响”。5 轻松识别服务中的更改(无论是关键依赖项还是用户流量)的能力也有助于确定要推进的缓解尝试。正如堪称典范的调试案例中所述,提出一系列常见问题并拥有指标、日志和跟踪可以帮助加快验证您关于哪里出错的理论的过程。
尽管每项服务都不同,但在我们检查的根本问题及其相关的缓解措施中,出现了以下模式。当您处理以前从未见过的问题时,考虑您的服务面临的问题类型、您应该提出的问题以及基于答案的相关缓解措施可能会有所帮助。
• 服务错误。这是我们的研究中触发警报的最常见原因。因此,它也具有最多样化的缓解措施。在确定缓解策略时要考虑的一些因素包括:(1) 错误是否在全球范围内发生?检查相关的发布、配置/数据更改和实验。(2) 每秒传入的查询数是否激增?增加容量和/或开始负载削减以丢弃您的服务无法处理的流量。(3) 是否有不良行为者导致每秒查询数发生变化?如果是,则阻止用户。
• 性能。延迟可能会导致糟糕的用户体验,并随着时间的推移而降级为错误。如果没有明显的关联容量或生产更改,这些问题可能很难调试。通常,响应者会查看跟踪以识别堆栈中哪些组件受到影响,并尝试从那里确定解决方案。
• 容量。容量问题是最容易发现的一些问题,尤其是在您有特定于容量的警报的情况下。与错误和性能问题一样,这些问题也可能表现为快速和缓慢的消耗。如果服务即将立即耗尽容量,团队通常会请求更多容量以“紧急贷款”来扩展其服务(或者他们可能会尝试横向扩展)。对于缓慢的消耗,响应者会执行额外的分析和计划,以确定是否存在其他根本问题。只有当自动化容量系统达到其授权的最大值,并且获取更多资源需要人工干预时,这些类型的警报才会浮出水面。
• 依赖项问题。关键依赖项——即使它位于服务堆栈的深处——也可能导致整个服务失败。了解您的硬依赖项(代码关键路径中的依赖项)并能够查看这些依赖项的健康状况有助于排除问题是否实际上出在另一项服务上。
• 调试微服务。我们采访的大多数团队都采用微服务架构。通常,错误可能比值班人员表现出来的位置更深。与调试依赖项类似,能够快速遍历堆栈、关联生产更改和理解服务架构会很有帮助。
SRE 不断努力改进系统并暴露漏洞,以限制生产中故障、未遂事件和效率低下的可能性。即使在最理想的条件下,事情也难免会出错。通过揭示、保留和传播调试工作流程中的共性(包括积极和消极的共性),目的是防止同一类问题再次发生,或者,当无法预防时,最大限度地减少不可避免的中断的持续时间或影响。希望其他组织也可以在实践中应用这些发现。
1. Beyer, B., Jones, C., Petoff, J., Murphy, N. R., eds. 2016. 构建安全可靠的系统。O'Reilly Media;https://landing.google.com/sre/books/。
2. Beyer, B., Murphy, N. R., Rensin, D. K., Kawahara, K., Thorne, S., eds. 2018. 站点可靠性工作手册:实施 SRE 的实用方法。O'Reilly Media;https://landing.google.com/sre/books/。
3. Google Cloud。2020 年。指标列表;https://cloud.google.com/monitoring/api/metrics。
4. Lunney, J., Lueder, S. 2017. 事后分析文化:从失败中学习。O'Reilly Media;https://landing.google.com/sre/sre-book/chapters/postmortem-culture/。
5. Mace, J. 2019. 云聚焦:与 Jennifer Mace 一起使用通用缓解措施减少服务中断的影响。O'Reilly Media;https://www.oreilly.com/library/view/spotlight-on-cloud/0636920347927/。
服务可用性的计算
您的可用性仅与您的依赖项的总和一样高。
Ben Treynor、Mike Dahlin、Vivek Rau、Betsy Beyer
https://queue.org.cn/detail.cfm?id=3096459
为什么 SRE 文档很重要
文档如何使 SRE 团队能够管理新的和现有的服务
Shylaja Nukala 和 Vivek Rau
https://queue.org.cn/detail.cfm?id=3283589
应对意外
故障会发生,弹性演练可以帮助组织为此做好准备。
Kripa Krishnan
https://queue.org.cn/detail.cfm?id=2371516
Charisma Chan 是 Google 英国伦敦的用户体验设计研究员。在加入 Google 之前,她曾领导金融服务和媒体行业的消费者和企业产品的设计研究和战略,并拥有纽约州伊萨卡康奈尔大学的学士学位。
Beth Cooper 是 Google NYC 的产品经理。她专注于为站点可靠性和软件工程师构建 Google 规模的监控。在加入 Google 之前,她曾在 Microsoft Azure 工作,为云和数据中心自动化构建产品。
版权所有 © 2020,所有者/作者持有。出版权已许可给 。
最初发表于 Queue vol. 18, no. 2—
在 数字图书馆 中评论本文
Devon H. O'Dell - 调试心态
软件开发人员花费 35-50% 的时间来验证和调试软件。调试、测试和验证的成本估计占软件开发项目总预算的 50-75%,每年超过 1000 亿美元。虽然工具、语言和环境减少了在单个调试任务上花费的时间,但它们并没有显着减少调试的总时间,也没有减少调试的成本。因此,过度关注开发过程中消除错误是适得其反的;程序员应该拥抱调试作为解决问题的练习。
Peter Phillips - 使用跟踪增强调试
创建用于运行旧程序的模拟器是一项艰巨的任务。您需要透彻了解目标硬件以及模拟器要执行的原始程序的正确功能。除了功能正确之外,模拟器还必须达到以原始实时速度运行程序的性能目标。实现这些目标不可避免地需要大量的调试。错误通常是模拟器本身中的细微错误,但也可能是对目标硬件的误解或原始程序中的实际已知错误。(原始程序的二进制数据也可能已微妙地损坏或不是预期的版本。)
Queue Readers - 又一天,又一个错误
作为本期关于程序员工具的一部分,我们在 Queue 决定就调试主题进行一项非正式的网络调查。我们请您告诉我们您使用的工具以及您如何使用它们。我们还收集了关于那些难以追踪的错误的故事,这些错误有时会让我们想到从事其他职业。