作者:Ebin John
来源:https://www.xttblog.com/?p=4775
Ebin John是ThoughtFocus的技术架构师。
现在是2020年。如果你想要我介绍微服务是什么东东,本文可能不适合你,你还是把宝贵的几分钟花在别处吧。但如果你沉醉于微服务的种种成功故事,想靠这味“灵丹妙药”实践一番,那就请读下去。抱怨会让你失望几分钟。
虽然微服务概念流行已有一段时日,但最近与几个人进行一番交谈后,我觉得有必要写下来。我受邀参加了一个仲裁小组,为“微服务是什么?我们应该采用这种架构作为解决方案吗?”这个发人深省的问题给出答案。
虽然问题的第一个部分很容易回答,第二个部分回答起来颇为棘手。交谈了几分钟后,有几个事实很清楚。
- 受益者将微服务架构应用于他们即将推出的产品,他们寻求一番肯定。
- 仲裁小组中相当多的人不懂技术。而随着交谈的“技术性越来越强”,交谈对于仲裁变得无关紧要了。
- 长时间的停顿和无人提问表明大家对Web服务不熟悉,对微服务不熟悉更不用说了。
我不会怪他们不知道Web服务是干什么的或者微服务如何给他们带来好处或坏处。他们准备搭上微服务这趟彩车,却不知道前方有什么后果等着!
我头一次听到“微服务”这个词还是在2013年,当时YouTube上的一段视频解释Netflix服务的架构。信息太多一时消化不了,我毫不犹豫地快进了视频。对于当时想进入设计原则领域的人来说,这个概念太复杂了。但是新的项目方案宣布采用微服务后,它很快成了一股风潮。该项目的设计令人着迷,它仍是我曾经接触过的最佳代码库之一。
老实说。模块化设计的广泛前景让我无暇顾及其弊端。而我就是一名无知的开发人员,离devops躲得远远的,因此又隔了一层面纱。五年后,我在开发一款全新的产品,与一批新的人员共事。我见过设计糟糕的微服务以及业余的devops战术引起的种种问题。我很快认识到了微服务的弱点。这也让我得以从整体上打量架构。为时太晚,但胜过根本没有觉悟!
看到微服务同时扮演正派和反派的角色之后,我劝告自己要成为唱反调的人。如果你是倾向于将微服务作为默认架构的架构师或设计师,我劝你硬着头皮向自己问几个问题。
你的应用程序庞大得足以细分成微服务吗?
让我们承认吧。并非所有应用程序都庞大得以足分解成较小的服务。顾名思义,微服务是一大堆各司其职的小服务。在理想情况下,我们会要求每个服务本身都是一个完整的应用程序。
每行代码的成本
下面假设对微服务与整体式服务“每行代码的成本”作一番比较。由于微服务在人力和计算成本方面需要的最少资源,微服务需要的成本较高,哪怕是轻量级微服务。而成本是每个人都关心的问题;不然,你可能根本不会做出使用微服务的决定。
当然,你的代码库在将来会越来越大,代码库本身可能会添加一个新的领域。但你应该永远记住:当你接近阈值时,设计良好的代码库始终可以切换到微服务。
你是否果真需要扩展应用程序的各个组件?
假设一下。产品负责人向你提出了使用人力资源管理系统(HRMS)应用程序的想法,以满足员工上万人的组织的需求。作为技术爱好者的你立马有一个解决方案:微服务架构。
当然这是极端的例子,不过你明白了其中的道理 !!
使用微服务架构的主要优点之一是易于扩展单个组件。我们可能会找到组件需要单独扩展的大量应用程序,但你的应用程序果真需要这么做吗?
你的事务跨诸多服务吗?
现在,这可能是最难做出的战略性选择之一。跨多个服务的事务是整个架构的一个负担。解决跨服务的事务意味着:服务之间的互锁、一系列难以追踪的僵局,以及会危及服务健康状况、有时甚至是工程师健康状况的竞态条件。
按照定义,REST服务是无状态的。它们不应该参与边界不仅限于一项服务的事务。在高性能环境下,两阶段提交[2PC]是不必要的麻烦。而SAGA模式只会增加你没有准备好的另一层复杂性。
由于微服务坚持采用分散式数据管理——这个做法值得称赞,微服务带来了最终一致性问题。如果是整体式应用程序,你可以在单个事务中一起更新一堆东西。微服务需要多个资源才能更新,而分布式事务不受欢迎(这有充分的理由)。因此,开发人员需要意识到一致性问题,并在做代码会后悔的任何事情之前,搞清楚如何发现何时不同步——Martin Fowler。
可能会有跨服务的事务吗?
是的,绝对有可能。
但是,是否值得在无状态服务中实施一系列操作?
恐怕不值得!!
服务之间是否需要经常联系?
在传统的整体式服务上,每个微服务实例由系统内的模块加以表示。模块之间的联系在内存中进行,延迟接近零。微服务的引入意味着,联系由内存中事务完全变成了通过网络传达指令。
有众多久经实践考验的解决方案,但是它们都有代价:延迟。从内存中事务改为基于网络的联系会将延迟从纳秒变为微秒。想象一下,三个不同的服务通过网络彼此联系。假设每个服务调用要花费100微秒(这在负载情况下并不少见),那么到头来单单在网络上就要花掉300微秒。
而一些应用程序本质上与组件和服务紧密集成。添加的通信层可能会给处理实时数据的应用程序造成灾难性的后果。设想一下外科手术或航空公司交通管制方面的通信延迟!
另一些缺点
- 增加了复杂性——当然,复杂性无法量化,只能以相对的方式进行比较。虽然微服务原本旨在通过将应用程序分解成小组件来降低复杂性,但架构本身部署和维护起来却很复杂。
我们要更清楚地认识到这点,即普通的IT部门并没有像Netflix的工程团队那样的技能组合。
- 分布成本——微服务是具有模块性的分布式系统。但是同样的分布确实要付出代价。你的整体式服务会部署在大型虚拟机或首选容器上。但如果是微服务,除了多个虚拟机或容器外,服务需要独立部署[在理想的环境上]。当然服务可能很小,但你可以计算一下总成本。记住,我甚至还没有谈到服务编排和维护涉及的成本。
- 改编Devops——这可能有益也可能有害,取决于你所站的角度。Devops是一种被广泛接受且经过验证的运维解决方案。但如果你是小型企业组织的成员,成立一支Devops团队会是弊大于利。不过有一点倒可以肯定,要是没有专门的devops团队,你就无法维护和监控微服务。
- 集成紧密——一些应用程序天生就紧密耦合。将它们分开来以“适应”架构将会带来灾难。
- 缺乏经验——缺乏经验对任何问题来说都是重要因素,并不仅限于SOA。但是说到微服务,由于拥有抽象定义,造成的危害尤其大。如果你的微服务部署因部署顺序而将你逼到被动的地步,或者某一个依赖项服务出故障后导致崩溃,那么你为时已晚。
- 端到端测试——一个典型的整体式应用程序将使你可以几乎立即启动并运行测试。若没有切实可行的编排,有多个相互依赖的服务会延误测试。
- 混乱的数据合约——在团队内部设计和订有数据合约与团队之间共享数据合约大不相同。你在接触微服务时,你的团队可能不在同一个地区,更不要说团队成员都采用同一种编程语言了。为特定要求制定数据合约会耗费你的时间和空间。
- 遗留代码库——老实说吧。对于我们大多数人来说,处理遗留代码库是一项日常工作。它是大多数企业组织的立足之本。迅速变化的技术进步让我们处于领先,而同时也使我们离遗留代码库渐行渐远。 你确信刚开发的RabbitMQ框架可以与托管在IBM AIX服务器上的遗留应用程序很好地兼容吗?
- 调试令人痛苦——每个服务都会有自己的一组日志文件要审查。更多服务意味着更多的日志文件。
结束语
我在这里是要告诉你“别使用微服务”吗?
绝对不是!!
微服务的名声一向不太好。没错,微服务解决了我们都认为无法解决的问题。Netflix改编微服务的故事启发了好多人。而试水微服务的并不仅限于Netflix。优步、SoundCloud和亚马逊就是几个现成的例子。别以为成功案例仅限于消费者应用领域。我近距离过接触过一家美国医疗保健界巨头,每次打开源代码,都着迷于设计方面的机会。
如果你在五年前紧跟微服务潮流,我不会谴责你的盲目轻信。今非昔比,我们现在能做的就是对微服务坦诚相见。而眼下是2020年,我们忙得不可开交。如果不必要地引入微服务架构,只会将你的不良代码变成不良基础架构。
我喜欢满怀热情的程序员。我曾经是这样的程序员,现在依然是。他们崇拜所做的事情,不遗余力地解决别人的问题。但是你不可能将同样的精力倾注到决策中;决策不当,会害你和贵企业蒙受重大损失。很抱歉,要让你失望了。微服务不应该是你的默认应用程序架构。微服务也不是你所寻找的灵丹妙药。应遵循KISS(力求简单)和YAGNI(你不会需要它)原则,保持有条不紊。
作为技术倡导者和发烧友,你有权喜欢自己青睐的技术。但是让你脱颖而出的是能够在 “正确的选择”与“你青睐的选择”之间作出切合实际的选择。