
本文要点:
基于单元的架构可以减少故障的爆炸半径,从而增强系统的韧性。
对于无法忍受停机或停机会严重影响终端用户的系统,基于单元的架构是一个不错的可选方案。
基于单元的架构强制将固定大小的单元作为部署单位,并倾向于采用横向扩展(scale-out)而非纵向扩展(scale-up)的方式,从而增强了微服务的可扩展模型。
基于单元的架构能够使各种组件(可能会是微服务)在范围更广的系统中的位置更加清晰,因为它们是以单元的粒度进行打包和部署的,而不是以应用服务的粒度。
基于单元的架构通过在单元周围运用额外的安全等级,有助于提高分布式系统的安全性。
作为软件开发人员,适应增长(扩展)的能力是我们面临的主要挑战之一。不管你是在小型的初创公司还是在大型的企业,在评估如何交付新产品或特性时,都不可避免地会遇到系统该如何处理不断增加的负载这一问题。
构建和运维现代分布式系统的挑战会随着规模和复杂性的增加而不断增长。在云和企业内部基础设施中,可能会出现意料之外且难以解决的故障,架构组件需要处理这些故障,以提供所需的可用性。
单体、微服务和韧性方面的挑战
几年前,微服务及其相关的架构变得流行起来,因为它们有助于解决单体应用(monorepos)所面临的挑战。
正如 Susan Fowler 在几年前接受InfoQ采访时所提到的,这些应用可能并不支持足够的并发和分区,所以会遇到可扩展性的限制,从而导致性能和稳定性的问题。随着这些单体应用的规模不断增长,它们在本地环境的运行也变得更具挑战性。应用的部署同样变得越来越复杂,这导致开发团队的开发速度越来越慢。
微服务使团队能够单独地开发、部署和扩展服务,从而解决了这些问题。但是,凡事有利也有弊,微服务也面临着自己的挑战。
微服务所面临的挑战之一就是它的粒度非常细,到了单个服务的级别。因此,开发人员并不知道在更广泛的系统中,他们所拥有的各种微服务会用到何处。此外,要明确其他人所拥有的微服务中哪些值得关注,也会更具挑战性。
随着时间的推移,微服务架构变得越来越复杂,这些挑战也会变得越来越突出。除此之外,随着云基础设施的广泛应用,许多公司管理着大量的云资源,从计算到存储,再到网络和支撑服务。这些资源都有可能遭遇故障,从而引发服务或大或小的降级,尽管我们可能已经采用了冗余和故障转移机制,但是如果不采取特殊措施,某些故障模式还是无法完全控制。
基于单元架构的再次兴起
故障隔离相关的挑战并不是什么新鲜的事情,也并非微服务或云计算所特有的。当软件系统为了适应不断增长的负载需求而采用分布式架构时,鉴于其分布式的特点,许多新的故障模式就必须纳入考虑。
基于单元的架构(cell-based architecture)最早出现于面向服务架构(Service-Oriented Architecture,SOA)的时代,它试图管理大型分布式系统内的故障,防止这些故障影响整个系统的可用性。Tumblr、Flickr、Salesforce和Facebook等公司最初实现这种架构的目的是将故障的爆炸半径限制在客户或用户群的一小部分(一个分片)中,在这个过程中会使用一个自包含的单元作为并行化单位来管理基础设施和应用资源,并隔离故障。
首先,基于单元的架构是舱壁模式(bulkhead pattern)的一种实现,这是软件工程从造船工业中借鉴的理念。舱壁是船舶结构中一种不透水的垂直隔板,可以在船体破损时避免海水淹没整艘船。

舱壁保护船舶免受洪水的袭击
多年以来,舱壁模式一直被宣传成现代化架构(尤其是微服务)的关键韧性模式之一。但是,这种模式的采用率一直很低,主要原因是它增加了复杂性,所以大多数公司会优先考虑其他方面。
最近,有些知名公司选择重新审视基于单元的架构方式,以满足其基于微服务的、云托管平台的高可用需求。在经历了 AWS 可用区网络故障导致的部分中断后,Slack 已经将其面向用户的关键服务迁移到基于单元的架构方式。Doordash通过其基于Envoy的服务网格实现了区域感知路由(zone-aware routing),实现了基于 AZ 的单元架构,并降低了跨 AZ 的数据传输成本。随着规模的不断扩大,Roblox也在将其基础设施重新编排为单元,以提高效率和韧性。
这些公司的共同点是,他们都在云或私有数据中心的大型基础设施之上运行微服务架构,并且经历了因为基础设施或应用程序故障的无限爆炸半径而造成的严重中断。为此,他们采用了基于单元的架构,以防止故障造成大面积的中断。
长期以来,亚马逊云科技(Amazon Web Services,AWS)都是基于单元的架构的采用者和传播者,在2018年的年度re:Invent大会上阐述了这一主题,并在2022年再次讨论了该主题。亚马逊云科技在 2023 年 9 月还发布了一份基于单元的架构的白皮书。
基于单元架构的构建基块
整体而言,基于单元的架构由如下三个元素组成:
单元(cell):提供了带有故障边界的自包含基础设施/应用程序栈;负责处理应用程序的工作负载
控制平面(control plane):负责调配资源、部署应用服务、确定路由映射、提供平台可观测性、移动/迁移数据等。
数据平面(data plane):负责根据数据位置和单元的健康情况(由控制平面确定)对流量进行恰当的路由选择
为了提供容错性方面的收益,基于单元的架构以支持单元级别的隔离以及控制平台与数据平面的低耦合为目标。很重要的一点在于,需要确保数据平面可以在没有控制平面的情况下运行,并且不应该直接依赖于控制平面的健康状况。
将单元作为第一级的架构构造
采用基于单元的架构会带来很多有趣的收益。首先,单元在基础设施层面提供了一个故障边界,按照设计,单元实例用来服务特定部分的流量,从而将故障隔离在用户或客户群的一个子集中。不过,它们也提供了将相关的应用服务分组到特定领域集群的可能性,这有助于改善架构和组织结构,促成高内聚和低耦合,并减少工程团队的认知负荷。
对于小型的系统,或者在刚刚着手采用基于单元的架构时,我们完全可以将所有的应用服务放到一个单元中。对于拥有众多应用服务的大型系统,可以使用多个单元按照领域边界来组织架构。这样的方式能够帮助大型组织采纳产品思维,并让系统架构与产品领域及子领域保持一致。这对于由数百个微服务组成的大型微服务系统尤为重要。

基于单元的架构组合了领域和故障隔离边界
从容错的角度来看,单元(或单元实例)是一个完整的、独立的基础设施栈,其中包含了完成业务功能以及为特定流量分段(由单元划分策略所确定)的工作负载提供服务所需的所有资源和应用服务。很重要的一点在于,要尽可能地隔离单元,以便于控制故障。理想情况下,每个单元应该与其他单元独立,不要共享任何状态,也不要共享数据库等依赖。单元之间的通信要尽可能减少,理想情况下,要避免同步的 API 调用,而应该使用异步、消息驱动的数据同步方式。如果 API 交互难以避免,那么必须要经由单元路由器,这样才不会影响基于单元架构的故障隔离特性。
关于单元的部署方案,有很多的考量因素,包括选择使用单个还是多个 DC(数据中心)进行部署,以及如何确定最优的单元规模。有些采用基于单元架构的组织会使用单个 DC 进行部署,即单元实例的所有基础设施和应用资源都位于单个数据中心或可用区。这种方式能够最大限度地减少多 DC 部署所带来的灰色故障的影响,并简化了健康监控(单元是否健康)。另一方面,如果使用得当的话,多 DC 部署可以在出现数据中心级别的故障时,为系统提供韧性,但是健康监控会变得更具挑战性。
单元大小在管理故障的影响和管理基础设施的成本方面也发挥着重要的作用。使用较小的单元可以缩小影响的范围(受影响的用户/客户会更少),提高资源利用率(由于单元占用率较高,闲置资源会减少),并且能够限制将流量分段重新路由到其他单元所需的工作量。不过,如果单元过小的话,在为数量特别巨大的客户端/客户提供服务时,将会遇到相关的挑战,所以,单元要足够大,从而能够基于分区键(partitioning key)满足最大流量分段的需求。
另一方面,单元越大,资源的规模经济就越好,这意味着容量利用率会更高。对运维团队来讲,管理较少的单元可能会更加容易。此外,对于较大的单元,需要注意基础设施方面的限制,如云供应商平台在区域和账户级别的限制。
管理基于单元架构的控制平面
采用基于单元的架构需要投入大量的精力来开发管理功能,这些功能超出了支撑常规微服务架构的需求。除了配置和部署基础设施和应用服务外,基于单元的架构还需要额外的功能,专门用来管理和监控单元、在可用单元之间划分和安排流量,并在单元之间迁移数据。
对于基于单元的架构来说,最重要的考虑因素是如何在单元之间划分流量,这需要采用面向单元的方式针对每个领域分别进行确定。制定最佳划分模式的第一步是选择分区键。在大多数情况下,这可能会使用用户或客户的标识符,但是应该根据具体的情况进行具体分析,同时要考虑到流量分段的粒度,避免分段大于选中的单元的容量。

单元划分可以采用不同的映射方法
实现单元分区映射的方法有很多,它们各有利弊。这些方法包括存储所有映射记录的完整映射和一致哈希算法(该算法可以将条目非常稳定地分配到桶中,并在添加和删除桶时,最大限度地减少混乱)。无论选择采用哪种映射方法,提供对其进行重写的能力都是很有帮助的,这样可以对某些分区键进行特殊处理,也有助于测试活动的开展。
另外一个考虑因素是当新用户/客户加入或者新单元调配时,应该采用什么样的单元放置策略。该策略应该考虑到每个单元的大小和可用的容量,以及可能出现的云供应商配额/限制。当达到单元容量的阈值,需要新的单元来处理进入平台的流量时,控制平面要负责调配新的单元并更新单元的映射配置,该配置会根据数据平面决定应用流量的路由。
与上述功能相关的是数据迁移能力,它对于单元放置(如果需要重新调整分区)和故障处理(如果某个单元处于不健康的状态,并且需要清空)非常重要。就其本质而言,数据迁移从技术角度来看是相当有挑战性的,所以这种能力是交付基于单元架构最困难的方面之一。在不同单元的数据存储之间迁移或同步底层数据,为数据冗余和故障转移提供了新的可能性,进一步提高了采用基于单元的架构所提供的韧性。
用于路由应用流量的数据平面
与控制平面负责管理架构类似,数据平面负责可靠地转移流量数据。在基于单元的架构中,这意味着要根据分区映射记录将流量路由到恰当的单元。需要强调的是,路由层要尽可能简单并支持横向扩展,避免出现复杂的业务逻辑,因为数据平面可能会遇到单点故障。
路由层的实现可以采用各种解决方案,包括 DNS 和 API 网关,或者部署在通用计算平台或基于容器执行平台的定制应用服务。无论采用哪种方式,分区映射数据必须从可靠的数据存储中读取,这可以是高可用的分布式数据库或 blob 存储服务。路由层可以支持同步 API 调用(HTTP 或 GRPC)和异步消息,不过后者在实现时会更具挑战性。

单元路由器是主要的数据平面组件
考虑到数据平面在单元之间流量流动中的关键作用,它可以用来执行安全策略,确保只有经过授权的 API 请求才能由单元内的服务来进行处理。因此,可以实现一系列的安全机制来防止未经授权的访问,包括用于认证的 OAuth 或 JWT、双向 TLS 以及用于授权的 RBAC 或 ABAC。
使用基于单元的架构的收益
采用基于单元的架构的主要收益是通过故障隔离提高韧性。单元提供了故障隔离的边界,减少了部署失败、客户滥用产品/平台、运维人员失误或数据损坏等问题的影响。
使用单元还有助于提高系统的可扩展性。理想情况下,单元的大小应该受到限制,以减少故障的爆炸半径,这也使得单元成为很好的平台扩展单位。随着工作负载的增加,可以调配更多的单元来满足新的流量(新客户/用户)。限制单元的大小可以降低非线性扩展因素或意外竞争点(性能瓶颈)带来的意外风险。
同样,单元也可用于确定部署范围。在向更广泛的用户/客户群体推出新版本的服务之前,企业可以使用金丝雀部署,将变更范围局限于一个单元(因此这会是用户/客户的一个子集),而不是在所有地方均推出新版本的服务。
大小受限的单元非常适合用来量化系统的性能,因为单个单元的性能更易于测试,并且能够基于横向扩展整个单元而不是纵向扩展单元内的组件来确定系统的可扩展性特征。
单元还具有将属于同一子域或限界上下文的服务进行分组的额外优势,这可以帮助企业将团队和部门的边界与产品域的边界统一起来。这对大型企业尤为重要,因为在这些企业中,会有数十或数百个团队负责构建和运营大型的产品套件。
最后一个潜在好处是,它能够通过减少跨 AZ 的流量来节约成本,但这应该与在数据平面内运行路由层所产生的额外运维成本进行权衡。
采用基于单元的架构的注意事项
虽然基于单元的架构在分布式系统中具有很多优势,但实现这种方法需要付出额外的努力并且会带来一定的挑战,因此它可能并不适合所有的组织,比如,仍在迭代产品以保持市场契合度的初创企业。与微服务架构一样,基于单元的架构也需要在底层平台上投入大量资金,才能让这种架构加快而不是阻碍团队的发展速度。
对于大多数基础设施规模并不庞大的公司来说,他们也可能会遇到那些采用基于单元架构的公司曾经面临的挑战,所以仍然值得评估是否有必要采用基于单元的方法。
首先,任何因声誉、财务或合同要求而无法承受大面积停机的公司都应该考虑采用基于单元的架构,即使不能全部采用,至少也要考虑那些面向用户的关键服务。
此外,任何需要或希望降低恢复点目标(Recovery Point Objective,RPO)或恢复时间目标(Recovery Time Objective,RTO)的系统也应该考虑采用基于单元的方法。最后,需要在租户级别实现严格的基础设施级隔离的多租户产品也可以从基于单元的架构中获益,从而提供完全专用的租户功能。
在任何情况下,都需要考虑采用基于单元的架构的总成本,并将其与预期效益进行平衡,以确定预期的投资回报率。
原文链接:
How Cell-Based Architecture Enhances Modern Distributed Systems
评论