← 文章 / 云原生与基础设施
Lobsters 7小时前 · 2026-08-06 18:59:33 · 3 阅读

论构建可扩展的控制平面


论构建可扩展的控制平面

2026年8月4日 • 3756字

头图

Zak van der Merwe 在 AWS 的整个职业生涯都在构建控制平面。最初是为 EC2,现在是为 DSQL。表面上看,控制平面相当乏味:它记录应该存在什么,并与实际存在的东西进行协调。没有人毕业时梦想着构建控制平面,但 Zak 会第一个告诉你,如果你喜欢解决分布式系统中的难题,那几乎没有比这更好的地方了。这里是许多难题汇聚之处,而你的决策将决定一项服务能否在增长中存活下来。

如果你一直在关注 Marc BrookerMarc Bowes 关于 DSQL 的文章,那么这篇是绝佳的补充,它揭开了幕布,展示了从一开始就为控制平面工程师设计的数据库意味着什么。

–W


论构建可扩展的控制平面

我在 AWS 工作了将近十四年,几乎全部时间都在构建控制平面。这不是任何人会为自己规划的职业道路。没有哪个大学毕业生会想:“我要花未来十年确保云服务的记账层保持稳定。”但我就在这里,我认为我之所以还留在这里,是因为控制平面恰恰是许多有趣问题所在之处,尽管需要一段时间才能看清这一点。

在加入亚马逊之前,我在开普敦一家电信公司工作,那里大概有十台服务器,全放在办公室后面的一个房间里,每台都有名字。你会通过 SSH 登录它们,和同事共享,如果出了问题,走过去就能处理。那是我对运行基础设施的全部认知模型。服务器是你逐一了解、精心维护的东西,而且因为数量少到能装进脑子里,你还能把它们作为一个整体来推理。

我提这个,不是因为这段经历有多特别,而是因为不到二十年前,这还非常普遍。正因如此,我觉得值得说出来。也许你的版本是一个小型的 Kubernetes 集群,或者几个 RDS 实例,你能一眼看穿整个系统,能叫出每个部件的名字,出问题时也知道是哪个部件坏了。这种对基础设施了如指掌的感觉很舒服,但也让接下来的故事变得难以描述——因为当我加入 EC2 时,这种感觉瞬间消失了。

说实话,刚开始我根本搞不懂 EC2 是怎么运作的。我总想用自己已有的知识去理解它。如果我启动一个实例,底层的服务器挂了,会发生什么?我的虚拟机是不是会瞬间被传送到另一台主机上?云服务是怎么制造出“硬件故障无关紧要”这种假象的?我完全无法用自己运行软件的经验来解释这一切。

我在 EC2 的第一份工作是做集群健康检查——给每台服务器发 ping,判断它是否健康。结果我发现,这根本不是魔法,而是相反:故障层出不穷。主机宕机、硬件异常、磁盘损坏。我看到了 EC2 的“底牌”,一片混乱。我的认知从“服务器是珍贵的东西,需要保护”变成了“一切都在着火”。

花了好一阵子我才摆脱这种感觉,但最终我意识到,这些故障不过是汪洋大海中的几滴水——绝大多数东西都运行正常。系统只是运行在了一个规模上,让故障成了常态,是统计上的必然,而非紧急事件。而让一个服务能在这种规模下运行,无需人类响应每一次故障,让一切保持运转的,就是控制平面

无论如何,我在 AWS 的这些年都在跟控制平面打交道。每个 AWS 服务都有一个控制平面,我觉得它们是默默无闻的英雄。它们工作得越好,就越没人注意到它们。正因为有它们,你才不用给服务器命名;也正因为有它们,当硬件故障时,作为客户你根本不用操心。我为 AWS 的两个主要服务构建过控制平面:EC2 和 DSQL。两者相隔近十年,但构建 EC2 控制平面时学到的惨痛教训,直接指导了 DSQL 的设计。这就是我今天想讲的故事。

到底什么是控制平面?

说到这里,我大概该好好解释一下我所说的控制平面是什么意思,以及为什么我觉得它很有意思。我会以 EC2 为例,因为我对这方面的理解大多来自它。

我的理解是,每个服务都包含数据平面和控制平面。数据平面是核心能力集合,是原始算力、硬件和网络。控制平面则是连接这些能力与用户的通道。它把数据中心里物理存在的东西,转化成你能实际使用并从中获取价值的形式。没有控制平面,你就得回到 SSH 登录某个机柜里命名的服务器那种老路上。有了它,你只需一个 API 调用就能启动上千台机器,完全不用操心它们部署在哪里。

来自开普敦的 EC2 架构图
(这是我们在开普敦办公室对 EC2 架构的可视化呈现,用了大量笔、纸和便利贴。)

EC2 涉及数千名工程师,功能多到没人能全部记住,但控制平面在概念上……其实相当简单。简化来说,EC2 让你在云端租用一台虚拟机(VM),而控制平面的任务就是为你创建和销毁这些虚拟机。

我喜欢用恒温器来类比,因为它不断测量温度,知道目标状态,并持续推动系统向正确方向调整。这正是控制平面在做的事。它是一个持续循环:观察当前状态,对比理想状态,然后修正偏差。当你启动一台虚拟机时,控制平面会记录下“应该存在一台虚拟机”,在合适的数据中心找到物理服务器,配置镜像,设置网络,然后启动它。之后,如果那台服务器因任何原因消失,控制平面会察觉到并更新记录以反映现实。它总是在调和“实际是什么”与“应该是什么”之间的差异。

团队反复强调一个原则,几乎成了口头禅:无论控制平面发生什么,已经运行的虚拟机必须继续正常工作。我们称之为静态稳定性,这听起来理所当然——毕竟运行中的虚拟机当然应该保持运行。但在大规模系统中,最显而易见的事情恰恰最难保障,因为每个新功能、每次变更、每个依赖都可能意外破坏这个保证。维护这一原则决定了故障的严重程度:是客户无法启动新资源,还是整个系统完全瘫痪。两者都很糟糕,但后者是灾难性的。EC2 具备静态稳定性这一事实,在我早期工作中给了我不少安慰。

EC2 团队在减少故障方面做得非常出色。但正是对故障形态的理解,塑造了我对构建控制平面的认知。

深入控制平面内部

要理解故障如何发生,首先需要了解控制平面如何存储状态。EC2 控制平面的核心是一个关系型数据库。当客户调用 RunInstances API 启动虚拟机时,最关键的操作是控制平面在数据库中写入一行记录:客户 X 现在拥有虚拟机 Y。此时 API 才能安全返回。

实际上,单个 RunInstances 请求会触发微服务和宏服务之间成百上千次内部 API 调用。其中许多服务都有自己的数据库来记录各自的状态。多年来这种复杂性已经难以用语言形容,但在所有复杂性的最底层,是一个 MySQL 数据库,而数据库中的内容必须与现实保持一致。

事情出问题的最简单方式也是最可怕的。有时主数据库服务器会直接宕机。我们的解决方案是热备——一台持续从主库复制数据的备用服务器,理想情况下只落后几毫秒。当主库故障时,我们会切换到备用库,从而将中断时间控制在几秒内。团队通过多年的运维实践、构建工具、编写操作手册、培训值班工程师在压力下执行切换,才换来了这个能力。但几秒的中断仍然意味着凌晨3点会触发警报,并且需要人类在不完整的信息下做决策。我们一直在问自己:架构能否彻底把人类从这个循环中移除? 更缓慢、更长期的问题是确保MySQL数据库能跟上业务增长。这其实挺让人沮丧的,因为数据平面承担了所有繁重工作——下载虚拟机镜像、配置网络、运行工作负载——而数据库只是记录现有资源的状态。每启动一个实例,就意味着对数据库进行更多的插入、更新和读取操作,最终记账员跟不上工人的节奏。 于是我们引入了更多从主库复制的服务器,用作只读副本。许多EC2 API并不做任何修改,它们只是描述当前资源的状况(比如你有多少台虚拟机)。我们将这些只读API的流量导向新的只读副本,这大大减轻了主数据库服务器的负载。这是任何试图扩展关系型数据库的团队的标准做法。顺便说一句,正是这批只读副本导致了EC2 API的最终一致性,正如Marc Brooker所写,这给客户带来了不必要的认知负担。这也是我们在DSQL中想要改进的地方,稍后会谈到。

只读副本为我们争取了时间,但每次写入仍要经过单一主服务器,最终我们不得不把数据库做分片。第一阶段对客户是可见的:把每个 AWS 区域拆分成多个可用区(AZ),每个可用区拥有独立的控制平面和各自独立的 MySQL 数据库。这同时改善了扩展性和可用性,因为可用区之间是相互独立失效的,任何一次故障的影响范围都被缩小了。这一拆分也成了一个基础构件,让 AWS 客户能够构建可承受单个可用区损失的架构。第二阶段则是内部的事:我们在每个可用区内进一步分片,划分出所谓的 cell(单元)。这两个项目都耗费了数年的工程时间,因为它们涉及大量服务的改造。代码库中每一个访问数据库的地方,都必须知道该路由到哪个分片。按主键的简单查询还好办,但其他操作——比如跨分片边界数据的 join——就麻烦得多。在这个层面,哪怕是看似最简单的决策,也会带来深远的影响:按账户分片还是按资源分片?不同的服务会根据自己的访问模式做出不同选择,并没有放之四海而皆准的答案。

这一切背后还有一笔人的代价,我觉得我们谈得太少了。早些年,我们缺乏自动化,很多如今控制平面顺手就能做的事,当时都做不了。一旦发现安全漏洞、整个集群都需要打补丁时,我们没有能说"以安全速率更新所有主机"的系统。我们只能把整个团队拉过来,把所有主机分片、再分配班次。开普敦办公室每个人都会领到一摞:去把你名下的主机逐台更新,回报状态。这就是控制平面还不成熟时的真实写照,而这种事注定无法规模化。几百台主机的集群,你还能这么干;几百万台,就不行了。最终是控制平面把人类彻底从这个循环里解放了出来。

如果你亲身经历过这条路——扩展性的悬崖、只读副本的取舍、永远比预期更久的分片项目——你就会知道这是一条漫长而痛苦的路,也是每个用关系型数据库支撑成功服务的团队终将走上的路。

寻找数据库的香格里拉

在 EC2 干了十年之后,我对理想数据库已经有了很明确的看法:它能随着业务增长平滑扩展,不需要人为干预;高可用,升级不停机,也没有服务器要我去盯着;它还能让我利用关系数据模型的能力来建模业务,让软件开发更高效。

巧的是,2020 年代初,AWS 数据库团队里一群经验丰富的工程师也正在琢磨怎么构建这样的数据库。这些人不少都有 EC2 等服务的从业背景,亲身经历过运维关系数据库的痛苦。同时,他们也在总结 DynamoDB 这种大规模无服务器数据库的运营经验,并思考如何把这些经验用到关系数据库上。

他们的目标是让数据库也像 EC2,尤其是像 Lambda 改变服务器那样被重新定义。你用传统数据库时,总会遇到所谓"有名字的头节点",本质上还是"有名字的服务器",就像我加入 EC2 之前的处境一样。理想的数据库应该让你彻底摆脱"有名字的数据库"这种思维。它会有一个控制平面,把这些事全帮你处理好,让数据库变成一个始终可用的逻辑端点,自动伸缩,你完全不用操心底层。

大约 2021 年,这个项目真正开始加速。我们已经想清楚一套架构,看起来能真正兑现"理想数据库"的承诺。我也有机会加入这个团队,开始搭建它的控制平面。这个服务在 2025 年以 GA 形式发布,就是 Amazon Aurora DSQL。

下面我们快速回顾一下 EC2 当年踩过的大坑,再看看 DSQL 是怎么解决这些问题的——尤其是对控制平面的开发者来说。

在 DSQL 里,你的数据并不是跑在某一台服务器上的。DSQL 会为每个连接启动一个 Firecracker 微型虚拟机,也就是说每个连接本身就是一个小小的头节点。某个连接挂了,只影响那一个连接,不会波及整个应用。没有人会被叫醒,也没有需要人为决策的故障切换。我也不用再管备机了,因为这套架构已经把人类从这个痛苦的循环里彻底移除了。

扩容读能力是我们在 EC2 花了多年才解决的问题,当年只能手动加副本,并接受最终一致性带来的代价。DSQL 会自动添加读副本,事实上这正是我参与构建的控制平面最核心的职责之一。如果你的应用读流量突然飙升,DSQL 能从容应对,而且读操作始终保持强一致性。多年来我们一直对客户说"稍后再试一次",所以这一能力至今仍让我觉得不可思议。它从根本上简化了任何基于 DSQL 构建的控制平面架构,也免去了使用这些 API 的开发者心智上的负担。

再就是分片,在 EC2 这件事体现为可用区和单元,我们同样花了好几年才搞定。当你为新的重要服务构建 AWS 控制平面时,必须提前预见到分片终将变得必要,经验也证明从一开始就做分片比之后再改造要便宜得多。这是一个两难困境:你为了一个尚未发生的问题而拉长了上线时间,而一旦交付节奏紧张,我见过很多团队为了能尽快发版而放弃分片。DSQL 消除了这个困境,它会自动对你的负载进行分区,你完全不用操心这件事。你可以继续使用熟悉的 Postgres 全套能力——复杂事务、多表连接、二级索引——同时放心地知道数据库会随业务一起扩展。过去十年里,许多新的 AWS 控制平面出于同样的原因选择构建在 DynamoDB 之上,但 DSQL 提供的世界要少一些妥协。你既能享受到 DynamoDB 级别的可扩展性,又能用上开发者真正更偏爱的关系型编程模型。

"自托管"

到了为 DSQL 控制平面选择数据库的时候,我们选了 DSQL。用自己的产品来跑自己的团队,意味着在任何客户之前就摸到每一处毛刺,但这样做同样绕不开当年在 EC2 遇到的那个循环依赖:控制平面不能依赖于它自己所控制的东西。

"自托管"这个决定给我们带来了两个显著的好处。随着客户开始使用 DSQL,他们创建的数据库数量越来越多,控制平面会根据使用情况持续地对这些数据库进行扩缩容,而且往往速度很快。所有这些客户活动都会给 DSQL 控制平面带来"簿记"工作,而且随着 DSQL 的普及,这类工作的量也在不断增长。由于 DSQL 控制平面本身就运行在 DSQL 上,我们的簿记数据库可以自动扩容以应对不断增长的需求,团队几乎不需要为此付出额外精力。

另一个好处体现在我们应对可用区故障的方式上。DSQL 从设计之初就具备了应对单可用区故障的能力,但某个可用区宕机并不意味着客户的工作负载会停止扩缩容,也不意味着客户会停止创建数据库。我还在 EC2 团队的时候,每逢可用区故障都是一场"火灾"——控制平面数据库崩溃,告警器响个不停。对于 DSQL 控制平面来说,这样的糟心事就没那么痛苦了,因为 DSQL 控制平面的数据库始终是可用的,这使得控制平面能够继续执行其关键工作,确保客户数据库持续稳定运行。

摘下玫瑰色的眼镜

如果你还在读到这里,你大概心里在想:"那有什么不足之处呢?"

作为一项相对较新的服务,我们还有一些功能尚未支持。其中有些是我们正在积极补齐的短板,而另一些则更为微妙,我们希望花时间把事情做对。外键约束就是一个很好的例子。外键约束是经典的数据库特性,非常实用,实现起来也并非难事。然而,在大规模场景下,外键约束也可能带来隐患。我们希望能把这件事做扎实,而这需要时间。

Postgres 单节点部署的一个优势是它会把工作集保存在内存里,缓存读取极快。但真实的架构要复杂得多。例如,基于 Postgres 的控制平面会跨多个可用区部署,并在数据库前面加一层连接复用代理。这些措施对可用性和扩展性来说是必要的,但会带来额外的延迟。使用 DSQL 就不需要自己操心这些事了。你能获得不错(虽然还达不到单节点 Postgres 那种水平)的延迟,而且随着应用规模增长,这个延迟依然稳定。这正是我做控制平面想要的东西。我当然希望快,但相比之下,我更在意应用扩展时的延迟可预测性。

不过也得对 AWS 控制平面建设者的现状说实话:即便从今天就开始,把 EC2 控制平面迁移到 DSQL 这样的工作也需要好几年,这没什么。我在 EC2 控制平面干了十多年,深知真正重要的工作往往以年为单位衡量影响,而不是季度。

未雨绸缪

这篇文章的大部分篇幅都在深入讨论数据库扩展和运维保障。工程领域很多故事都是这个套路。我们在 EC2 遇到的问题——怎样在不出错的前提下做得更快、如何把更多时间花在客户真正在意的事情上、团队从寥寥数人扩张到数千人后如何协作、系统在底层不断变化时如何保持可靠——正是每个工程组织在规模化过程中都会遇到的难题。它们和 1998 年催生亚马逊那份原始分布式计算宣言的问题是近亲。多年来,我自己的关注点逐渐收窄到其中一种特定形态:怎样才能让各个团队完全独立负责 EC2 的一块业务,在各自最紧迫的问题上快速推进而不需要昂贵的协调,同时让产品在客户眼里依然是一个整体。

环顾当下整个行业,我发现当年的那种压力正以一种我没预料到的规模再次上演。智能体编码(agentic coding)的到来,把写软件的成本压到了几乎为零,随之而来的代价是工作中真正困难的部分被推到了别处。当代码变得廉价,真正的瓶颈就转移到了判断力上——搞清楚该做什么、如何安全地上线、以及如何抢在客户开口之前预判他们的需求。一个好的控制平面给使用它的人带来的正是这种转变:把维持基础设施运转的那些隐形工作从他们肩上卸下,让他们可以把注意力放在自己的客户身上。只不过这一次,同样的转变正发生在整个软件开发领域,甚至一个人的团队也会感受到向外扩张的必要性。

我不想假装知道一年后的软件开发会是什么样子,因为我们现在正处于一次大改造的中途,墙还敞着。但我确信的是:当你脚下是一个不会坍塌的地基时,快速前进会容易得多;而值得你花一辈子去做的问题,始终是那些考验你判断力、而不是考验你能否撑住账簿层的问题。我希望 DSQL 能给下一代建设者提供这样的地基,帮他们赢回时间去替客户探路——这也是我一直希望在 EC2 时能有更多余裕去做的事情。

借用 Werner 的话:"现在,去构建吧。"


原始来源: Lobsters

评论 (0)