写点什么

平台工程三大支柱的良性循环

作者:Pratik Agarwal
  • 2026-05-13
    北京
  • 本文字数:6910 字

    阅读完需:约 23 分钟

我们正处于内部开发平台(IDP)的时代。业界的承诺极具吸引力:将云端那些“缺乏差异化且繁重”的工作进行抽象化处理,让产品团队能够完全专注于交付商业价值。

但作为一名在基础设施领域深耕十年的从业者,我亲眼目睹,这一承诺未能兑现。通常情况下,平台会遭遇瓶颈:要么沦为“漏洞百出的抽象层”,迫使开发人员不得不去理解底层基础设施;要么变得过于僵化,反而拖慢了本应助力其提速的团队。

普遍的看法是,我们正努力在可靠性与易用性之间寻求平衡。

我们认为,一个系统要想达到“企业级”(即可靠),就必须结构复杂、防护严密而且变更缓慢。反之,我们认为“开发人员友好”(即易用)就意味着要移除安全防护措施。

我想分享一个不同的框架,它源于我在反复观察这些系统时看到的有效模式。根据我的经验,可靠性和易用性并非对立关系,而是良性循环。

一个人机工程学设计欠佳、界面混乱、操作繁琐或“生硬”的平台,本质上是不可靠的,因为它容易引发人为错误。要构建一个可扩展的平台,我们必须通过三个相互关联的支柱来服务于两个不同的用户群体:基于自动化的可靠性、开发人员人机工程学和运维人员人机工程学。

第一支柱:依赖自动化状态管理的可靠性

在小规模系统中,可靠性往往是被动应对的。警报一响,有人登录来修复问题。但在全球性数据库或庞大的缓存集群这样的规模下,这种“英雄式”的运维是不具备可扩展性的。可靠性必须作为一种可控的状态。

以控制平面为“大脑”

我参与开发过的最具韧性的系统,都严格区分了数据平面(执行者)和控制平面(决策者)。

可以将控制平面视为一个连续的控制回路,就像恒温器一样。它的作用是不断地将实际状态与目标状态进行校准。虽然下面列举的内容未能穷尽所有情况,但对于这类控制平面,这确实是我遇到过的一些常见的应用场景。

自动配置与再平衡

在分布式系统中,“热点”现象在所难免。无论是特定的数据库分区,还是数百万玩家的缓存排行榜,总会有一些节点会比其他节点承担更重的负载。

采用手动方式时,运维人员在看到 CPU 使用率高的告警后,会手动拆分分片。而采用控制平面方式时,系统会分析流量模式,识别热点阈值,自动配置新节点,并迁移该分区。

请注意,我们不要低估“确定阈值”和“迁移分区”背后所涉及的巨大复杂性。对于持久化数据库而言,迁移过程通常包括:将数据在磁盘上的表示形式序列化,以向后兼容的格式提取数据,在受网络吞吐量限制的地理位置之间传输数据,以及将数据反序列化并写回新机器。问题的关键在于,控制平面必须能够协调所有这些迁移操作,同时不影响这些节点上客户流量的实际延迟和可用性表现——这些节点通常受限于 CPU 和网络吞吐量。

这些过程要求控制平面具备幂等性。由于网络不可靠,“将分区 X 迁移至节点 Y”的命令可能会被发送两次,或在传输途中失败。控制平面必须能够从这类故障中恢复,同时又不破坏系统的状态。

集群健康和自愈

硬件会出故障,数据会老化。一个可靠的平台不会因为单个节点故障就通知管理员;它本就预料到会发生这种情况。控制平面应持续对存储节点和计算节点做健康检查。当某个节点不再响应心跳检测时,“大脑”应自动执行以下操作:

  • 隔离该节点,阻止新流量进入。

  • 重新复制丢失的数据,维持所需的复制因子。

  • 退役旧硬件。

全局决策

控制平面采用单领导者架构具有长远的效益,通常可持续数年,甚至长达十余年。单领导者架构使控制平面能够全面掌握全局状况,有助于更高效、便捷地做出决策。

以速率限制为例。你可能希望基础设施能够对来自恶意或噪声源的请求进行限流或拒绝(也称为流量整形)。在这种情况下,本地速率限制往往难以奏效,因为单个主机无法获知集群中其他节点的行为。另一种模型是,由控制平面的单个领导者与集群中所有无状态路由器或代理进行双向通信,并据此发送速率限制信息及其他元数据。采用这种模型实现全局速率限制就不需要复杂的分布式协调协议或其他机制了。

当单领导者确实成为瓶颈时,这类架构的一种常见演进方式是保留单领导者,但将其工作分配或卸载给集群中的其他节点。这种方法既能实现可扩展性,又能保证系统有一个全局一致的视图。

注意:如果不考虑“脑裂”等情形,领导者选举绝非易事。关于领导者选举的文献虽然超出了本文的讨论范围,但我推荐阅读Martin Kleppmann的这篇文章

通过自动化这些“底层”决策,你可以通过代码逻辑来确保系统的可靠性,而非工程师在凌晨 3 点能否及时找到自己的笔记本电脑。

第二支柱:开发人员人机工程学

自动化胜过文档。开发文档固然必要,但仅靠它无法充分保障可靠性。如果你告诉开发人员:“请不要在没有 100 毫秒延迟的紧凑循环中使用这个 API”,总会有某个人在某个地方忽略这条提示。

开发体验设计是一门艺术,旨在让“黄金路径”成为阻力最小的路径。其核心在于将可靠性“左移”,从运行时环境转移到开发人员编写代码所使用的工具之中。

“有主见的”SDK 模式

SDK 是平台真正的用户界面,是基础设施与开发人员业务逻辑的交汇之处。一个基本的 SDK 仅是对 API 调用的封装。而一个符合人体工程学的 SDK 则是一个可靠性引擎。

基于模式的抽象

在任何足够成熟的平台上,你会注意到一个有趣的现象:用户都在解决相同的问题,只是实现方式略有不同,遇到的 Bug 略有差异。他们正在实现分布式锁、构建速率限制器,或者基于平台的基础组件自行构建排行榜逻辑。这是一个信号。当你看到同一个模式在十几个团队中被重复实现过十几次时,就该将该模式整合到平台中了。

以锁定场景为例。正确实现分布式锁的难度出人意料;为了应对锁持有者操作中途崩溃的情况,需要使用 TTL 心跳、隔离令牌和预留逻辑。大多数团队都低估了这种复杂性,结果便是那些仅在生产环境负载下才会显现的微妙竞争条件。解决之道并非提供更详尽的锁实现文档,而是设计一个锁客户端:开发人员只需调用 lock.acquire()和 lock.release(),而 SDK 会在内部处理心跳检测、隔离和预留逻辑。

同样的原则也适用于连接管理。如果你的平台使用 gRPC 或长连接,那么连接池、健康检查和负载均衡就不应成为需要用户自行处理的任务。一个能够调整连接池大小、在出现临时故障时进行重试以及优雅地关闭连接的连接提供程序,能让开发人员专注于思考查询内容,而非如何维护健康的连接。在多语言环境中,这种协调机制尤为重要,因为每种语言的生态系统在连接生命周期方面有不同的默认设置和注意事项。

环境感知型默认设置

我们在多种不同的系统环境中运行:裸机实例、容器编排器以及无服务器函数。每个环境都有非常独特的特征和属性,因此,使用一套通用的 SDK 默认设置可能会带来风险。

例如,HTTP keepalive 是一种标准的性能优化手段;通过在不同请求间复用 TCP 连接,可以避免重复握手带来的开销。在大多数环境中,这种复用是我们所期望的。但在 AWS Lambda 这样的无服务器环境中,执行上下文在两次调用之间处于冻结状态。服务器端保持连接的计时器仍在运行,但客户端却处于冻结状态。当函数在几分钟后恢复运行时,它会尝试通过服务器已经关闭的连接发送请求。结果便是出现看上去是服务器端问题、实则源于客户端配置错误的神秘超时错误。

修复方法本身很简单:为无服务器执行模型正确配置 keepalive 行为。Keepalive 机制本身并非坏事;在长期运行的服务中,它是保证连接健康状态的关键。但在 Lambda 这种“冻结-解冻”环境中,默认 keepalive 设置反而会造成实际的损害。代价便是那些花在追踪 gRPC 日志上并最终得出这一结论的数小时。这里有一个更深层的教训:SDK 应当“知晓”自身运行的环境。通过提供针对不同环境的配置文件(如 ServerlessConfig、ContainerConfig 和 LongRunningConfig),并针对每种执行模型调整默认设置,可以为用户节省大量的调试时间——避免他们为那些不是因为代码缺陷、而是因为基础设施假设与运行时实际情况不匹配的问题而苦苦追查。

消除重试风暴

在分布式系统中,引发级联故障的最常见原因之一是“重试风暴”。试想,某后端服务出现了一瞬间的延迟激增。每个客户端都遵循简单的“重试 3 次”逻辑,立即向该服务发送了三倍于原流量的请求。原本就已经不堪重负的服务,此刻彻底崩溃。这种崩溃之所以特别危险,在于每个客户端都在做“正确”的事——重试失败的请求。但成千上万个客户端同时重试所产生的涌现行为,却带来了灾难性的后果。

一个符合人体工程学的 SDK 解决这一问题的方式,并非仅仅记录正确的重试策略,而是将其作为默认设置强制执行。带抖动的指数退避是一种可以确保重试请求在时间上分散,而不会以协调一致的波浪形集中到达的技术。断路器机制则可以确保遭遇反复失败的客户端能给后端留出足够的喘息空间,而不是持续地增加负载。通过将这些机制作为默认配置内置于客户端库中(而非作为需手动启用的选项),后端将获得最佳的渐进式恢复机会。

这三种模式的核心要点是一致的:找出用户反复解决的问题,并将这些解决方案融入平台本身。这样不仅减轻了开发人员的认知负担,还消除了整类整类的错误——因为他们再也不会无意中引入这些错误了。

第三支柱:运维人员人机工程学

运维人员的人机工程学设计是关键环节!我们常常对开发体验念念不忘,这无可厚非。但平台还有另一类用户,我们却总是忽略他们:内部运维人员。正是这些工程师负责构建和维护平台,更重要的是,当系统出现故障时,他们还承担着调试平台的重任。

如果平台的内部状态如同暗箱一般难以捉摸,或者解决一个常见的问题需要按照严格确定的顺序执行一系列复杂的手动操作,那么显而易见,平台存在一个可靠性问题。糟糕的运维人员人机工程学会直接导致平均恢复时间(MTTR)过长。

为什么运维人员需要人机工程学?

假设你需要横向扩展数据库,使其从两个分区扩展到四个分区。实现这种分区方案的运行手册可能如下所示:

  1. 配置两个所需分区类型的新实例。

  2. 配置包含这些实例的系统逻辑分区。

  3. 将两个新分区“连接”到数据库。

  4. 可选:执行任何必要的数据迁移,从而在分区之间平衡存储负载。

这四项任务可以作为四个独立的脚本运行,也可以由运维人员通过一系列命令来执行,看起来似乎很简单。但试想一下,当警报触发并且认知负荷达到峰值时,运维人员可能会不小心在执行步骤 2 之前先执行了步骤 3。这时系统便会处于不一致状态:实例已经存在,但它们所属的逻辑分区尚未创建。现在,他们不得不同时调试两个问题:原本存在的热分区,以及刚刚制造出的混乱局面。又或者,因为终端历史记录中存有上周执行过的类似命令,他们竟针对错误的分区 ID 完成了全部四个步骤。再或者,因为运行手册上标注了“可选”,他们跳过了第 4 步却没有意识到,在这种特殊情况下,集群将失去平衡,并在一个小时后崩溃。

每个基础设施团队都有类似的故事。问题并不在于运维人员粗心大意,而在于这些工具要求在最恶劣的条件下也能完美地运行。

声明式优于命令式

这就是与第一支柱(即依赖自动化状态管理的可靠性)进行关联的关键所在。与以往的四个命令式步骤不同,现在运维人员可以通过声明式接口指定做什么,而控制平面则负责确定如何做:

update partition --scale-up --new-num-nodes 4

控制平面负责按正确的顺序、以幂等的方式处理实例配置、创建逻辑分区、连接分区以及重新平衡数据,并在每个步骤进行验证。这种方法减轻了运维人员在实现目标状态时所需的认知负担。此外,由于执行顺序和安全检查已经编码到控制平面中,不依赖运行手册,因此还能减少人为错误。

一款设计精良的工具应配备内置的安全防护措施。

  • 预演模式

在应用任何更改之前,工具会预先展示操作结果:“此操作将在 us-east-1 区域配置 2 个新节点,并重新平衡 3 个分区。预计耗时:12 分钟。” 通过这段文字,运维人员可以在提交前确认意图。

  • 影响范围控制

该工具应该能够有效防止运维人员误将生产环境作为目标(本意是针对预发布环境),或影响范围超出预期的节点数量。明确确认高影响变更要求,这很有好处。

  • 幂等性恢复

如果命令因网络波动、超时等原因中途失败,运维人员应该能够重新运行同一命令并从中断处继续执行,而不是再创建一组部分配置的资源。这种做法对应我们在控制平面中讨论过的幂等性要求。

运维可视化:超越简单的仪表盘

运维可视化不应该仅仅是有一个布满上百条波浪线的仪表盘;它应该能够回答“当前哪里出了问题,以及原因是什么”。

我发现,把它当做可观测性的层次结构来思考会很有帮助。

哪里出了问题?那些提示服务性能下降的高级健康指标会引起你的注意。在这个层级上,无论状态是正常还是异常,都应保持二元状态。目标不是将每种故障模式都编码到顶层视图中,而是要尽快回答“我需要立即采取行动吗?”“处于故障状态”与“处于退化状态”的区分应留给下一层。问题出在哪里?中间层仪表盘会缩小排查范围。控制平面无法部署新的分片。特定区域的复制延迟骤增。为特定租户提供服务的节点延迟升高。为什么出问题了?深度分析工具会揭示内部状态。节点 X 和 Z 都认为自己拥有分区 Y。由于下游依赖项运行缓慢,连接池已经耗尽。负载分流规则配置错误,匹配范围过广。

关键在于,每个层级都应该与下一层级相衔接。当高层级警报被触发时,只需要一次单击,就可以跳转至按受影响区域进行筛选的中层仪表盘;再点击一次,则可定位到需要关注的具体节点或组件。这种从“出了问题”到“具体原因在此”的流程,应该让人感觉自然流畅且迅捷。

将知识融入工具

需要特别指出的是,运维人员人机工程学设计不佳还存在一个更隐蔽的弊端:它会导致“部落知识”的产生。当故障恢复流程既复杂又设计不周时,只有那些曾经经历过特定故障模式的工程师才知道如何处理。所谓的“操作手册”要么变成了半年前的 Slack 讨论主题,要么就只存在于某个人的大脑中。

这是一个伪装成人员问题的扩展问题,仅靠招聘是无法解决的,因为每位新加入的值班工程师都要经历同样的学习曲线。解决之道在于将第二支柱中的“开发人员人体工程学”原则向内应用:将重复的运维模式融入工具。如果你的团队已经手动进行过十次重新平衡分区,那么这个流程就应该变成一条命令。如果诊断复制延迟问题总是需要检查相同的五项内容(指标、日志、数据库状态等),那就构建一个诊断命令,同时检查这五项并报告结果。

目标是让一名刚开始参加值班轮转的工程师能够像一位拥有十年经验的老手一样解决相同的故障,这不是因为问题简单,而是因为这些工具中蕴含着老手多年来积累的知识。

综述:良性循环

该框架的核心观点在于,这三个支柱并非孤立存在的。它们共同构成了一个反馈循环,决定着工程文化的长期健康状况。

开发人员人体工程学、运维人员人体工程学与自动化可靠性之间的反馈循环使信任得以建立

符合人体工程学的 SDK 能够形成可预测的使用模式。当开发人员能够轻松地采用正确的模式、恰当的重试机制、连接池以及具备环境感知能力的默认设置时,整个系统集群的稳定性便会得到提升。得益于客户端行为规范,控制平面检测到的异常情况也会减少。

稳定的集群可以让运维人员免于频繁地处理紧急呼叫。当控制平面负责处理重新平衡、故障修复和流量整形等繁琐的工作时,运维人员就不用全天候忙于救火了。值班工作变得可控,而不是令人畏惧。

这种方法形成了一个良性循环:充满信心的运维人员有了回馈平台的余力。他们可以开发更好的工具、优化 SDK,并进行韧性演练,在潜在故障演变为服务中断前将其扼杀在萌芽状态。他们会修复运行缓慢的 CLI 工具,重写令人困惑的仪表盘,并添加模拟运行模式来防止下一次人为失误。这些细微的体验优化,正是对未来可靠性的直接投资。

反之亦然。当工具质量不佳时,运维人员会犯更多错误。错误增多会导致事故频发。事故频发又会导致工程师疲于奔命,无暇改进工具。于是工具便依然糟糕。这是一个自我强化循环,要打破它,就必须同时对这三大支柱进行有针对性的投资。

下一次,当在“权宜之计”与“架构优化”之间做选择时,请思考一下,你的选择将强化这三大支柱中的哪一项。通过聚焦于可靠性与人体工程学的良性循环,你不仅是在构建一套工具,更是在为整个组织奠定能够实现规模化发展的基石。

该框架何时会显得大材小用

这一框架的形成源于大型复杂分布式系统的现实情况——在这种系统中,一个客户端配置错误就可能引发整个集群的故障。如果你运营的是一个仅由少数工程师维护的小型服务,那么构建完整的控制平面、具有特定设计理念的 SDK 以及分层可观测性,其开销可能无法带来相应的回报。一份编写得当的操作手册和一个简单的部署脚本,或许就是你需要的全部内容。当人为错误的成本超过构建自动化系统的成本时,当团队规模大到足以让“部落知识”成为负担时,或者当系统复杂到无人能凭一己之力掌握全局时,这些投入便开始显现价值。

目标是信任

构建基础设施平台不仅是一项技术挑战,更是一个建立信任的过程。

当平台设计符合人体工程学,能够帮助开发人员加快开发速度而不造成阻碍时,开发人员才会信任它。当平台运行可靠,而且运维人员知道“大脑”正在处理琐碎的任务,同时在情况变得复杂时能提供支持工具,他们才会信任它。

信任一旦建立,便会不断积累。开发人员信任平台便会主动采用,而非被迫接受;运维人员信任平台便会进行投入,而非绕过它。这种信任,比任何架构图或设计文档都更能区分出:究竟是能够实现扩展的基础设施,还是基础设施最终沦为原本要消除的瓶颈。

原文链接:https://www.infoq.com/articles/platform-reliability-cycle/