每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/
作者的大部分职业生涯都在构建系统软件,加入AWS之前,他主要专注于网络和安全领域。大约13年前,他踏入AWS,进入了一个全新的领域——存储。即使在那个时候,AWS的规模已经远远超过了他之前所做的任何工作,但他过去掌握的许多技术依然适用——将问题分解为基本原理,并通过逐步迭代来解决问题、提高性能。
如果现在看看AWS的服务,会发现已经有了一套成熟的核心构建模块,但事情并非总是如此。EBS(弹性块存储)在2008年8月20日推出,比EC2的测试版发布晚了近两年,当时的想法很简单,就是为EC2实例提供网络附加块存储。团队中只有一两个存储专家和一些分布式系统人员,主要依赖于扎实的计算机系统和网络知识。回头来看,如果当时知道自己还缺少多少知识,可能连这个项目都不会启动!
自从他加入EBS团队以来,有幸见证了EBS从使用共享硬盘驱动器(HDD)的产品,演变成如今能够为单个EC2实例提供数十万IOPS的服务。这个变化令人惊叹,因为现在单个实例能获得的IOPS甚至比早期HDD时代的整个可用区(AZ)的IOPS还多。更惊人的是,今天的EBS每天在分布式SSD集群上执行超过140万亿次操作。不过,这一切并不是一夜之间完成的,也不是通过某个重大改变实现的,甚至也不可能完美无缺。他刚加入EBS团队时,最初负责EBS客户端软件,这个软件负责将实例的IO请求转换为EBS存储操作。从那时起,他几乎参与了EBS的每个组件的工作,并为能够如此直接地参与EBS的发展感到欣喜。
EBS作为一个存储系统有其独特之处,主要因为它的主要工作负载是作为EC2实例的系统磁盘,这来源于过去数据中心服务器中的硬盘。许多存储服务将数据的持久性作为其主要设计目标,并愿意为此牺牲性能或可用性。但EBS的客户不仅关心持久性,还非常在意EBS卷的性能和可用性。EBS与EC2紧密相连,因此EBS卷的性能和可用性几乎直接影响到EC2的整体体验,进而影响使用EC2构建的应用程序和服务的运行体验。EBS的故事就是一个理解并改进大型分布式系统性能的故事,这个系统从顶部的客户操作系统一直延伸到底层的定制SSD设计。在接下来的分享中,他将讲述团队的这一旅程,其中包含的一些宝贵教训或许对其他系统也有启发。毕竟,系统性能优化是一个复杂且极具挑战性的领域,涉及多个领域的专业知识。
在深入探讨之前,先回顾一下计算机系统与存储设备之间的交互方式。多年过去,存储设备连接到总线,总线再连接到CPU的高层原理并没有改变。CPU排队处理的请求会通过总线传输到存储设备,而存储设备要么从CPU内存中检索数据并最终将其放到持久存储介质上,要么从持久存储介质上检索数据并将其传输到CPU的内存中。
可以把这类操作类比成去银行办理业务。你走进银行存钱,但首先必须排队,等待办理业务的银行柜员。在理想情况下,客户到达银行的速度刚好和处理请求的速度一致,这样你就无需排队。但现实世界并不完美,它是异步的。更有可能的是,一批客户同时到达银行,比如他们可能乘坐同一辆电车或火车。这样一来,一部分客户就需要等待前面的人完成交易。
队列的存在不可避免地会影响客户的体验,虽然平均等待时间(延迟)可能看起来尚可,但队列中的第一个人体验最好,而最后一个人则要承受更长的等待时间。银行可以采取多种方式改善客户体验,比如增加柜员以并行处理更多请求,或是重新安排柜员的工作流程,以减少每个交易所需的时间,从而降低总等待时间和平均等待时间。也可以为不同需求的客户创建不同的队列,以降低整体排队时间。不过,这些改善措施都意味着额外的成本,例如为应对可能永远不会发生的高峰时段而雇佣更多的柜员,或者为了创建额外的队列而增加更多的营业面积。尽管如此,除非有无限的资源,否则队列依然是吸收高峰负载的必要手段。
在网络存储系统中,系统中有多个队列,涉及从操作系统内核到存储适配器的队列、主机存储适配器到存储网络的队列、目标存储适配器到存储介质的队列。在传统的网络存储系统中,不同组件可能来自不同供应商,它们对队列的处理方式各有不同。你可能使用的是专用的无损网络(如光纤通道),也可能是通过TCP传输的iSCSI或NFS协议,无论是使用操作系统的网络堆栈,还是定制驱动程序。调整存储网络往往需要专业知识,这与优化应用程序或存储介质的技能不同。
EBS在2008年首次构建时,市场上大部分存储介质还是硬盘,服务的延迟主要受到硬盘介质的限制。硬盘的IOPS性能几十年来一直相对稳定,约为120-150次每秒,而平均IO延迟为6-8毫秒。最大的问题是,由于排队和命令重新排序,硬盘的尾部延迟很容易飙升到几百毫秒。
早期团队意识到,要获得合理的性能,必须将客户工作负载分散到多个磁盘上。虽然这种做法有助于降低高峰延迟,但也导致了性能的不一致性,从而影响了更多客户。AWS意识到要提供高质量的客户体验,必须彻底解决这个问题,专注于避免“噪音邻居”效应。
随着AWS的发展,团队意识到,必须无情地专注于提供高质量的客户体验,这意味着要实现强大的性能隔离,以避免“噪音邻居”干扰其他客户的工作负载。AWS的规模带来了许多复杂的挑战,然而,令人惊讶的是,一旦深入理解系统,解决方案往往非常简单,并且由于系统规模的巨大,这些解决方案会产生巨大的影响。团队通过更改驱动程序的调度算法并将客户工作负载均衡到更多的磁盘上,取得了一些小的增量改进,但这些改进还不足以彻底消除“噪音邻居”问题。客户的工作负载太过不可预测,团队需要探索全新的解决方案。
2011年作者加入AWS时,固态硬盘(SSD)开始进入主流,并且它们的容量已经开始让团队觉得有吸引力。SSD不再需要像HDD那样依赖机械臂来读取数据——随机请求几乎和顺序请求一样快,而且控制器和NAND芯片之间有多个通道可以快速获取数据。换个比喻,使用SSD代替HDD就像是把银行变成了一个足球场大小的建筑,并配备了能以极快速度处理交易的超级员工。一年后,团队开始使用SSD,并从此再也没有回头。
团队从一个小但意义重大的里程碑开始:构建了一种基于SSD的新存储服务器类型,并推出了一种新的EBS卷类型,称为Provisioned IOPS。推出新卷类型并不容易,而且这也限制了能够利用这种新技术的工作负载。但对于EBS来说,这意味着性能的显著提升,不过并没有完全达到团队的预期。
起初,团队以为只要用SSD替换HDD,几乎所有的问题都能解决,确实,SSD解决了很多由硬盘机械特性带来的问题。然而,出乎意料的是,系统的性能并没有如预期般大幅提升,“噪音邻居”问题也并没有自动消失。团队必须将注意力转向系统的其他部分——网络和软件堆栈——这是SSD提升后突显出来的新瓶颈。
即便如此,团队仍在2012年8月发布了Provisioned IOPS卷,性能提升显著,最大IOPS达到了1000,比现有的EBS标准卷高出10倍,平均延迟为2-3毫秒,提升了5-10倍,并且极大地改善了尾部延迟控制。客户对这个新卷感到非常兴奋,开始基于它构建关键业务应用程序。但团队并未因此满足,他们意识到,性能工程才刚刚开始,而要做到这一点,首先需要测量系统性能。
到2012年,EBS的历史已经积累了一些基础的遥测数据,但还远远不够。要知道修复哪些问题,首先需要知道系统的瓶颈在哪里,并根据修复的难度和收益来进行优先级排序。团队的第一步是为每个子系统中的每一个IO操作进行仪表化,包括客户端发起器、网络堆栈、存储持久性引擎以及操作系统。在监控客户工作负载的同时,团队还建立了一套连续运行的基准测试,以便监控更改的影响——无论是正面还是负面——并在已知的工作负载下进行监测。
通过新的遥测系统,团队确定了几个需要初步投资的主要领域。首先,需要减少整个系统中的队列数量。此外,Xen hypervisor在EC2中表现良好,但作为一个通用的hypervisor,它的设计目标和EC2的需求有所不同,功能过于复杂。团队认为通过投入资源,可以简化hypervisor中的IO路径,从而提高性能。再者,需要优化网络软件,核心持久性引擎则需要进行大量组织和代码优化,包括磁盘上的数据布局、缓存行优化以及全面采用异步编程模型。
在AWS的一个非常一致的经验教训是,系统性能问题几乎总是跨越了硬件和软件堆栈的多个层面。尽管“全栈工程师”这一理想值得推崇,但在深度和复杂的系统中,通常更有价值的是创建由各领域专家组成的协作团队,这些专家能够跨越整个堆栈并在他们各自的深度领域中展开创造性工作。
此时,团队已经有了专门负责存储服务器和客户端的团队,因此可以并行专注于这两个领域。此外,还得到了EC2 hypervisor工程师的帮助,成立了跨AWS的网络性能协作小组。团队开始构建一份既有短期战术修复又有长期架构变更的蓝图。
在设计组织结构时,团队采用了“分而治之”的方法,将开发团队拆分为小团队,分别专注于数据复制、持久性和快照加载等特定领域。
团队通过“分而治之”的方法,将原本单一的开发团队拆分为小团队,分别专注于特定领域,如数据复制、持久性和快照加载等。每个团队都集中解决他们所面临的独特挑战,将性能优化任务分解为更小的部分。这些团队能够独立进行迭代并提交更改,这得益于团队建立的严格测试流程。为了让客户不断受益,团队制定了蓝图,并开始逐步拆分组件,同时部署增量更新。
增量交付的最大好处是可以在进行下一次更改前观察其影响。如果某项更改没有达到预期,团队可以轻松撤销并尝试其他方向。例如,2013年时,团队根本无法预见到亚马逊有一天会自己制造SSD,并且建立一个为EBS量身定制的技术栈。
质疑现有假设是推动每一层系统改进的关键。
团队从软件虚拟化开始。在2017年底之前,所有的EC2实例都运行在Xen hypervisor上。在Xen架构中,虚拟设备使用一个环形队列来让客户实例与驱动程序域(dom0)共享信息,以进行IO操作等设备模拟。EBS客户端作为一个内核块设备运行在dom0中。如果跟踪一个IO请求从实例发出直至离开EC2主机的路径,团队发现沿途有多个队列:实例的块设备队列、Xen环形队列、dom0内核块设备队列以及EBS客户端的网络队列。在大多数系统中,性能问题是多方面积累的,因此将组件单独处理通常是一个有效的做法。
团队编写了几个“回环”设备,以便隔离每个队列,评估Xen环形队列、dom0块设备栈和网络的影响。令人惊讶的是,即使在dom0设备驱动程序中几乎没有延迟,当多个实例尝试执行IO操作时,它们之间的交互会导致整个系统的有效吞吐量下降。团队发现了另一个“噪音邻居”问题!更糟糕的是,EC2的块设备队列和队列条目的默认设置实际上是基于很多年前Xen开发团队针对当时有限的存储硬件所设定的。这个设置每个主机只有64个IO请求并发,远远不能满足最苛刻的工作负载需求。
虽然团队修复了软件虚拟化中的主要问题,但这还远远不够。在2013年,团队已经开始开发第一个Nitro卸载卡,专门用于网络处理。这款卡片把VPC(虚拟私有云)的数据包处理从Xen dom0内核转移到了专用的硬件管道中,不再需要占用客户实例的CPU资源来处理网络流量。相反,Xen通过虚拟PCI设备直接传递给实例。这一举措大幅降低了延迟并提高了效率,因此团队决定对EBS存储也采取类似措施。
通过将更多处理工作转移到硬件上,团队消除了hypervisor中的多个操作系统队列,即使当时还没有准备好将设备直接传递给实例。不过,即便没有完全直通,利用硬件的中断处理能力,hypervisor所需的中断服务时间也大大减少。这第二张Nitro卡还具备处理EBS加密卷的硬件能力,几乎没有影响EBS卷的性能。此外,利用硬件进行加密意味着密钥材料可以与hypervisor分离,从而进一步保护客户数据。
将EBS迁移到Nitro平台是一项巨大的胜利,但几乎立刻又将压力转移到了网络本身。表面上看,问题似乎很简单,团队只需要使用最新的数据中心TCP优化参数调整线路协议,并选择最佳的拥塞控制算法。然而,一些变化正在悄悄影响团队的计划:AWS正在试验不同的数据中心布线拓扑,此外,原本作为单一数据中心的可用区(AZ)规模正在扩大,跨越了最初的物理边界。团队的调优工作确实带来了一些好处,比如在存储请求中添加少量随机延迟,反而减少了平均延迟和尾部延迟,这是由于网络上的平滑效应造成的。然而,随着系统性能和规模的不断提高,这些改动最终都成为了临时措施,团队必须持续进行测量和监控,确保性能不会退化。
团队认识到,需要一种比TCP更好的解决方案,于是从2014年开始为可扩展可靠数据报(SRD)协议奠定基础。这项协议旨在为存储提供更强的容错能力,能够绕过故障并轻松进行硬件卸载。通过专注于数据中心网络设计而非互联网的通用性,团队成功开发了一种允许IO请求乱序执行的协议,从而不再需要TCP那种严格的有序交付机制。SRD不仅提升了存储的性能,还被用于网络中。例如,在Elastic Network Adapter (ENA) Express中,SRD通过利用多个网络路径并减少网络设备中的队列溢出,提升了TCP栈的性能。
性能提升从来不是单一焦点的问题,而是通过持续质疑假设、测量和理解系统,并将精力转移到最具潜力的机会上的学科。
团队并不满足于仅仅让少数卷和客户享受更好的性能,他们希望让所有客户都能从SSD的优势中受益。然而,规模的挑战让事情变得困难。EBS有数千台存储服务器,运行着数百万个非预置IOPS的客户卷。这些卷中的一些甚至至今仍然存在。完全淘汰所有硬件并进行替换,成本将非常高昂。
团队面临的挑战是如何在不干扰服务器冷却气流的情况下,找到放置SSD的位置。幸运的是,SSD通常较小且轻便,但不能让它们在机箱中随意摆放。经过几次试验和错误之后,在材料科学家的帮助下,团队找到了耐热的工业级魔术贴,并用它将这些SSD固定在服务器上,同时还能便于在服务器剩余生命周期内对SSD进行维护。
最终,团队在2013年内手动为每台服务器安装了一块SSD,并做了一个小改动:将新的写操作暂存在SSD上,这样可以立即返回完成信号给客户应用程序,然后再将数据异步地写入较慢的硬盘。这一切都是在不打扰客户的情况下完成的,团队就像是在空中将螺旋桨飞机改造成喷气式飞机。这一切的关键在于,团队从一开始就设计了能够无中断维护的系统,能够将EBS卷迁移到新的存储服务器,更新软件或重建空服务器。
这种迁移客户卷到新存储服务器的能力在EBS的历史上多次派上用场,无论是为了引入新的、更高效的磁盘数据结构,还是为了用新硬件替换旧硬件。有些EBS卷自2008年推出的头几个月起就一直在使用。这些卷在更新和重建过程中,可能已经经历了数百台不同的服务器和多代硬件的更替,但这一切都没有影响这些卷上的工作负载。
最后,再分享一个在这个过程中发生的个人故事。在加入亚马逊之前,作者的大部分职业生涯都在早期初创公司或类似的小公司文化中度过。他曾经构建托管服务,甚至出于必要构建分布式系统,但从未参与过像EBS这样庞大的项目,无论是在技术上还是组织规模上。过去,他习惯于自己独立解决问题,或者与一两位同样积极的工程师合作。
作者非常喜欢深入挖掘问题,直到彻底解决为止。但有一个关键时刻,一位他信任的同事指出,他正在成为组织的性能瓶颈。作为一个对系统了如指掌的工程师,他对EBS的方方面面都非常关心,结果他卷入了每个升级事件,并且想要审查每一个提交和每一个设计更改。为了成功,他意识到必须学会“扩展自己”,而不仅仅依靠责任心和行动偏好。
这促使他开始在代码之外进行更多的实验。他知道自己在与其他聪明的工程师合作,但也意识到需要退后一步,思考如何让他们更高效运作。他最喜欢的一种工具是“同行调试”。他记得有一次和几位工程师在休息室里,投影出代码和几个终端。突然间,一位工程师喊道:“呃,这绝对不对!”就这样,团队发现了一个困扰已久的问题。设计上的疏漏虽然通常不会引发问题,但偶尔会导致请求响应变慢,修复这个问题后,消除了一个造成系统抖动
的根源。团队并非总是使用这种技术,但巧妙的是,在遇到棘手问题时,能够结合大家的系统知识来解决问题。
通过这一切,作者意识到,赋予他人权力,允许他们安全地进行实验,往往会带来比预期更好的结果。从那时起,他将很大一部分精力投入到如何消除阻碍,但同时保留必要的护栏,并推动工程师们走出他们的舒适区。工程领导力中蕴含着心理学,这是他之前未曾领悟的。他从未想到,职业生涯中最有成就感的部分之一竟然是鼓励和培养他人,看着他们独立解决问题,并最重要的是,与他们一起庆祝胜利!
回顾团队的起点,他们知道自己可以做得更好,但并不确定能做得多好。团队选择了逐步改进的方法,而不是一刀切的变革。这种方法使团队能够更快地为客户提供价值,并随着对客户需求的不断了解进行调整。团队成功地将EBS延迟体验从最初每次IO操作平均超过10毫秒改善到如今最高性能的io2 Block Express卷,能够实现一致的亚毫秒级IO操作。所有这些改进都没有让服务下线,也没有重构整个架构。
当然,团队知道这还不是终点。客户的需求永无止境,而这种挑战正是激励团队不断创新和迭代的动力。