作者 | Ashley Davis
译者 | 明知山
策划 | 丁晓昀
持续之战:单体架构与微服务
"从许多方面来看,微服务就是一种僵尸架构,另一种拒绝死去的知识传染病菌。这种病菌从 J2EE(远程服务器 Bean,有人记得吗?)的黑暗时代开始,经历了 WS-Deathstar 的胡闹,现在又以微服务和无服务器的形式存在。"
—— David Heinemeier Hansson (来源)
随着亚马逊云科技在他们的官博中宣称他们放弃了微服务并回归单体架构,单体架构与微服务之间的战争再次爆发。
你对此有何看法?你是支持微服务还是单体?但我想说的是,这种区分有点虚幻,因为人们争论的只是一种虚构的概念:微服务与单体只是整个故事的一个组成部分。
亚马逊云科技的这篇文章被视为他们(作为微服务的长期支持者)已经回头转向单体架构的证据。
尽管文章的标题明显是为了引起关注,但从内容上看,似乎是关于他们从函数即服务向微服务架构(如果不是比微服务更大的分布式应用程序服务)的转变。
但在我看来,这并不重要。这只能说明,亚马逊云科技的一个团队承认他们尝试的架构在一段时间后不奏效,然后尝试了不同的架构,得到了更好的效果。但这又怎样?这只是好的软件开发应该经历的正常过程。
我们都希望专注于最重要的事情,为我们的客户做正确的事情,在微服务与单体的争论中选边站队只会给我们造成阻碍。有时候,我们需要微服务。有时候,我们需要单体架构。(我还不确定我是否会需要 FaaS——但我保持开放的态度)。大多数情况下,我们需要在两个极端之间找到平衡点。
为什么我们害怕微服务?
当然,与单体相比,微服务更难 —— 我承认这一点。但如果你有了自动化的微服务架构,这个论点就站不住脚了。我曾经使用过的一些无缝集成又容易使用的系统就是拥有良好自动化的微服务。另一方面,我曾经参与的一个最困难的项目是一个古老的大单体,几乎没有自动化。我们的日子不会因为选择了单体而变得轻松。
对微服务的害怕有没有可能是对微服务过度炒作的反噬?是的,微服务已经被过度炒作了。微服务不是灵丹妙药。像所有潜在的解决方案一样,它们并不适用于所有场景。当你使用一种错误的架构来解决某个问题(或更糟糕的是,管理层强制要求使用错误的架构)时,我可以理解你为什么会对这种架构充满厌恶。
是否有一部分害怕是来自微服务早期的日子?十年前,微服务确实使开发变得更加困难。但从那时起,工具和平台已经取得了长足的进步,现在比以往任何时候都更容易进行自动化,给微服务开发带来更加无缝和愉快的体验。
也许,一部分害怕来自对复杂性的感知,我认为这是其中很大的一部分。人们会自然而然地害怕(或至少想要避免)复杂性。我说可感知的复杂性,因为不仅仅是微服务会变得复杂,单体也会 —— 只是时间问题。然而,对于微服务来说,复杂性是公开的,所有人都可以看得到,我们必须早日加以应对。在我的“BootstrApping Microservices”一书中,我称之为将痛苦提前,以便能够在开发过程中更容易、以更低的成本应对复杂性。
不幸的是,在现代软件开发中,我们无法逃避复杂性。我们的应用程序正在变得越来越庞大和复杂 —— 即使是普通的单体架构也注定会变得无比复杂。
在现代的大规模软件开发中,我们无法避免复杂性。我们需要使用工具来帮我们管理复杂性,避免它们阻碍我们的开发过程或压垮我们。
为什么微服务看起来如此困难?
"你必须达到这道门槛才能使用微服务。"
—— Martin Fowler (来源)
构建分布式应用程序(不仅仅是微服务)需要更高的技术熟练度。管理大量的服务意味着我们必须拥有自动化管理工具。为了了解我们的服务在做什么,我们还需要跟踪很多东西。随着服务之间的交互变得越来越多,了解这些信息的困难程度将呈指数级增加。
假设你是一个小团队或在开发一个小项目,在不需要微服务的场景中采用了微服务,或者如果你不愿意付出构建和运行分布式系统所需的技能和技术投入,你就不能指望从中得到良好的体验。
另一个可能的痛点是未能适当地将服务与领域对齐。我曾见过一些微服务应用程序与技术对齐但没有与业务需求对齐,导致存在过多的服务和一个不必要的难以管理的系统。将服务分得太小,不必要地增加了系统的复杂性和难度,这是一个问题。
如果你无法正确地将架构与领域对齐,那么无论使用单体还是微服务,都将遇到严重的问题 —— 随着服务数量的增加,这些问题将会被大幅放大。微服务既能带来性能方面的伸缩性,也会放大已经存在的问题。
这只是一个伸缩性问题吗?
"如果你无法应对单体的复杂性,凭什么认为微服务就是良方?"
—— Simon Brown (来源)
微服务的真正问题是它们只是放大了已经存在的问题吗?
一个糟糕的微服务实现比糟糕的单体架构糟糕 X 倍(X 是你的分布式应用程序中服务的数量)。随着分布式应用程序中通信路径的指数级增加,情况甚至更糟。
如果你没有合适的工具、技术、自动化、流程和组织来应对单体,那么你凭什么认为你可以处理好微服务?
微服务不仅带来性能和开发方面的可伸缩性,也带来了困难程度的伸缩。如果你在构建和维护单体架构时感到困难,转向微服务也并不会给你带来任何好处。
微服务应用程序也是一种单体,只是服务的数量增加了、服务的大小变小了而已。如果疲于应对单体架构,却认为微服务是良方,那么请再三思。
我认为微服务不仅在性能和开发方面带来了可伸缩性,也带来了困难程度的伸缩。微服务有它的优点,但这些优点并不是完全免费的。
微服务的成本
"微服务并非免费午餐。"
—— Sam Newman (摘自“Building Microservices”)
微服务到底是什么?为什么我们要将应用程序划分为独立的服务?
微服务有许多众所周知的好处:
但这些好处并非微服务的全部,我们也需要为此付出成本:
对于任何一种工具、技术、架构或任何我们想要使用的东西,我们必须问自己一个问题:收益是否超过了成本?如果收益超过了成本,你将在使用这些技术时获得良好的体验。如果没有,你将在痛苦的时光中度过。
管理复杂性
"微服务支持大规模、复杂应用的持续部署。"
—— Chris Richardson (来源)
微服务有许多优势,但我们使用它们的真正理由是,它们可以帮助我们管理应用程序日益增长的复杂性。
没错,微服务不是复杂性的根源,而是解决复杂性的方法。
所有的应用程序都将变得复杂,即使是单体也无法避免。微服务为我们提供了将复杂性分解为更小、更简单、更易管理的构建块的工具。
微服务通过将复杂性分解为简单而隔离的部分来帮助我们管理复杂性。我们也可以在单体架构中做到这一点,但你需要一个纪律严明和积极主动的团队来保持设计的完整性,不至于变得一团糟。
我们可以使用微服务来抽象和将软件组件化。当然,我们也可以在单体架构中做到这一点,但微服务还为我们提供了牢固的组件边界,更不用说其他优势了,如独立部署和故障隔离。
可能性频谱
"不存在放之四海而皆准的架构模式。"
—— Dr. Werner Vogels (来源)
我在本文一开始问了一个问题:你是支持微服务还是单体?
回到本文的标题,这不是一个非此即彼的选择。从一个大服务(单体)到许多小服务(微服务),在它们之间还有许多其他可行的选择。
这不只是单体与微服务二选一,它们之间存在一种可能性频谱。如果你将自己固定在支持单体或微服务的立场上,就将错过它们之间丰富的架构多样性。
你不必人为地将自己对准频谱的任意一端。你甚至不必将自己固定在其中任意的特定位置。尽管一些人想让你这样认为,但并不存在所谓的正确的立场。你选择的位置应该与你的团队、业务、项目或客户对齐。只有你可以决定应该处在频谱的哪个位置。
投资回报递减
随着你在频谱的右侧移动,你将获得微服务的好处,但向右移动也伴随着成本和困难的增加。我们需要确保转向微服务的成本是我们愿意承担的。
如果你不是为了管理复杂性,不需要微服务的其他好处,或者在管理单体的自动化和技术方面存在困难,那么你应该尽量留在频谱的左侧。随着你需要微服务的程度的增加,应该朝着频谱的右侧靠近。
随着投资回报递减,一直迈向完美的微服务乌托邦可能是不值得的,但只走其中的一部分道路可能会带来高回报。
此时我们要清楚地认识到,我们不需要达到(我喜欢称之为)微服务乌托邦的程度才能开始享受无服务的好处。无论我们是否达到了频谱的另一侧,我们只要朝着频谱的右侧移动一定程度,都会得到切实的好处!
有很多原因使我们不想迈向完美的微服务。(首先,谁来决定完美的定义?)当我们开始向右侧推进时,将看到巨大的回报。但随着继续向前推进,投资回报开始递减。我们越是朝着更小的服务前进,成本就会超过好处。在杂乱复杂的现实世界中,实现完美的微服务是很困难的,更不用说这其实是不必要的。但这并不意味着朝着那个方向前进不会有所裨益。
混合模型
如果不需要一直推进到微服务一侧,那应该在哪里停下来呢?答案是在中间的某个位置,在这个位置有一些权衡可以提高我们的开发速度和能力,但成本不会超过好处。
我喜欢将在中间的某个位置看作是两全其美。是的,我们可以拥有单体(或多个单体),单体周围环绕着一些微服务。持有这种务实立场的我是否成了某种异教徒?这种架构的实际好处在于我们可以将单体的好处与微服务的好处混合起来。单体代码库的便利性和简单性,加上在必要时可以利用的微服务的灵活性、可伸缩性和其他好处,使得这种架构成为一个理想的选择。如果有必要,我还可以逐步从单体拆分出单独的微服务,让某些功能或任务可以从中受益。
混合模型并不是什么新想法,这就是现实世界通常的样子(在中间的某个位置),尽管人们在网络上继续争论不休。
David Heinemeier Hansson(单体支持者)似乎很喜欢这个想法,他将其称为城堡架构。
大小真的重要吗?
"也许‘Micro’是一个具有误导性的前缀。它并不一定是‘小’的意思。大小实际上并不重要。"
—— Ben Morris (source)
服务越小,就越 Micro,作用就越小,我们就需要越多的服务。随着我们减小服务的大小并增加服务的数量,困难程度也会提升。
或许,我们应该停止专注于微服务“Micro”的部分。我认为这会导致人们将自己的服务变得过于小,而这一定会导致在使用微服务时遇到困难。
我甚至不确定我们是如何如此专注于使它们变得尽可能小的。我们的意图是将软件拆分成不同的部分,分离责任,让每个部分都比整体简单,从而更容易管理系统的复杂性。但如果服务过于小,我们可能会被复杂性淹没,无法管理好它们。
尽管每个人似乎都有自己关于微服务大小的看法,但现实是,微服务的大小没有固定标准。
所以,我们应该停止争论服务的大小,我们应该谈论的是“合适大小”的服务,也就是适合实际情况的适当的大小——单体或者是频谱较小的一端。我们的服务,无论大小如何,都应该根据业务和领域来决定。微服务大小只是后话,整体的组织更为重要。
问题不在于使服务变得尽可能小,服务小到超过某个程度就会适得其反。它们越小,就必须与系统的其余部分进行更多的交互才能完成任务。交互越多,我们就需要付出更高的网络传输成本,更不用说这会使得它们之间的交互变得更加难以理解。我们需要在服务大小和服务有多喋喋不休(Chatty)之间取得良好的平衡(感谢 Damian maclennan 提供了"喋喋不休"一词)。
选择对你来说有意义的服务大小,一些服务比其他服务大,这并不是什么问题。请不要让你的强迫症决定服务的大小——这可能会阻碍一个出色的架构的出现。将服务变得更大或更小本质上没有对错之分,只要你找到适合自己的。
不要害怕改变你的想法
"老实说——我以前也这么做过,从微服务转向单体,然后再转回来。两个方向都有尝试过。"
—— Kelsey Hightower
有时候,为了了解新技术是否适合我们的项目,我们必须进行尝试。所以不要害怕尝试新技术,不要害怕尝试微服务或混合模型,看看它们是否有效。
尝试之后不要害怕改变你的想法,并撤销之前做出的决定。承认某些事情不成功并不是件坏事,这是我们为了取得成功所需要做的事情。尝试不同的事情,进行各种实验,并放弃那些没有成功的事情。因为微服务在特定项目上不适用并不意味着它们对于其他团队或项目也是糟糕的选择。
或者更好的是,保持开放的思维,这是不让自己与新思想和新思维隔绝的最佳方式,这些可能是你做好下一个项目所需要的。
延伸阅读
Bootstrapping Microservices(https://www.bootstrapping-microservices.com/)
Rapid Fullstack Development(https://rapidfullstackdevelopment.com/)
查看英文原文:
https://www.infoq.com/articles/monolith-versus-microservices/