我在Google当SRE时学到的:如何处理复杂系统
创始人
2025-06-25 14:02:56
0

今天,让我们来讨论一个有趣的主题:复杂系统。

引言

在我的职业生涯中,我曾在许多复杂的环境中工作过。例如,我在优步(Uber)的一家竞争对手公司工作,负责优化网约车中的司机-乘客匹配。这个环境和其他环境一样,在技术上是具有挑战性的。然而,没有什么能比得上,我目前在谷歌的经历所带来的复杂性,在那里的两年时间,重塑了我对复杂性的认知。

在这篇文章中,我们将剖析“复杂性”这个概念本身。接下来,我们将退后一步,理解是什么让某些环境更偏向于复杂(complex)而非繁琐(complicated),然后探讨有效驾驭复杂系统的模式。

繁琐(Complicated) vs. 复杂(Complex)

理解繁琐问题和复杂问题之间的区别至关重要,因为每种问题都需要根本上不同的方法:

繁琐问题虽然错综复杂但可预测。它们遵循结构化、可重复的解决方案。例如,报税是繁琐的,但它是一个结构化和常规的问题,因为流程年复一年基本保持不变。

复杂问题不仅错综复杂而且独特。它们需要适应性的、通常是新颖的解决方案。例如,减缓气候变化是一个复杂问题,因为它需要新的、适应性的解决方案,而现有方法本身无法真正应对其不断演变的挑战。

回到软件工程领域,在那家优步的竞争对手公司,其中一个挑战是为乘客高效找到最近的司机。这绝非易事,但它本身并不复杂。确实,存在许多解决方案,例如应用地理哈希(示例),实施这些解决方案之一就是正确的方法。

在谷歌,我担任站点可靠性工程师(SRE),专注于为谷歌机器学习(ML)基础设施提供动力的系统。在这里,我认为挑战是真正复杂的,因为需要新的范式和调度方法,尤其是在谷歌的规模下。

识别一个系统是繁琐的还是复杂的是非常重要的。确实,我们提到繁琐系统在定义上是可重复的,而复杂系统需要独特和定制化的方法。因此,如果我们试图将通用解决方案应用于复杂问题,可能不会带来有效的结果。

复杂系统的特征

在本节中,我们将讨论五个有助于识别复杂系统的常见特征。并非所有复杂系统都具备所有特征,但它们往往表现出以下特征中的至少一部分。

涌现行为(Emergent Behavior)

涌现行为是指系统的整体行为,无法仅通过单独分析其各个组成部分来预测。

例如,Gemini产生意外结果就是一种涌现行为。虽然我无法透露根本原因,但通过单独分析所有不同的组件,这种行为几乎是无法预见的。

这是复杂系统的一个可能特征:它们的行为方式,很难仅通过观察其部分来预测,这使得它们更难调试和管理。

延迟后果(Delayed Consequences)

复杂系统的另一个可能特征是延迟后果,即行动并不总是立即产生效果,相反,后果可能在很久以后才显现出来。

例如,部署系统的新版本可能会引入一个细微的问题,这个问题可能只在几天甚至几周后才出现。这种延迟使调试变得复杂,因为与即时影响相比,识别根本原因变得更加困难。

在复杂系统中,仅仅依赖即时反馈可能会产生一种虚假的稳定感,导致问题最终爆发时带来重大意外。牢记后果可能需要时间才会显现,在复杂环境中工作时至关重要。

局部优化 vs. 全局优化(Local vs. Global Optimization)

在复杂系统中,优化一个部分并不一定能改善整个系统,在某些情况下,甚至可能使情况变得更糟。

与非复杂系统不同(在非复杂系统中,改进一个部分通常会带来积极的收益),复杂系统要难理解得多。各组件以不明显的方式相互作用,局部优化可能产生难以预测的连锁反应,有时会导致系统层面的负面结果。

这突显了复杂系统的一个关键特征:整体大于部分之和。因此,局部收益并不总能转化为全局改进,在某些情况下,它们甚至可能使整个系统性能下降。

滞后效应(Hysteresis)

滞后效应描述了系统的过去状态如何继续影响其行为,即使原始原因已被消除。

一个说明滞后效应的现实例子是交通拥堵:即使在道路事故被清理后,延误仍然存在,因为车辆仍然聚集在一起。同样,在分布式系统中,故障可能导致级联式减速,即使在根本问题修复后也是如此。确实,依赖的系统可能由于各种原因(如缓存、重试或排队的请求)需要时间恢复。

在复杂系统中,仅仅修复根本原因并不总是足够的。因此,评估系统是否容易出现滞后效应,如果会,则预测其影响,是至关重要的。

非线性(Nonlinearity)

在复杂系统中,微小的变化可能产生不成比例的巨大或不可预测的影响。

例如,在排队论中,系统负载会增加延迟,这是可预测的。然而,当队列接近饱和时,即使请求量增加很小,也可能导致响应时间呈指数级飙升。

复杂系统常常达到临界点(tipping points),行为会突然转变,使得过去的趋势对预测不再可靠。这种非线性意味着,输入可预测地映射到输出的传统线性假设,对于复杂系统的设计、测试和推理并不总是有效的。

小结

总结本节,复杂系统:

  • 难以仅通过单独观察其组成部分来理解。
  • 并不总是立即显现其影响,后果可能是延迟的。
  • 当优化某个部分时,整体并不总是得到改善,改变有时反而会使情况更糟。
  • 即使原始原因消失后,仍可能持续受到过去状态的影响。
  • 可能对微小变化产生巨大或意外的反应。

请注意,规模本身并不能使一个系统变得复杂:即使小型系统也可能表现出涌现或非线性等复杂行为。

驾驭复杂系统的模式

鉴于这些特征,我们如何在复杂环境中有效运作?以下是我个人认为有效的一些策略。

可逆性(Reversibility)

在处理复杂系统时,我们应尽可能优先选择可逆决策(reversible decisions),即那些如果效果不佳可以撤销的变更。

亚马逊的“单向门 vs. 双向门”(one-way vs. two-way doors)框架很好地抓住了这个理念:

  • 单向门代表不可逆的决策,需要仔细斟酌。
  • 双向门代表可逆的决策,允许我们快速行动、迭代,同时降低风险。

在许多情况下,尤其是在复杂系统中,优先选择双向门能带来更好的结果,因为我们可以进行实验、学习并改进,而不是一开始就过度设计。

话虽如此,并非所有决策都应该是可逆的。例如,像安全策略或合规性相关的变更等选择需要前期承诺。关键在于知道何时应优化速度和迭代,何时应深思熟虑和谨慎行事。

超越即时指标思考(Think Beyond Immediate Metrics)

因为复杂系统并不总是对局部优化做出可预测的响应,所以定义正确的成功指标可能与我们做出的变更同等重要。确实,过分关注孤立的、局部的指标可能会产生一种虚假的成功感,同时掩盖了系统中其他地方无意的负面后果。

为避免这种情况,在进行变更之前,我们应该定义局部和全局指标,以获取系统健康的整体视图。这确保我们不仅衡量关注点直接区域的影晌,而且考虑系统作为一个整体。

精心选择的指标不应仅仅确认局部变更的成功;相反,它们应帮助我们做出更好的决策,并确保在系统层面(而不仅仅是孤立区域)实现有意义的改进。

创新(Innovation)

如前所述,复杂系统通常需要独特的解决方案。由于传统策略可能并不总是适用,我们必须愿意跳出思维定式,拥抱创新。

我记得在谷歌参加的一次早期会议。有人提出了一个在复杂性方面看似荒谬的问题,尤其是考虑到规模。我当时的内心反应是:“这不可能”。但随后,一位队友说:“但我们是谷歌,我们应该能够搞定它!”

这句话让我印象深刻。虽然显然并非每家公司都拥有谷歌的资源,但我认为心态才是真正重要的。当面对一个复杂问题时,我们应该假设它是可解的,然后将其分解、实验并迭代,直到找到前进的道路。

有人可能觉得这部分是老生常谈,但重申一下,复杂问题需要非常规思维。在许多情况下,面对复杂问题时,对创新解决方案持开放态度不仅有益,而且是必要的。

受控发布(Controlled Rollout)

在复杂系统中部署变更时,我们应依靠经过验证的最佳实践来最小化风险。这些包括:

  • 功能开关(Feature flags):动态启用或禁用功能而无需部署新代码,允许安全实验和更快回滚。
  • 金丝雀发布(Canary release):向生产环境中一个小的、受控的子集进行有限发布,非常适合只有少量生产实例的环境。
  • 渐进式发布(Progressive rollouts):逐步扩大发布范围,最适合具有多个集群或区域的大规模生产设置。
  • 影子测试(Shadow testing):在并行环境中使用生产流量运行变更,而不影响真实用户。这有助于在启用变更之前验证其正确性。

通过利用这些技术,我们减少了故障的爆炸半径(blast radius),提高了对变更的信心,并实现了更快的迭代。

可观测性(Observability)

可观测性是复杂系统的主要支柱之一。我对可观测性的工作定义(主要受Observability Engineering启发)如下:

你能够通过切分(slicing and dicing)高基数(high-cardinality)和高维度(high-dimensionality)的遥测数据,来理解系统的任何状态(无论多么新颖或怪异),而无需发布新代码。

没有可观测性:

  • 系统变得更加脆弱,因为未知问题在造成实际影响前一直隐藏。
  • 调试意外故障变得异常困难。
  • 由于缺乏高效的反馈回路,创新速度会减慢。

在未知因素不可避免的复杂环境中,可观测性至关重要。它使团队能够驾驭不确定性、更安全地进行实验,并获得短反馈回路以持续改进系统。

没有适当的可观测性,变更就只是意见而非基于信息的决策。

模拟(Simulation)

预测复杂系统的行为很少是简单的,有时几乎是不可能的。

我记得一个案例,我们花了大量时间设计一个变更,谨慎地用数据支持每一个假设。然而,由于未考虑到的因素,如潜在变量(lurking variables),该变更最终无效^1^。

有时,与其仅仅依赖预测,一个更有效的方法是在推出变更之前对其进行模拟。有多种方法可以利用模拟测试,包括:

  • 重放过去事件(Replaying past events):如果我们设计系统来记录其所有输入,我们就可以针对新版本重放过去的事件,并分析其影响。这使我们能够以受控方式验证变更,减少不确定性,并改进复杂系统中的决策。
  • 确定性模拟测试(Deterministic simulation testing):不依赖真实世界数据,我们可以创建受控的、可重复的模拟,在特定条件下对系统行为进行建模。这使我们能够以完全确定性的方式测试系统在各种条件下的反应。

请注意,本节提出的想法也严重依赖于可观测性。

机器学习(Machine Learning)

在复杂环境中,基于规则的方法常常会达到极限,因为要预见所有场景过于复杂。在这些情境下,机器学习(ML)会变得特别有效。

确实,与静态启发式方法不同,机器学习模型可以基于反馈回路持续适应,并从真实世界数据中学习,而不是依赖僵化的、预定义的逻辑。

这使得系统能够:

  • 检测未被明确编程的新兴模式。
  • 动态适应变化,而无需持续的人工干预。
  • 做出概率性决策,而不是依赖严格的 if-else 条件。

强大的团队协作(Strong Team Collaboration)

最后但同样重要的是,我相信在复杂环境中,比在任何其他地方都更甚,强大的团队协作是绝对必要的。例如,清晰地传达变更为何复杂、与队友讨论可用选项并权衡利弊,这些都是关键技能。

在复杂系统中,通常没有唯一正确的答案。因此,一个能够有效协作并共同应对模糊性的团队可以产生巨大的影响,最终带来更强大的决策。

最后思考

重申一下,繁琐问题可以用可重复的解决方案解决,而复杂系统则需要适应性不同的思维方式。这就是为什么识别系统是繁琐的还是复杂的是如此重要:它决定了我们应如何解决问题。

然而,在许多环境中,系统既非纯粹的繁琐,也非纯粹的复杂。某些部分可能遵循结构化、可预测的解决方案,而其他部分则需要适应性和新颖的方法。关键在于学会识别何时需要适应性,何时结构化解决方案就足够了。

作者丨Teiva Harsanyi 编译丨Rio

来源丨网址:https://www.thecoder.cafe/p/complex-systems

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

相关内容

热门资讯

实测分享“518乐游牛牛有透视... 您好:518乐游牛牛这款游戏可以开挂,确实是有挂的,需要软件加微信【4194432】,很多玩家在51...
揭秘”h5牛牛金花房卡透视批发... 【要素一】(KK)微信链接各大厅/房卡介绍微/88231266h5牛牛金花房卡是一款非常火爆的游戏应...
带飞插件!新道游.软件开挂作... 有 亲,根据资深记者爆料新道游是可以开挂的,确实有挂(咨询软件无需打开直...
玩家实测“新天道斗牛如何安装透... 您好:新天道斗牛这款游戏可以开挂,确实是有挂的,需要软件加微信【4194432】,很多玩家在新天道斗...
八分钟解决”详心联盟大厅房卡透... 【要素一】(KK)微信链接各大厅/房卡介绍微/88231266详心联盟大厅房卡是一款非常火爆的游戏应...