核心内容
EBS于2008年8月20日推出,最初基于共享HDD构建。 从HDD过渡到SSD,大幅提升了性能,单个EC2实例可获得的IOPS从整个可用区的总量增长到数十万。 目前EBS每天可处理超过140万亿次操作,跨分布式SSD集群。
队列理论应用: 理解和优化系统中的多个队列,如操作系统内核、存储适配器、存储介质等之间的队列。 通过增加处理单元、优化工作流程等方式改善队列性能。 从HDD到SSD的转变: HDD的机械特性限制了其性能,IOPS约为120-150,平均IO延迟6-8ms。 SSD消除了物理寻道时间,显著提升了随机访问性能。 持续测量与优化: 构建全面的遥测系统,在多个子系统中监控每个IO。 开发持续运行的金丝雀测试,监控变更影响。 系统重构: 减少整个系统中的队列数量。 优化Xen虚拟机管理程序中的IO路径。 改进网络软件和核心持久性引擎。 组织结构调整: 采用“分而治之”的方法,将团队分成专注于特定领域的小组。 实现独立迭代和部署变更的能力。
设定长期目标,但不要害怕渐进式改进。 如果无法测量,就无法管理——强调全面监控的重要性。 始终质疑假设——挑战现有观念导致了堆栈各个部分的改进。 跨团队协作的重要性——性能问题通常跨越硬件和软件堆栈的多个层面。 增量交付的价值——允许观察每个变更的影响并根据需要调整方向。
-----
Marc Olson已在EBS(Elastic Block Store)项目中耕耘超过十年。在这段时间里,他亲历并推动了EBS从一个依赖共享驱动器的简单块存储服务,发展成为一个每日执行超过140万亿次操作的大规模网络存储系统。
在本文中,Marc以独特的内部视角,生动地描述了EBS的演进历程。他分享了在队列理论、全方位监控的重要性,以及渐进式改进与颠覆性创新的价值等方面的宝贵经验。更为重要的是,他强调了约束条件往往能激发创新解决方案。这篇文章深入探讨了作为AWS核心服务之一的EBS,如何随着客户需求的变化(以及客户自身创新步伐的加快)而不断发展的过程。
-----
我的职业生涯大部分时间都致力于构建系统软件。在加入AWS之前,我专注于网络和安全领域的工作。大约13年前,我加入了AWS,这引领我进入了一个全新的领域,即存储,同时也带来了新的挑战。尽管AWS的规模在当时已经远超我之前的工作环境,但我发现我之前掌握的很多技术依然适用,例如,我可以将复杂的问题简化为基本原理,并通过连续不断的迭代来逐步解决问题,同时提升性能。
如果你今天回顾AWS的服务,你会发现它们是一套成熟的核心构建块,但情况并非一直如此。EBS于2008年8月20日发布,比EC2测试版发布晚了近两年,它的初衷是为EC2实例提供网络附加块存储。当时我们有一两个存储专家,一些分布式系统人员,以及扎实的计算机系统和网络知识。这能有多难呢?现在回想起来,如果当时我们知道自己有多么无知,可能根本不会启动这个项目!
自从我加入EBS团队以来,我有幸成为EBS从使用共享HDD构建的产品,发展到能够为单个EC2实例提供数十万IOPS能力的演变过程中的一部分。回想起来,这真是令人惊叹,因为今天的EBS能够为单个实例提供的IOPS,比早期基于HDD的整个AZ能够提供的还要多。更为惊人的是,如今的EBS在整个分布式SSD集群中每天交付超过140万亿次操作。但我们绝不是一夜之间,或者通过一次性大爆发,甚至完美地做到这一点的。当我刚开始在EBS团队工作时,我主要负责EBS客户端,这是负责将实例IO请求转换为EBS存储操作的软件组件。从那时起,我几乎参与了EBS的每个组件的开发,并且很高兴能够如此直接地参与到EBS的演变和成长中。
作为一个存储系统,EBS有点特别。它的独特性在于我们的主要工作负载是为EC2实例提供系统盘,这种需求源自于物理数据中心服务器中曾经内置的硬盘。许多存储服务将持久性作为其主要设计目标,并愿意在性能或可用性方面做出让步以保护数据的完整性。EBS客户关心持久性,我们通过io2 Block Express卷和卷快照为他们提供了实现高持久性的基本工具,但他们同样非常关注EBS卷的性能和可用性。EBS作为EC2的一个存储原语,与EC2的性能和可用性紧密相关,而这又几乎直接影响到使用EC2构建的应用程序和服务的运行体验。EBS的发展历程就是理解和改进一个跨越从顶层的客户操作系统到底层的定制SSD设计的非常大规模分布式系统性能的历程。在这篇文章中,我想向你介绍我们所经历的旅程,其中包括一些可能对你的系统也适用的难忘教训。毕竟,系统性能是一个复杂且极具挑战性的领域,它跨越了多个领域中的复杂语言。
排队理论简介
在深入讨论之前,我们先回顾一下计算机系统与存储的交互方式。多年来,高层次的基本原理始终没有改变。存储设备通过总线连接到CPU。CPU将请求依次排列,并通过总线传递给设备。存储设备要么从CPU内存中读取数据,然后将其存储到持久化介质上,要么从持久化介质中读取数据,再将其传输到CPU的内存中。
使用直连硬盘的计算机系统架构
你可以将其类比为银行。当你走进银行进行存款时,首先需要排队,才能与银行柜员交谈,完成交易。在一个理想的世界中,进入银行的顾客数量与柜员处理请求的速度完全匹配,你永远不需要排队。但现实世界并不完美,现实是异步的。更可能的情况是,一群人同时进入银行,也许他们是乘坐同一辆电车或火车到达的。当一群人同时进入银行时,其中一些人必须等待柜员处理前面的交易。
当我们考虑完成每笔交易所需的时间以及清空队列的时间时,所有顾客的平均排队等待时间(延迟)可能看起来是可以接受的,但排在队列最前面的顾客体验最佳,而最后一位顾客的延迟则要长得多。银行可以采取多种措施来改善所有顾客的体验。银行可以增加更多的柜员以并行处理更多请求,可以重新安排柜员的工作流程以缩短每笔交易的时间,从而降低总时间和平均时间,或者可以为对延迟不敏感的顾客创建不同的队列,或合并可能更快完成的交易以保持队列短小。但每个选项都伴随着额外的成本——可能需要为一个可能永远不会发生的高峰期雇佣更多的柜员,或增加更多的空间来创建单独的队列。虽然不完美,但除非你有无限的资源,队列是吸收峰值负载所必需的。
简化的EC2和EBS排队示意图(约2012年)
在网络存储系统中,我们在堆栈中有多个队列,包括操作系统内核与存储适配器之间的队列、主机存储适配器到存储网络的队列、目标存储适配器的队列以及存储介质的队列。在传统的网络存储系统中,每个组件可能来自不同的供应商,他们对队列服务的方式也各不相同。你可能在使用专用的、无损的网络结构(如光纤通道),或者在TCP上使用iSCSI或NFS,无论是使用操作系统的网络堆栈,还是自定义驱动程序。在任何情况下,调优存储网络通常需要专业知识,与调优应用程序或存储介质分开进行。
当我们在2008年首次构建EBS时,存储市场主要以HDD为主,我们服务的延迟主要受这种存储介质的延迟影响。去年,Andy Warfield深入探讨了HDD背后引人入胜的机械工程。作为一名工程师,我仍然对硬盘驱动器的各种设计感到惊叹,但归根结底,它们是机械设备,物理定律限制了它们的性能。硬盘内部有一叠高速旋转的硬盘,这些硬盘上有包含数据的轨道。相对于轨道的大小(小于100纳米),有一只巨大的机械臂来回摆动,以找到正确的轨道进行数据读写。由于涉及的物理因素,硬盘的IOPS性能在过去几十年中相对保持在120-150次操作每秒,或6-8毫秒的平均IO延迟。硬盘的一个最大挑战是尾部延迟会由于队列和命令重新排序的影响,轻易地漂移到数百毫秒。
由于端到端的EBS延迟主要由HDD主导并以几十毫秒计算,我们不必太担心网络延迟。即使是早期的数据中心网络也足够强大,可以满足用户对延迟和吞吐量的期望。网络上增加的几十微秒延迟只占整体延迟的一小部分。
除此之外,硬盘性能也会因队列中的其他事务而变化。随机分布在介质上的小请求比相邻的大请求需要更长的时间来查找和访问。这种随机性能导致行为极不一致。我们很早就知道,需要将客户分散到多个硬盘上以实现合理的性能。这有一个好处,它降低了最热工作负载的峰值异常延迟,但不幸的是,这也将不一致的行为扩散到了许多客户。
当一个工作负载影响另一个工作负载时,我们称之为“吵闹的邻居”。吵闹的邻居成为了业务的关键问题。随着AWS的发展,我们认识到必须无情地专注于高质量的客户体验,而这不可避免地意味着我们需要实现强大的性能隔离,以避免吵闹的邻居干扰其他客户的工作负载。
在AWS的规模下,我们经常遇到的挑战因系统的规模和广度以及我们对保持客户体验的关注而变得艰难而复杂。令人惊讶的是,一旦深入理解系统,解决方案往往相当简单,由于规模效应,其影响巨大。我们通过改变驱动器的调度算法并将客户工作负载均衡到更多的硬盘上,取得了一些改进。但所有这些只带来了微小的增量提升。我们并没有真正突破吵闹的邻居问题。客户的工作负载过于不可预测,难以实现我们所知的他们所需的一致性。我们需要探索完全不同的解决方案。
设定长期目标,但不要害怕逐步改进
大约在我2011年加入AWS的时期,SSD开始逐渐占据主流地位,其尺寸也愈发符合我们的需求。在SSD内部,不存在物理臂的移动来检索数据,因此随机访问请求几乎能与顺序请求一样迅速完成。此外,SSD的控制器与NAND芯片之间设计了多条通道,以加速数据的访问过程。若以之前的银行系统作为类比,将HDD替换为SSD,就如同构建了一个足球场大小的银行,并配备了能以惊人速度处理交易的超级能力者。自那之后的一年,我们开始广泛采用SSD,并且这一决策至今未被质疑或改变。
我们从一个小但重要的里程碑开始:我们构建了一种基于SSD的新存储服务器类型,并推出了一种新的EBS卷类型,称为Provisioned IOPS。推出一种新的卷类型并不是一件小事,它也限制了可以利用它的工作负载。对于EBS来说,虽然立即见到了改善,但还没有达到我们的预期。
我们认为,仅仅用SSD替换HDD就能解决几乎所有的问题,确实解决了来自硬盘机械部分的问题。但令我们惊讶的是,系统的改善远没有我们预期的那么显著,吵闹的邻居问题也没有自动得到解决。我们不得不将注意力转向我们的堆栈其他部分——网络和软件——这些部分被改进的存储介质突显了出来。
尽管我们需要做这些改变,我们还是在2012年8月推出了最大支持1000 IOPS的EBS卷,比现有的EBS标准卷性能提升了10倍,平均延迟约为2-3毫秒,比之前提高了5-10倍,并显著改善了异常情况的控制。我们的客户对能够在上面构建其关键任务应用程序的EBS卷感到兴奋,但我们仍然不满足,并意识到系统中的性能工程工作才刚刚开始。但要做到这一点,我们必须对系统进行测量。
如果无法衡量,就无法管理
在EBS历史上的这一点(2012年),我们只有基础的遥测工具。为了知道需要修复什么,我们必须了解什么是故障,然后根据工作量和收益优先处理这些修复。我们的第一步是建立一种方法,在每个子系统的多个点上对每个IO进行仪表化——包括我们的客户端发起器、网络栈、存储耐久性引擎以及操作系统。除了监控客户工作负载外,我们还建立了一组持续运行的金丝雀测试,允许我们在已知工作负载下监控更改的影响,无论是积极的还是负面的。
通过新的遥测工具,我们确定了几个主要的初步投资领域。我们知道我们需要减少整个系统中的队列数量。此外,虽然Xen虚拟机管理程序在EC2中表现良好,但作为通用虚拟机管理程序,它具有不同的设计目标和许多我们在EC2中不需要的功能。我们猜测,通过一些投资,我们可以简化虚拟机管理程序中的IO路径,从而提高性能。此外,我们需要优化网络软件,并且在核心耐久性引擎中需要进行大量的组织和代码工作,包括磁盘数据布局、缓存行优化,以及全面采用异步编程模型。
在AWS中,一个非常一致的教训是,系统性能问题几乎普遍涉及到硬件和软件堆栈中的多个层级,但即使是优秀的工程师通常也会集中关注特定的狭窄领域。虽然被高度推崇的“全栈工程师”理想很有价值,但在深度复杂的系统中,创建专家团队以便在整个堆栈及各自领域进行深入协作和创造往往更为重要。
此时,我们已经有了分别负责存储服务器和客户端的独立团队,因此可以同时关注这两个领域。我们还邀请了EC2虚拟机管理程序工程师,组成了跨AWS的网络性能专家组。我们开始构建既有短期战术修复,又有长期架构变更的蓝图。
分而治之
使用Physalia从IO路径中移除控制层
在我还是本科生的时候,虽然我喜欢大部分课程,但也有几门课程我有着复杂的爱恨关系。我们大学的“算法”课程是针对本科生和研究生的研究生课程。我发现这门课程非常严峻,但最终我爱上了这个主题,《算法导论》(通常称为CLR)是我保留的为数不多的教科书之一,我仍然偶尔参考它。我在加入亚马逊之前并没有意识到,事后看来显而易见的是,你可以像设计软件系统一样设计一个组织。不同的算法在组织功能方面有不同的优缺点。在实际操作中,亚马逊选择了分而治之的方法,并保持团队小而专注于具有明确定义的API的自包含组件。
这种方法在零售网站和控制平面系统的组件上应用得很好,但在如何构建高性能数据平面时则不那么直观,同时还要提高性能。在EBS存储服务器中,我们将一个整体开发团队重组为专注于特定领域的小团队,如数据复制、耐久性和快照水化。每个团队专注于他们独特的挑战,将性能优化分解为更小的任务。这些团队能够独立迭代和提交更改——这得益于我们逐步建立起来的严格测试。对我们来说,持续推进对客户很重要,因此我们从制定一个目标蓝图开始,然后开始分离组件并逐步进行更改。
渐进交付的最大优点是你可以在进行下一个更改之前观察其影响。如果某个更改未达到预期效果,那么很容易撤销并改变方向。在我们的案例中,我们在2013年制定的蓝图最终与今天的EBS完全不同,但它为我们提供了一个前进的方向。例如,当时我们绝对没有想到亚马逊有一天会建造自己的SSD,技术栈可以专门针对EBS的需求进行定制。
总是质疑你的假设!
挑战我们的假设使得我们在每一个堆栈部分都取得了改进。
我们从软件虚拟化开始。直到2017年底,所有EC2实例都运行在Xen虚拟机管理程序上。在Xen中,存在一个环形队列设置,允许来宾实例或域与特权驱动域(dom0)共享信息,以进行IO和其他模拟设备的操作。EBS客户端在dom0中作为内核块设备运行。如果我们跟踪一个实例的IO请求,仅在离开EC2主机时,就有许多队列:实例块设备队列、Xen环、dom0内核块设备队列和EBS客户端网络队列。在大多数系统中,性能问题是复合的,因此集中关注隔离组件是有帮助的。
我们做的第一件事是编写几个“回环”设备,以便我们能够隔离每个队列,评估Xen环、dom0块设备堆栈和网络的影响。我们几乎立即发现,尽管dom0设备驱动程序几乎没有延迟,当多个实例尝试驱动IO时,它们之间的相互作用会使整个系统的有效吞吐量减慢。我们发现了另一个“吵闹的邻居”!令人尴尬的是,我们在启动EC2时使用了Xen默认的块设备队列数量和队列条目设置,这些设置是在多年前根据剑桥实验室用于构建Xen的有限存储硬件确定的。这是非常意外的,特别是当我们意识到它将整个主机的IO未决请求限制为仅64个,而不是每个设备——这对于我们最苛刻的工作负载显然不够。
我们解决了软件虚拟化的主要问题,但这还不够。2013年,我们正在开发首个专用于网络的Nitro卸载卡。通过这张卡,我们将VPC(我们的软件定义网络)的处理从Xen dom0内核移到一个专用的硬件管道中。通过将数据包处理数据平面从虚拟机管理程序中隔离出来,我们不再需要从客户实例中窃取CPU周期来驱动网络流量。相反,我们利用Xen的能力将虚拟PCI设备直接传递给实例。
这对延迟和效率来说是一个巨大的胜利,因此我们决定对EBS存储做同样的事情。通过将更多的处理移到硬件中,我们去除了虚拟机管理程序中的几个操作系统队列,即使我们还没有准备好直接将设备传递给实例。即使没有直通,通过卸载更多的中断驱动工作,虚拟机管理程序花在服务请求上的时间减少了——硬件本身有专门的中断处理功能。第二张Nitro卡还具备处理EBS加密卷的硬件能力,对EBS卷性能没有影响。利用我们的硬件进行加密也意味着加密密钥材料与虚拟机管理程序分离,进一步保护客户数据。
实验网络调优以提高吞吐量和降低延迟
将EBS迁移到Nitro是一个巨大的胜利,但几乎立即将开销转移到了网络本身。这里的问题看似简单。我们只需要使用最新的和最先进的数据中心TCP调优参数来调整我们的网络协议,同时选择最佳的拥塞控制算法。有几个因素对我们不利:AWS正在尝试不同的数据中心布线拓扑,而我们的可用区(AZs),曾经是一个单一的数据中心,现在正在超越这些边界。我们的调优是有益的,如上例所示,向存储服务器请求添加少量随机延迟会出乎意料地降低平均延迟和异常值,因为它对网络的平滑效应。这些更改最终寿命很短,因为我们不断提高系统的性能和规模,我们必须持续测量和监控,以确保不出现退步。
知道我们需要比TCP更好的东西,2014年我们开始为可扩展的关联图(SRD)奠定基础,提出了“针对弹性和可扩展HPC的云优化传输协议”。我们早期设定了一些要求,包括一个可以改善我们恢复能力和绕过故障的协议,并且我们希望它能够容易地卸载到硬件中。在调查过程中,我们做出了两个关键观察:1/我们不需要为一般互联网设计,而可以专注于我们的数据中心网络设计;2/在存储中,正在传输的IO请求可以重新排序。我们不需要支付TCP严格按顺序交付保证的代价,而可以将不同的请求发送到不同的网络路径,并在到达时执行它们。任何障碍可以在客户端处理,然后再发送到网络上。我们最终得到的是一个不仅对存储有用的协议,还对网络有用。在Elastic Network Adapter(ENA)Express中使用SRD,可以提高客机TCP堆栈的性能。SRD通过利用多个网络路径和减少中间网络设备中的溢出和队列,提高了网络的利用率。
性能改进从来不是单一焦点的问题。这是一种持续质疑假设、测量和理解,并将重点转移到最有意义的机会上的学科。
约束催生创新
我们对仅有少量卷和客户享有更好性能的现状感到不满意。我们希望将SSD的好处带给每个人。这是一个规模使事情变得困难的领域。我们拥有数千台存储服务器,运行着数百万个未预配IOPS的客户卷。其中一些卷至今仍在使用。如果要丢弃所有这些硬件并进行替换,将是一笔昂贵的开销。
机箱中有空闲空间,但唯一不干扰冷却气流的地方是在主板和风扇之间。SSD的优点是通常体积小且重量轻,但我们不能让它们在机箱内松散摆放。经过一些试验和材料科学家的帮助,我们找到了一种耐热的工业强度魔术贴,这也让我们可以在服务器的剩余使用寿命内对这些SSD进行维护。
是的,我们手动将一个SSD安装到每台服务器中!
2013年,在几个月的时间里,EBS成功地在数千台服务器中每台都安装了一个SSD。我们对软件进行了小幅修改,将新的写入操作分配到SSD上,从而允许我们将完成情况返回给应用程序,然后异步将写入操作刷新到较慢的硬盘上。我们在这一过程中没有对客户造成干扰——我们在飞行中将螺旋桨飞机改装成喷气式飞机。这一切之所以可能,是因为我们从一开始就设计了具有无干扰维护事件的系统。我们可以将EBS卷重新定向到新的存储服务器,并根据需要更新软件或重建空闲服务器。
这种将客户卷迁移到新存储服务器的能力在EBS的发展历史中多次派上用场,因为我们发现了新的、更高效的磁盘格式数据结构,或者引入了新硬件来替换旧硬件。从2008年EBS启动的最初几个月起仍有一些卷在使用。这些卷可能已经在数百台不同的服务器和多个硬件代际上运行过,我们在更新和重建我们的系统时,这些卷的工作负载没有受到影响。
反思性能与成长
还有一个我想分享的个人经历。在加入Amazon之前,我的大部分职业生涯都在早期创业公司或类似的小公司文化中度过。我曾出于必要构建过托管服务,甚至分布式系统,但从未在EBS这样的规模上工作过,即便是2011年的EBS,无论是在技术上还是组织规模上。我习惯于独自解决问题,或者和一两个同样积极的工程师一起合作。
我非常喜欢深入研究问题并彻底解决它们,但有一个关键时刻,一个我信任的同事指出我成为了组织的性能瓶颈。作为一个已经成长为系统专家的工程师,同时也非常关心EBS的各个方面,我发现自己参与了每一次升级,也想审查每一个提交和每一个提议的设计变更。如果我们要成功,我必须学会如何扩展自己——我不能仅凭拥有和行动偏好来解决这个问题。
这促使了更多的实验,但不是在代码中。我知道自己在和其他聪明的人一起工作,但我也需要退一步,思考如何让他们更有效。我的一个最喜欢的工具是同伴调试。我记得有一次我们在一个休息室里,墙上投射着代码和几个终端。一个工程师喊道:“呃,这不可能是对的!”我们发现了一个困扰了我们一段时间的问题。我们忽略了在关键数据结构上锁定更新的位置和方式。我们的设计通常不会导致问题,但偶尔我们会看到请求响应变慢,解决这个问题消除了一个抖动源。我们并不总是使用这种技术,但有趣的是,当事情变得非常棘手时,我们可以结合我们的共同系统知识。
通过这一切,我意识到,赋权于人们,让他们安全地进行实验,往往会产生超出预期的结果。我从那时起在职业生涯中花了大量时间专注于消除障碍,同时保持保护措施,让工程师走出舒适区。工程领导力中有一部分心理学因素,我之前没有意识到。我从未想到,我职业生涯中最有成就感的部分之一是鼓励和培养他人,见证他们拥有和解决问题,最重要的是与他们一起庆祝胜利!
结论
回顾起步阶段,我们深知有很大的提升空间,但对最终能达到怎样的高度也并不确定。因此,我们选择了循序渐进的迭代改进方式,而不是一次性的大规模变更。这种方法使我们能够更快地为客户创造价值,并根据不断变化的客户工作负载需求及时调整。我们成功地将EBS的延迟体验从平均每次IO操作超过10毫秒,提升至与性能最高的io2 Block Express卷相匹配的一致亚毫秒IO操作。所有这些改进都是在不中断服务的情况下,通过引入全新的架构实现的。
我们明白,这仅仅是一个开始。客户对性能的追求永无止境,正是这种挑战激励着我们不断创新、持续迭代。
Source:Continuous reinvention: A brief history of block storage at AWS;Marc Olson;August 22, 2024
---【本文完】---
近期受欢迎的文章:
更多交流,可加本人微信
(请附中文姓名/公司/关注领域)





