互联网服务正日益成为我们日常生活的一部分。我们从中获取价值,依赖于它们,并且现在开始像对待电话系统和电网一样,认为它们是无处不在的。然而,互联网服务的实现仍然是一个尚未解决的问题,互联网服务远未充分发挥它们在世界中的潜力。
互联网服务被实现为大型分布式计算机系统。大型计算机系统需要人工操作员。硬件会故障,软件会故障,设施需要管理。人类就像白细胞一样,维持系统的运转。人类诊断问题。人类更换损坏的硬件。人类从系统中移除损坏的节点。人类根据庞大用户群不断变化的需求调整系统,随着新功能的添加和新访问模式的出现进行优化。人类应对外部对服务的滥用。
事实证明,人类也很昂贵,而且容易犯错。例如,2003年6月《科学美国人》上的一篇文章调查了三个互联网站点,发现操作员导致了51%的故障。1 在微软,我们也看到了人为错误导致的问题。我们已经看到了软件错误、硬盘处理不当以及硬件和软件配置错误等问题,仅举几例。我们也看到人为错误呈下降趋势。随着系统变得越来越大,硬件故障往往占据主导地位。
关注互联网服务的核心目标——为用户提供可靠的服务并保持低成本——人们发现人为干预会妨碍成功。为了在下一代场景中取得进展,互联网服务需要专注于开发软件,以经济高效且可靠地部署计算机系统。特别是,我们需要关注由数千台计算机组成的系统所涉及的挑战。
讨论互联网服务中的监控问题,可以很好地切入更大的问题。
互联网服务出于不同的原因监控其系统
在构建于数千个独立组件之上的大型互联网服务中,监控的作用是什么?传统方法涉及收集数据,渲染数据的可视化,并最终依靠人工分析来做出决策。监控数据的优点在于,计算机处理数据的速度远快于人脑。在微软,我们正在问自己,系统如何通过直接以编程方式使用监控数据,并根据数据做出自动决策来获益。我们特别关注监控数据,因为它可以通过系统本身以编程方式使用。
微软的通信服务平台小组受到了加州大学伯克利分校的 David Patterson 和斯坦福大学的 Armando Fox 领导的 ROC(面向恢复的计算)项目的影响。(有关 ROC 的更多信息,请参见 http://roc.cs.berkeley.edu。)ROC 认为,我们应该通过优化系统从故障中恢复的能力,来接受互联网服务中系统故障和人为错误的必然性。
以一个假设的服务为例,它只有一种类型的故障:每月发生一次,每次发生故障都需要三个小时才能恢复。这导致一年内总共 36 小时的停机时间,可用性得分为 99.59%。在解决这个问题时,服务的工程师可以尝试通过减少故障频率或故障恢复时间来提高可用性。
请注意,减少恢复时间对可用性有直接影响。例如,将恢复时间从三个小时减少到 45 分钟,将减少一年内的停机时间,从而使停机时间减少到九个小时,可用性得分为 99.9%。
可用性 |
每年允许的停机时间
|
99% |
约 3 天 |
99.9% | 约 9 小时 |
99.99% |
约 1 小时 |
99.999% |
约 5 分钟 |
99.9999% |
约 30 秒 |
系统的可靠性是恒定的,故障率是相同的,但恢复时间得到了优化。这是一个重要的例子,因为在实践中,我们发现优化恢复时间比减少故障发生次数更有成效。故障率往往是固定的,源于硬件的基本属性。
我们发现 ROC 在实践中是正确的方法。例如,我们几乎从不担心尝试将服务器的响应速度提高几毫秒,但我们始终专注于优化恢复程序。此外,成熟且技术先进的监控方法是从故障中快速恢复能力的最重要因素。如果没有检测故障的能力,就不可能有效地从故障中恢复。
在高层次上,我们需要了解数千个节点在任何时间点正在发生什么。当问题发生时,系统必须能够进行故障转移并继续成功运行,而无需人工修复问题。硬件和日常运营成本的所有重要改进都始于建立可靠的监控系统。
互联网服务是一个 24/7 全天候运行的过程,涉及许多相互作用的部分。与制造业一样,互联网服务力求获得一致的、可重复的结果。虽然没有制造产品,但服务本身应表现出一致的可靠性和响应性。当向数据中心添加容量时,规划人员希望具有可预测性——最近添加的系统应与现有系统一样良好地运行。
我们借鉴 SPC(统计过程控制)领域来实现一致的结果。SPC 用于确保制造过程的质量和稳定性。SPC 的目标是使用统计方法来衡量过程中的差异,从而识别问题并随着时间的推移稳定过程。例如,对于一家生产轮胎的制造厂来说,为每个生产的轮胎使用不可预测量的橡胶是不经济的。使用 SPC,制造商为每个轮胎中应使用的橡胶量设定目标。此外,制造商还设定了围绕目标的可接受差异量容差。然后,SPC 方法测量每个轮胎上的橡胶用量,帮助制造商了解制造过程在橡胶用量方面是否稳定且可预测。如果过程变得无效或不可预测,则 SPC 方法有助于识别问题的根源。
这种方法对互联网服务有好处。服务管理器需要了解和定义系统良好运行时的状态。他们需要能够检测到任何偏差或偏离该状态的趋势。当工程师对系统进行更改时,服务管理器需要能够衡量更改的效果。我们使用 SPC 测量来了解我们是否正确地使用了资源。例如,如果一项服务的所有事务都在目标响应时间之下很好地执行,那么该服务可能就过度构建了。
除了使用 SPC 管理服务外,我们还可以在软件中使用它来实现自我管理。服务软件的实现本身应积极维护严格的过程控制。服务软件应从头开始进行分解和设计,并考虑到过程控制。软件应借鉴和构建闭环控制、过程控制和自稳定系统的概念。将控制系统视为对刺激的持续响应。软件通常不符合此模型,但互联网服务完全符合。互联网服务每周 7 天、每天 24 小时运行,不断响应来自数百万用户的请求。虽然从根本上来说,互联网服务不是实时系统,也不是严格意义上的连续系统,但总体而言,它们在不断地响应刺激。当进行更改时,在来自数百万用户的重负载下,可以相对快速地看到效果。
控制系统可以分为开环或闭环。开环系统可以被监控和控制,但监控信息不直接用于控制系统。然而,闭环系统将监控数据直接反馈给控制器,使其能够补偿运行条件的变化。2 图 1 显示了一个示例,即空调设备。开环系统将允许操作员控制空调的工作量。闭环系统将测量空气的温度,并将结果反馈给控制器,从而控制空调的输出并保持恒定的温度。
系统中的每个服务或进程都可以被认为是公开了一个控制器,该控制器实现了一个标准化和通用的接口。同样,系统中的每个服务或进程都可以被认为是公开了一组标准化的传感器,通过通用的软件接口,提供组件性能的画面。组件可以监控自身,反馈到自己的控制器,以维持期望的状态。外部软件代理也可以监控组件,与公开的控制器接口,以修复或维持更广泛系统的期望状态。
互联网服务必须是自稳定系统。这些系统在受到扰动时,保证在有限的步骤内返回到合法状态。3 当软件系统不满足此属性时,人工操作员必须介入以将系统置于合法状态。
这方面的一个很好的例子涉及反馈环路,这是一个我们在实践中多次遇到的问题。考虑这样一种情况:系统中的特定服务器开始响应缓慢并间歇性地发生故障。机器上存在临时问题。客户端收到故障,超时并重试其操作。在服务器上,失败的操作仍在尝试完成。服务器遇到问题,尚未意识到客户端正在超时和重试。每个客户端重试都会加剧问题,因为它会消耗服务器已经紧张的资源,启动服务器无法完成的新操作,以至于服务器完全无法响应并且无法恢复。如果客户端只是在一段时间内停止使用服务器,它就能够恢复,间歇性故障消失,并且服务器恢复到良好状态。在本例中,系统在置于非法状态时,没有采取措施返回合法状态。
我们如何将自稳定系统的概念应用于软件服务?我们必须首先根据监控数据定义合法状态。
我们可以从以下几个方面推断互联网服务的状态
系统中的每个节点都必须在这些方面进行仔细的测量。任何方面的问题都可能表明服务处于非法状态。监控软件在获得这些领域的原始测量数据后,也应注意每个领域的差异。不一致的结果可能与直接的坏结果一样,是潜在问题的迹象。
在实践中,我们发现选择正确的测量方法非常重要。例如,在测量响应性时,这是否意味着测量用户的端到端响应时间?这是否意味着测量每个内部事务的响应时间?如果所有测量都是低级别测量,则很难准确了解用户的体验。衡量用户的体验(独立于实现,包括所有端到端功能)的能力极其重要。另一方面,高级别测量不允许软件或服务管理器准确了解问题出在哪里。因此,我们发现拥有许多特定的测量也很重要。将低级别实现测量与高级别用户体验测量相关联是一个巨大的挑战。
每位工程师都害怕在半夜被呼叫,并收到消息:“网站宕机了!”我们都有关于现场事故的故事要讲,从“你能相信这个简单的问题造成了这么大的麻烦吗?”到“我们花了一整周的时间调试网站,最后在一个周末重新架构了网络!”
互联网服务具有许多互连的组件以及不断变化和新兴的用户访问模式,将以非平凡的方式发生故障。简单的问题最终会演变成影响客户的站点范围问题。在流程的某个时刻,有人注意到——工程师或客户——问题升级。
升级通常会指向根本问题的副作用。例如,一组缓慢或发生故障的硬盘驱动器可能会导致客户投诉。当客户投诉升级时,问题往往被表述为客户体验的函数。由于不同的客户以不同的方式描述他们的问题,工程师可能会感觉他们看到了多个实际问题。经过仔细的调试,工程师将找到根本问题并修复它。然而,总体方法效率低下。
为了解决此类问题,服务必须检测和隔离发生故障的组件。首先,服务必须检测发生故障的组件,以便它们不会默默地将故障级联到系统的其他部分。查找发生故障组件的最佳方法是直接监控该组件,而不是在升级后调试数小时。然后,服务必须隔离发生故障的组件,使其不会影响其他工作系统的可用性。
故障检测是一个模糊的领域。组件可能在绝对意义上发生故障。例如,如果计算机的 CPU 停止工作,我们可以说它绝对发生了故障,因为知道除非进行物理修复,否则它将无法工作。计算机已宕机,并且对计算机的所有请求都将失败。
组件也可能在相对意义上发生故障。例如,如果系统中的一个节点的性能仅为系统中类似节点的 10%,即使它在技术上正在运行,我们也希望将其视为发生故障。故障也可能是间歇性的。一台服务器可能偶尔发生故障,在很长一段时间内运行良好,但每隔一段时间(例如每隔几个小时)进入故障状态一小时,这可能是一台发生故障的服务器。
给定监控数据流,我们如何准确确定组件是否发生故障?简单的二元方法是不够的。将组件可能存在的状态枚举出来会有所帮助
状态机非常适用于此问题。给定一个用于推理的状态机,我们可以智能地决定组件如何在各种状态之间转换。我们发现错误计数的简单阈值效果很好。例如,如果组件连续发生 1,000 次故障,我们认为该组件已故障。这种技术很简单,但在某些方面存在缺陷。例如,很少被访问的故障组件将需要很长时间才能达到其故障阈值。
更先进的技术考虑了故障率,并且通常更具适应性。我们发现在实践中,更简单的技术往往被证明是足够的。大多数真实世界的故障都会定期发生,并且很容易理解,并且很容易通过简单的阈值检测到。由于故障标准不会快速变化,因此从自适应技术中几乎没有什么收获。
在互联网服务中,每个节点都需要知道它可能与之通信的所有其他节点的状态。这有助于通过允许“快速失败”来防止级联故障——在尝试访问已知的故障组件时返回即时错误,而不是在超时时占用资源。这也有助于故障隔离并防止负反馈循环。
虽然大多数组件可以在内存中保留所有其他组件的完整状态,但持久状态存储是必需的。当机器宕机并重新启动时,我们希望它们知道所有当前发生故障的组件,而无需通过实际操作重新检测状态。
互联网服务倾向于解决非常并行的问题。例如,在数百万用户中,个人通常会引入可以独立满足的工作项。复制技术允许跨多台机器并行查询公共数据结构。为了使成功的大型互联网服务必须并行化才能良好扩展,服务管理器必须能够衡量他们的服务实际并行化的程度。
监控系统有助于确定系统的并行化程度。衡量系统的平衡相对简单,因为跨数千台计算机进行测量很简单。您可以直接测量使用的存储容量、内存、网络带宽和 I/O 带宽量。您可以比较系统中节点之间的这些测量值,以确定它是否均匀平衡。
在检测到不平衡的地方,您可以通过移动数据和用户帐户,以及通常通过重新分配数据中心的资源来恢复系统的平衡,从而实现平衡。但是,您如何智能地重新分配资源?
用于资源重新分配的简单技术可以成功地使站点达到平衡状态,但它们并没有最大限度地减少必须显式移动的资源量。例如,在大型分布式存储服务的负载均衡中,数据量达到 PB 级,并且以非均匀方式访问数据,一种简单的技术将涉及随机移动数据。虽然简单且肯定能保证平衡,但这种技术成本高昂,因为它涉及不断地在所有节点之间随机移动数据。
对最大限度地减少为实现平衡而必须引入的更改量的方法的研究将是有益的。我们可以统计地将某些用户行为与他们为系统引入的工作量相关联。通过让监控系统测量这些行为,我们可以计算出选择特定数据进行移动的策略,同时仍然实现平衡,从而最大限度地减少为使系统达到平衡状态而必须重新分配的资源量。
在实践中,我们已经看到用户行为发生了巨大变化。随着新技术的开发以及服务向用户提供新功能,我们发现了全新的访问模式。数字照片提供了一个很好的例子。互联网邮箱曾经相对较小,充满了简单的文本消息。现在,互联网用户经常交换数字照片,并且邮箱中有很多兆字节的消息。我们发现最大的困难在于使平衡算法适应不断变化的用户模式。然而,在监控方面,我们不需要更改监控平衡的方式来跟上不断变化的用户模式。
互联网服务将软件行业进一步推向“软件即服务”的愿景。越来越多的应用程序无需在用户的 PC 上本地安装软件即可使用。现在,软件跨越许多计算机和设备,并且通常在用户可以找到互联网接入的任何地方都可用。
互联网服务的开发人员拥抱这个新世界。创新和功能可以在任何一天交付给用户,只需通过升级服务软件即可,而无需用户下载。此外,互联网服务已采用基于广告的商业模式,无需用户购买。这迫使服务开发人员更频繁地交付创新,因为用户采用没有任何障碍。
鉴于持续创新方法以及随之而来的短开发周期,我们遇到了一个艰巨的问题:如何向正在运行的互联网服务发布新软件,将其部署到数千个节点,并仍然避免停机?
我们需要可预测且可重复的软件部署,并且我们特别需要监控实际软件安装的正确性——独立于功能的正确性和性能的质量。人为错误是互联网服务停机时间的常见主题。根据我们的经验,人为错误在数千台计算机的软件部署和配置中很常见。软件部署的艰巨任务迫切需要完全自动化和监控。
互联网服务往往有许多运动部件,就像发动机一样,需要进行性能调整。软件工程师和操作员通过站点的配置来行使控制权。我们通俗地将配置参数称为我们可以调整的“旋钮”,这让人联想到科学仪器或音频工程师的混音台的图像。示例包括服务应为缓存分配的内存量、给定进程中要使用的线程数、最大队列深度等——任何可能影响经典计算机科学速度与空间权衡的参数都倾向于显示为可以调整的旋钮。
一些实施者通过存储在每个节点本地的配置文件来配置其系统。另一些实施者通过集中式配置数据库来配置其系统。结果在功能上是等效的:存在一个单一的预期配置,该配置是持久化的,应在系统中的所有节点上一致地应用。
随着用户群的增长,新功能的添加和访问模式的变化,需要定期更改配置以保持服务的最佳运行状态。如何在服务运行时更改服务的配置,并在数千个节点上正确执行该更改?如果数千个节点的配置更改在除四个节点之外的所有节点上都成功,会发生什么情况?
由于数千个节点的部署失败很可能发生,因此服务必须监控每个节点的精确配置。主配置指定了预期配置,并且不断自动检查机器以确保配置正确。
在运行数据中心时,事情总是会出错,并且需要人类来保持数据中心的平稳运行。鉴于硬件和软件故障率,并乘以当今数据中心中运行的大量节点,数学计算表明故障很容易每天发生。
考虑以下示例:硬盘 MTTF(平均故障间隔时间)估计值往往约为 100 万小时。假设一个数据中心有 10,000 台计算机,每台计算机有 10 个硬盘驱动器,总共 100,000 个硬盘驱动器。使用简化的模型,假设所有硬盘驱动器都具有统一的故障率,并且新硬盘驱动器和旧硬盘驱动器具有相同的故障率(在实践中并非如此),您预计每 10 小时会有一个硬盘驱动器发生故障。在微软,我们的日常运营确实证明了这一点——在我们的大型数据中心中,每天发生硬盘故障是很常见的。
服务希望有效地利用人类,仔细注意人类与数据中心交互的方式。随着互联网服务的增长以及其数据中心的扩展,企业不希望在向数据中心添加容量时雇用更多的人。从人工管理角度来看,数据中心的可扩展性是人类与系统交互点的直接函数。由于当计算机正常工作时,人工干预往往是不必要的,因此我们发现最常见的交互发生在系统发生故障时。因此,互联网服务专注于简化故障模式和恢复场景。
报警的首要原则是人类很容易被大量数据淹没。数据中心不能将它看到的每一个故障都升级给人类。监控软件需要处理数据,聚合数据,并通常将其看到的内容映射到关于系统的更高级别元数据。与计算机科学中的大多数问题一样,额外的间接层总是有帮助的——元数据比原始监控数据在做出自动决策时更有用。
我们已经看到过这样一种情况:一个单一的问题被过度升级,产生了数百个独立的升级。在这样的情况下,工程师总是感到不知所措,花费数小时筛选数据以了解根本原因,过滤掉误报并寻找潜在的模式。我们最精简的情况是,一个问题只引起了适量的升级。
当退后一步观察互联网服务的日常运营时,人们会发现相当多的“程序遵循”。互联网服务倾向于使用众所周知的成熟硬件和软件平台。随着时间的推移,工程团队获得了运行系统的经验并对其进行调整,使其达到只有少量众所周知的故障模式,每种故障模式都以相对一致的方式重复出现。工程团队为每个已知的故障模式分配了标准操作程序。
动机是消除例行公事中的猜测。如果在半夜发生问题,您希望遵循明确定义的程序——无需分析,无需调试,只需按照过去一直修复问题的方式修复问题即可。鉴于这种趋势,这个问题迫切需要通过软件来解决。人工操作员本质上是专家系统,他们的大脑能够将调试服务的经验和对标准程序的理解映射为使系统恢复合法状态的操作。
将监控应用于自我修复的第一步是能够枚举和检测服务的故障模式。如果故障模式是临时的、不被理解的或不断变化的,那么系统就无法在没有人类大脑帮助的情况下自行修复。在实践中,许多故障需要相同的响应才能修复。关键是识别所有必要的修复响应,然后将它们映射到可检测到的故障。
我们发现在实践中,存在需要特定响应的特定故障。我们还发现,有一组故障可以使用通用响应来处理。我们倾向于使用具有少量且固定的访问模式的系统,因此具有少量且固定的故障模式。我们倾向于使故障模式保持简单,以便恢复简单。然后,我们将每个故障映射到特定的恢复响应。构建一个完全通用的系统非常困难,但我们发现,拥有将故障映射到恢复操作的通用概念是可行的。随着时间的推移,我们增强了对故障的理解和检测能力,并改进了我们的恢复操作。
图 2 中的事件频率图说明了 Hotmail 的这个例子。在这里,事件被认为是需要某种形式的恢复操作的事情。事件不一定是中断或影响用户——仅仅是幕后发生的事情。x 轴跟踪 38 种不同类型的事件。y 轴显示了一个月中事件发生的次数。我们可以看到,少量事件频繁发生,而大多数事件不经常发生。
优化在两个维度上进行。我们专注于降低顶级事件的频率和影响。我们还专注于减少事件类型的数量——在本例中,许多事件只发生一两次,但总的来说,它们贡献了大量的事件。
任何大型互联网服务的目标都是生产一个自我管理的系统——一个“开箱即用”并且由一个小型工程师团队有效管理的系统。在极限情况下,这归结为一个人工智能问题。我们可以构建一个不需要人工干预的系统吗?
消除人工干预最容易的地方是从众所周知的故障模式中恢复。事实上,大多数成功的互联网服务已经在这个领域取得了坚定的进展。我们如何在更动态的领域取得进展?我们如何提高数据中心适应不断变化的用户需求的能力?当用户采用新发布的功能时,我们如何让软件动态地重新配置数据中心中的系统以提供最佳性能?
拥有庞大用户群的互联网服务享有大数定律的支持。通过数百万用户访问服务,抽样技术可以提取使用模式并检测这些模式的变化。我们可以进一步将服务配置的更改与系统整体性能的正面或负面影响相关联。
复杂性是一个真实世界的问题。为了实施大型互联网服务,开发团队必须努力追求简单性。动态和自适应方法可能会将系统的复杂性推向超出合理范围的程度,以至于无法预测结果。然而,随着底层软件范例和基础设施的不断改进,我们将能够开发更动态的系统,而不会受到复杂性的困扰。
监控系统有助于减少互联网服务中的人工干预。监控软件框架必须涵盖各种各样的问题,从跨数千个节点的测量数据收集到自动稳定系统的软件执行器。通过以编程方式使用监控数据,服务可以维护过程控制、检测和隔离故障、保持平衡的资源利用率,并使人类免受复杂系统中固有的噪声影响。
随着互联网服务的成熟,以及数百万人大量使用的大型系统变得更加为人所理解,我们将在规模经济方面取得巨大进步。企业将能够部署数千个廉价的商品组件,将它们连接到分布式系统中,并为任何地方、任何时间、任何设备上的互联网用户提供大量的计算能力。我们将开始看到当今相对较少的互联网服务数量增长。并且我们将感到满意,因为互联网服务变得像今天的电话网络和电网一样普及和理所当然。
比尔·霍夫曼 (Bill Hoffman) 是微软通信服务平台组的开发经理。在微软,他专注于互联网服务和大规模系统的软件开发,从 Web 应用程序到 Web 服务,再到存储系统,以及数据中心软件的整体管理。在加入微软之前,他曾在互联网初创公司 Jump Networks 担任软件开发人员,该公司于 1999 年被微软收购。他拥有康奈尔大学计算机科学学位,现居加利福尼亚州伯克利市。
最初发表于 Queue vol. 3, no. 10—
在 数字图书馆 中评论本文
尼克拉斯·布鲁姆 (Niklas Blum), 塞尔日·拉夏贝尔 (Serge Lachapelle), 哈拉尔德·阿尔韦斯特兰德 (Harald Alvestrand) - WebRTC - 面向开放 Web 平台的实时通信
在这个疫情时期,世界比以往任何时候都更依赖于基于互联网的 RTC(实时通信)。在过去十年中,RTC 产品的数量呈爆发式增长,这在很大程度上归因于更便宜的高速网络接入和更强大的设备,同时也归因于一个名为 WebRTC 的开放、免版税平台。WebRTC 的作用正在从实现有用的体验转变为在疫情期间让数十亿人继续工作和学习,并保持重要的人际联系方面变得至关重要。WebRTC 未来蕴藏的机遇和影响确实令人着迷。
本杰明·特雷诺·斯洛斯 (Benjamin Treynor Sloss), 希拉贾·努卡拉 (Shylaja Nukala), 维韦克·劳 (Vivek Rau) - 重要的指标
衡量您的站点可靠性指标,设定正确的目标,并努力准确地衡量这些指标。然后,您会发现您的服务运行得更好,停机时间更少,用户采用率也会更高。
西尔维娅·埃斯帕拉基亚里 (Silvia Esparrachiari), 塔尼娅·赖利 (Tanya Reilly), 阿什利·伦茨 (Ashleigh Rentz) - 跟踪和控制微服务依赖项
如果您曾经把钥匙锁在家里或车里,您就会熟悉依赖循环。没有钥匙你就打不开锁,但是不打开锁你就拿不到钥匙。有些循环是显而易见的,但更复杂的依赖循环可能很难在导致停机之前被发现。跟踪和控制依赖项的策略对于维护可靠的系统是必要的。
迪普塔努·贡·乔杜里 (Diptanu Gon Choudhury), 蒂莫西·佩雷特 (Timothy Perrett) - 为互联网规模服务设计集群调度器
希望构建调度系统的工程师应考虑他们使用的底层基础设施的所有故障模式,并考虑调度系统的运维人员如何配置补救策略,同时协助租户系统的所有者在对租户系统进行故障排除期间尽可能保持租户系统的稳定。