过渡架构的作用:一周处理近百起高严重性事件,如何重写这个技术负债系统?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"本文最初发表于 Medium 博客,经原作者 Zak Islam 授权,InfoQ 中文站翻译并分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"导读"},{"type":"text","text":":软件领域的圣经《人月神话:软件项目管理之道》,由 IBM System\/360 系统之父佛瑞德・布鲁克斯所著,全书讲解了软件工程、项目管理相关课题,内容源于作者在 IBM 公司 System\/360 家族和 OS\/360 中的项目管理经验。这些经验概括出了第二系统效应,又称第二系统症候群,它认为,在完成一个小型、优雅而成功的系统之后,人们倾向于对下一个计划有过度的期待,可能因此建造出一个巨大、有各种特色的怪兽系统。第二系统效应可能造成软件专案计划过度设计,产生太多变数,过度复杂,无法达成期待,并因而失败。本文作者反思了他在 AWS 的时光,提醒后来者不要随意重写系统,而是要用过渡架构的方法来达到目标。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"2015 年在 AWS,我接手了一款技术债累累的产品。在一个美好的一周里,我们共处理了 70~100 起高严重性事件。这个系统不具备基本的协议,如 API 速率限制、工作优先级、或者像隔离噪音邻居这样的防御功能,但是它很容易在一秒内处理上百万个请求。换言之,在它后面有一个巨大的集群,但是这很有用。在对这个系统进行首次评估的时候,我们真的不知道从何入手。摆在我们面前的挑战似乎不可逾越。我们知道重写系统是必要的,但是我们必须获得重写系统的权利。AWS 的一个核心"},{"type":"link","attrs":{"href":"https:\/\/twitter.com\/tacertain\/status\/1121429740596785152?lang=en","title":null,"type":null},"content":[{"type":"text","text":"工程原则"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"……工程师们感谢我们的前辈。我们赞赏工作系统的价值,以及其中所体现的体验。我们知道,很多问题本质上都不新鲜。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"简而言之,它意味着尊重先前的事物。那时,我想我们并没有真正意识到,随着我们职业生涯的发展,这个原则将如何影响我们作为工程师和领导者的思维方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"重写"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在那个时候,重写系统的想法很有诱惑力。现在回想起来,我真的很高兴我们没有这么做。而在我后来的职业生涯中,我了解到这种诱惑有一个"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Second-system_effect","title":null,"type":null},"content":[{"type":"text","text":"名字"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第二系统效应"},{"type":"text","text":"(又称"},{"type":"text","marks":[{"type":"strong"}],"text":"第二系统症候群"},{"type":"text","text":")是指由于期望值过高和过度自信,小型、"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Elegant","title":null,"type":null},"content":[{"type":"text","text":"优雅"}]},{"type":"text","text":"而成功的系统往往会被过度设计的、"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Software_bloat","title":null,"type":null},"content":[{"type":"text","text":"臃肿"}]},{"type":"text","text":"的系统所取代。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"虽然这个系统在当时处于一个不太理想的状态,但是它并不需要重写;它只是需要一点爱❤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"过渡架构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"过渡架构实际上是迭代开发的一种漂亮说法。这意味着,要小步前进。回到这个系统:我们决定采取迭代的方法来修复我们所继承的“烂摊子”;将我们重写它的愿望搁置一边。我们有一座大山要攀登,但我们必须迈出第一步。首先,我们审视了所有的问题,然后创建一个图来排列这些问题。排列图看上去像这样……"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/06\/0620611b43aba40fddab71e336753979.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"这张图给了我们一种有趣的视角(图中数字系虚构)。一旦我们看到了上图中的根本原因,我们就知道系统存在两个大问题。我们需要在系统中加入速率限制,然后想办法扩展服务 X,这样它就不会在负载下崩溃。我们把小团队分成几个"},{"type":"link","attrs":{"href":"https:\/\/medium.com\/productmanagement101\/spotify-squad-framework-part-i-8f74bcfcd761","title":null,"type":null},"content":[{"type":"text","text":"小组"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",集中力量解决这两个具体问题。我们承认这个系统的其他部分也是一团糟的,但是我们选择接受它们,因为我们知道这些问题为我们的客户解决了问题,但是却给我们带来了操作上的麻烦。几次冲刺过去了(感觉似乎是永恒的),我们最终实施了速率限制的第一次迭代。太棒了……是吗?错了!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"迭代 1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我们的速率限制系统的第一次迭代是一个内置于部署到生产中的软件包的静态文件。这就是说,我们必须更新这个文件,对其进行签入,进行代码审查,进行构建,然后将其部署到生产中——就在事件发生的中间!那听起来很恶心,但确实有效!虽然我们并没有减少事件数,但是我们事件的平均修复时间(Mean time to resolution,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"MTTR"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":")下降了一半。那是个巨大的胜利。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"迭代 2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"下一步,我们需要确定如何在生产中应用配置更改,而无需构建代码,然后进行部署。用 S3 桶中的文件的引用替换静态配置文件。接着,我们构建了一个独立的工具,它可以把变更从开发人员桌面推到这个文件(经过适当的检查和平衡),我们已经更新了服务,每隔几分钟就重新加载这个文件。这听起来似乎很简单,但是我们必须对它进行深入的思考。即使 S3 出现故障,我们也必须确保服务能够正常运行。我们必须确定服务是否会失败,是否对所有客户应用默认限制,最终处理整个集群的一致性,等等。这是很难解决的问题,但是我们花了很多时间来回答这些问题:因为我们知道迭代 1 已经用于生产。这样我们可以赢得很多时间。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"迭代 3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"最后,我们回答了所有困难的问题,将迭代 2 引入生产。对此,我们的胃口也越来越大了。虽然我们进一步降低了 MTTR,但是工程师们希望我们有一个能自动对传入的请求进行速率限制的动态系统。感觉到我们需要这个系统。为了更好地减轻我们的工作负荷,我们必须拥有这个系统。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"为了构建这样的系统,我们需要:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"一种低延迟的数据分配协议,用于报告来自整个集群中主机的按客户分列的请求速率。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"一种半分散的服务,可以基于启发式方法作出某些决策。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"更新请求限制的自动化系统。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"对了,这种系统必须具有高度的弹性和容错能力。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我们考虑了这个系统的成本和复杂性后,决定不建立它。大家都认为,我们在迭代 2 中建立的系统足够好:它能提供我们需要的东西,运行良好,最重要的是它非常可靠。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"完美的系统"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我不时地反思我在这个团队中的时间,尤其是那些限制速率的项目。我们知道我们需要在某个时间点上进入迭代 3。如果我们从那里开始,我们会建立一个高度复杂的系统,它会检查所有的复选框,花费我们大量的时间,并且只返回我们正在尝试解决的原始问题的一些价值,同时在此过程中产生新的问题。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我们采用类似的迭代方法来扩展各种服务,在服务之间实现重试,并提高性能,以至于代码库仅与我们最初集成的代码库有相似之处。在管理运营开销时,我们不大可能重写系统。最后,我们会面临第二系统症候群,一个冗长的、团队士气低落的项目,以及新类型的技术挑战。运用尊重前人的原则鼓励我们欣赏工作系统的价值及其带来的经验。在我的职业生涯中,这是我获得的最有影响力的经验之一,我想把它传授给每一个愿意学习的人。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"结论"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我在这个团队的时光教会了我许多宝贵的经验。其中最重要的两条是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"避免重写的诱惑。从表面上看,重写系统似乎是避免固有复杂性的正确做法。当你欣赏工作系统的价值和它们所体现的教训时,重写往往就不那么吸引人了。(有时你必须重写一个系统。这很正常。当你不得不重写时,坚持复制有效的东西,要坚持有效的东西,做最小的必要改动。)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"过渡架构——北极星固然不错,但往往应该仅仅是一个设想。迭代或过渡架构有助于消除不必要的复杂性,并提供一个足够好的解决方案。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"这是从经验中学来的,我希望别人不必用艰苦的方法就能学到这些经验。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"原文链接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"https:\/\/zakisaninja.medium.com\/back-in-2015-at-aws-i-took-over-a-product-that-was-riddled-with-technical-debt-65b3670966e6"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章