当前位置: 首页 > 科技观察

做好这七点,避免微服务落地失败

时间:2023-03-13 15:36:35 科技观察

本文翻译自微服务失败的7种方法[1],张海丽译。作者HollyCummins总结了她见过的一些导致微服务落地失败的情况,提出了7个重要的关注点,引导大家尽量避免。译者在工作之余完成了翻译,其中难免有不当之处。欢迎读者指正。本文主旨:微服务是手段,不是目的。分布式不保证解耦。合同测试是任何微服务架构的重要组成部分。分解需要发生在前端、后端和集成。层,以及在业务逻辑上,如果企业不具备快速自主发布微服务的能力,微服务的很多优势就会丧失,实现云原生。在去年11月的QConPlus上,我介绍了一些微服务的不正确使用方法[3]。这些问题是根据我的经验整理出来的,是我在客户现场反复看到的一些问题。我看到的第一个问题是我们有时甚至不知道问题是什么。人们觉得我们应该做微服务[4],但我们并没有真正花足够的时间来定义我们为什么做微服务。我们试图解决什么问题?现在有什么问题困扰着我们?我们做微服务之后有什么更好的?这是一个非常自然的本能问题,尤其是对我们技术人员而言。我们想开始直接用微服务解决问题,同时想尝试其中一些很酷的新技术。虽然这些也很重要,但是应该更清楚我们要通过微服务解决什么问题。容器技术让这种“开始用微服务解决问题”的情况变得更糟:因为容器是一种近乎神奇的技术,这使得它本身就是一个很好的解决方案——它是如此的轻量级,它是如此的便携,它让很多事情变得更好。所以我们最终决定:“既然我已经有了这些容器,那么只在一个容器中运行我的应用程序将是对容器容量的极大浪费。我应该在尽可能多的容器中运行它!”不幸的是,“没有足够的容器(来释放伟大的容器技术的能力)”不是一个合理的(来辨别我们为什么需要微服务)问题陈述。简历驱动开发我看到的另一个问题是简历驱动开发[5]。我们在看简历的时候,有时候会觉得应该在“微服务”部分写点什么。既然什么都不写肯定不好,我们就会想:“我可以通过重新设计我公司的技术架构来让我的简历更漂亮”。当您阅读本文时,您可能会想,“不可能,这太功利了。没有人真的只是为了改善他们的简历而做出公司结构决策吗?”但事实证明……有人会这样做。RedHat公司[6]最近对基于容器的开发[7]的主要驱动因素进行了调查。职业发展是第一驱动因素。职业发展是简历驱动发展的更好说法。避免在简历中提及微服务部分是一件很重要的事情,因为如今微服务几乎是一种新的主??流技术理念。即使我们现在不在找新工作,我们也不想成为异类——当我们环顾四周时,似乎其他人都在做微服务。所以一个很自然的想法就是,如果TA都在做微服务,我为什么不做微服务呢?我称之为“微服务嫉妒”。微服务不是目标“微服务羡慕”是一个问题,因为微服务不是我们应该羡慕的东西。我们的一位技术顾问同事有句话说,如果一个客户一直在谈论Netflix的技术并要求使用微服务,他就知道这个合作可能有问题。几乎可以肯定,他们转向微服务的原因是错误的。如果对话更深入一些,涵盖耦合和聚合等内容,那么他??就会知道客户在转向微服务的原因上存在真正的问题。微服务改造的出发点不应该是微服务本身。微服务是实现业务敏捷性或弹性或同等更高级别目标的手段。事实上,微服务甚至不是唯一的手段。这只是一种手段。分布式单体重要的是要问:“你有微服务吗,或者你有分布在数百个Git存储库中的单体吗?”不幸的是,这正是我们经常看到的。分布式单体是一件可怕的事情——很难说清它是什么,而且它比纯单体更容易出错。在传统的单体应用中,所有内容都包含在一个开发环境中,您可以获得编译时检查和IDE重构支持等好处。由于您始终在一个进程中执行,因此您可以保证函数执行。你不必担心记住分布式计算和服务发现的谬误,处理你试图调用的东西已经不复存在的情况,事情更安全。另一方面,如果我们去除单体应用的安全性但保持耦合,我们最终会得到“云原生意大利面条”。“意大利面式架构”一词可以定义为阻碍企业快速解码和转换其应用程序和数据以满足不断变化的需求的能力的信息技术问题。“意大利面条建筑”是从一盘意大利面条的外观衍生出来的比喻。每个意大利面条代表每个业务工具,它们纠结成无限复杂的线程。——摘自《 什么是 “意大利面架构” 和如何避免它 [8] 》。[编者按]“意大利面条”的比喻似乎可以理解:虽然各种服务看似分离,但它们在各个层次上耦合混合在一起,也容易出现断裂和崩溃。分布式不等于分离几年前,我受邀为一个苦苦挣扎的项目提供帮助。当我进入项目时,团队对我说的第一句话是“每次我们更改一个微服务时,另一个服务就会中断”。如果您一直在关注微服务的优势,就会知道这与应该发生的情况完全相反。微服务应该是相互独立和解耦的。然而,如果你让你的系统分布式,解耦[9]就变得不那么容易了(这是有代价的)。虽然Distributed和Decoupled都是以D开头,但它们本身并不是一回事。很可能拥有一个高度分布式的系统,在承受分布式带来的所有痛苦的同时,仍然完全纠缠和耦合。上面提到的困境就是在这种情况下发生的事情。当我开始探索代码库时,我一直在每个存储库中看到相同的代码。这个应用程序的对象模型相当复杂,大约有20个类,其中一些类有70个字段。这是一个非常复杂的结构。微服务开发的原则之一是完全DRY(Don'tRepeatYourself),避免公共库,因为它们是耦合的源头。在这种情况下,为了避免与中央对象存储库耦合,每个微服务在其代码中都有对象模型的剪切和粘贴副本。但是如果域结构(DomainSchema)仍然是共享的,那么还是有耦合的。复制目标代码并没有消除耦合,它只是消除了编译时检查的可能性。如果一个字段名称发生变化,它仍然会破坏每个人,但这种破坏直到运行时才会发生。这个悲伤的故事表明了领域驱动设计原则在微服务中的重要性。我们想要实现的理想情况是每个微服务都可以整齐地映射到一个领域。这样做的一个副作用是您的微服务具有非常小的接口粒度,这也是您做对的标志。如果我们沿着技术边界而不是领域边界进行划分,我们最终会遇到我所看到的情况;每个微服务都有一个巨大而脆弱的接口。结果是零散的“意大利面”一团糟。MarsClimateOrbiter尽管从技术上讲它是一个航天器,而不是微服务平台,但MarsClimateOrbiter[10]是分布式和解耦之间区别的一个很好的例子。美国宇航局于1998年发射了火星气候轨道器,其任务是研究火星气候。可悲的是,轨道飞行器没有成功环绕火星;相反,漫游者坠入了火星。NASA的事后调查发现,问题源于不同团队构建的两个不同控制系统之间的关系。大多数时候,转向是由探测器本身的系统完成的。每隔几天,当轨道飞行器进入地球视野时,佛罗里达州的监督控制系统就会发出航向修正。这与系统的分布式程度差不多;它的一部分在太空中。但两个系统之间的领域实际上是相似的:都处理发动机推力的计算。两个团队没有就界面的外观进行足够的沟通,所以他们最终使用了不同的单位。太空部分使用公制单位,地球部分使用英制单位,所以灾难发生了。我们可以肯定地说,在这种情况下,系统是非常分布式的,但是这种分布并没有帮助。当涉及多个团队时,经常会出现面向消费者的合同测试的微妙沟通问题。令人高兴的是,有一个很好的缓解措施:消费者驱动的契约测试[11]。在IDE不帮助我们进行类型检查的系统中,我们需要测试我们的集成,但我们希望尽量减少全面的集成测试。集成测试很繁重,运行成本高,而且内在耦合。如果我们已经投资于开发微服务,我们不想退回到测试并做一个巨大的集成。那么,我们如何让自己相信我们正在构建真正有效的东西呢?数据模拟(Mock)是一种常见的解决方案,但是数据模拟本身就有一个问题。为了建立数据模拟,生产团队和消费团队会在开发之初就界面的情况进行对话。他们达成协议,然后消费团队开始尝试编写一个模拟数据,看起来像是他们对生产团队所说的代码所说的内容的理解。在一个理想的世界里,他们会做得很好。问题是消费团队经常把自己的假设写到模拟中,他们可能不知道其他代码长什么样,是否适合做这部分模拟,毕竟不是消费团队写的代码团队。在好的时候,他们得到了正确的结果。单元测试全部通过,集成阶段继续通过,一切正常。不幸的是,这并不总是发生。有时实际的实现与消费团队的理解不同,要么是因为生产团队改变了主意,要么是因为某个地方的某人做出了错误的假设。在这种情况下,测试仍然会通过。但是,当我们真正集成真正的服务时,它失败了。问题是,模拟行为未通过真实服务进行验证。制作团队很可能从未见过创建的模拟。更好的选择是进行消费者驱动的契约测试。契约测试的美妙之处以及它与模拟的不同之处在于,双方都与契约测试进行交互。对于消费者来说,合同测试就像一个方便的模拟。另一方面,合约测试对于生产团队来说也是一种方便的功能测试。它比像OpenAPI[12]这样的语法检查更深入的验证。合同测试实际上也检查语义和行为,这节省了生产团队编写功能测试的时间。如果一切兼容且正常工作,则所有合约测试都将通过。这是一个快速的信心提升,因为它们便宜且运行轻便。如果生产团队破坏了某些东西,他们的测试将失败并在破坏性变更逃逸到集成环境之前提供早期警告。如果API发生变化,则双方(或连接的中介机构)会提出新版本的合约。那里有几种不同的合同测试系统。如果您在Spring生态系统中,那么SpringCloudContract[13]工作得非常好。如果你是一个多面手,那么我真的很喜欢Pact[14]。它几乎可以绑定您可能使用的所有语言。企业毛球当然,即使我们梳理了所有的测试,即使我们在业务逻辑层有一套漂亮的解耦微服务,也不能保证成功。我们的系统中还有许多其他元素,我们在制定真正干净的微服务架构时可能没有考虑过。我们在业务逻辑的开发上投入太多,以至于忘记了前端和后端,以及所有的粘合层。在企业架构中,胶水层是很有可能存在的,而且是粘性的。我们的一位架构师将此称为“企业毛球”。如果我们将所有的功能分解工作都集中在业务层上,我们往往会得到一堆夹在单体前端和单体数据库层之间的整齐解耦的微服务。在这些类型的系统中,改变将是一个挑战。然而,作为一个行业,我们在分解数据库方面做得越来越好,这样它们就可以映射到单独的微服务上,并且我们正在开发微前端。但我们还没有完成分解。如果系统不是很复杂,我们会有一个集成层。这可以是消息系统,也可以是将复杂系统整合在一起的其他集成解决方案。即使在对架构的其余部分进行了现代化改造之后,集成层通常仍然是单一且不灵活的。团队本身可能承受着巨大的负担——我的同事们称之为“恐慌三明治”。因为集成层是整体式的,所以他们必须仔细协调所有更改,这会阻碍其他人。这可能会导致很多挫败感,尤其是对于集成团队而言。从表面上看,他们似乎反应迟钝且行动迟缓,尽管他们正在努力工作。要解开这种耦合,我们需要采用模块化集成模式。如果我们不分离集成层、数据库和前端层会怎样?几乎可以肯定我们的微服务不会做我们想做的事。“毛球”各部分之间的依赖关系会阻止任何部分快速移动。业务层的微服务将无法独立部署,部署速度明显不连续。阻碍释放的阻力你们中有多少人经历过这种情况?你真的很努力,你创造了一些了不起的东西;你知道用户会喜欢它,但它还没有掌握在他们手中。价值摆在桌面上,但您的精彩内容无法发布。即使你有一个微服务架构,你也会有一个发布板。其他所有的微服务都需要同时发布,因为需要一起测试,做起来成本太高,除非恰好是大批量的服务同时发布。即使是填写一份发布清单也很昂贵。人们常常害怕释放,因为过去他们可能因糟糕的释放而深受伤害。发布清单、发布板、单线程测试和其他发布方法都是为了减轻那些已知的风险。因为发布截止日期在整个组织内共享,所以我们最终不得不争分夺秒地在截止日期前推出功能。当然,这也使得发布的风险更大。有人正在跟踪一个电子表格,其中包含所有微服务之间的依赖关系,这些微服务之间的耦合程度超出了应有的程度。但是,发布仍然必须按计划执行。当我们选择微服务时,这不是我们想要发生的!所有这些本意良好的流程都变成了拖累,阻碍了价值到达用户手中,而且实际上常常增加风险。测试自动化通常,我们如此害怕发布的原因是其中涉及的手动工作量。特别是,真正给我们信心的测试并不是自动化的,所以我们需要做很多工作来确定我们的应用程序是否有效。当我拜访客户并听到“我们的测试不是自动化的”时,我听到的是“我们不知道我们的代码目前是否有效,但它可能有效。上次我们进行手动QA时它起作用了;我们希望它仍然有效”。这是一个可悲的情况。如果你关心你的测试,自动化它-质量是你应该关心的事情。特别是如果架构已经是“意大利面条”并且耦合已经悄悄出现,那么很可能休息一下。去面条很难,所以我们想在快速反馈的地方尽早发现它。休息。如果你要成为“意大利面条”,至少要成为经过测试的“意大利面条”。发布周期手动测试只是发布过程中涉及的手动过程的一部分。在受监管或以合规为重点的行业中,几乎总是有一堆手动合规性工作。合规性是我们非常关心的事情——因此我们应该将其自动化。所有这些手动流程和所有这些导致速度变慢的流程,这意味着即使我们是云,但我们实际上并没有获得上云的红利。我们使用云,但它不像云讽刺的是,在云端,我们曾经做过的事情,那些曾经是个好主意的东西,那些曾经让我们更有安全感的东西,实际上正在伤害我们。老式的治理在云端行不通,达不到我们想要的业务结果,而且因为上云而损失了很多业务利益。通过观察发布周期,很容易发现企业是否按计划迁移到云端。几年前,我的一位同事与一家大型传统银行进行了一次销售会议。他们的市场被金融科技公司和新兴的挑战者银行蚕食,企业明白他们失败的原因——他们跟不上的速度不够快。他们来找我们并解释说他们拥有大量COBOL资产,这就是阻碍他们前进的原因(可能确实如此)。然后他们补充说,他们显然需要摆脱所有COBOL并转向微服务,因为其他人都在做微服务。然后他们说他们的发布委员会每年只开两次会。提到这个Brilliant,我的同事们都觉得不自在。如果您的发布委员会每六个月开一次会,您就知道您的发布节奏是每六个月一次。无论您拥有多少可独立部署的微服务,在这种情况下都无法实现敏捷。这家银行需要的帮助并不是真正的技术帮助;他们需要改变他们思考风险的方式,以及他们对堆进行自动化的方式。缺乏持续交付纪律是阻碍他们获得敏捷的原因,而不是COBOL。“我要分解”是常见的客户需求,但分解的含义不止一个。当我们想要一个分解的应用程序时这并不能保证服务的模块化——有时它只是意味着混乱分散得更广泛。如果有一些外部限制,比如发布看板和过时的工作流程,让我们陷入困境,那么在我们解决这些问题之前,我们如何分解事情可能是徒劳的。关于作者HollyCummins是IBM企业战略组的创新领导者,多年来一直是IBMGarage的顾问。作为Garage的一员,她为各行各业的客户提供技术驱动的创新,从银行业到餐饮业,从零售业到非政府组织。Holly是OracleJava冠军、IBMQ大使和JavaOne摇滚明星。她与人合着了曼宁的《Enterprise OSGi in Action》。参考链接[1]微服务失败的7种方法:https://www.infoq.com/articles/microservices-seven-fail/[2]技术顾问:https://www.linkedin.com/in/holly-k-cummins[3]微服务的一些错误使用方式:https://plus.qconferences.com/plus2021/presentation/7-ways-fail-microservices[4]微服务:https://microservices.io/[5]简历驱动开发:http://radar.oreilly.com/2014/10/resume-driven-development.html[6]RedHat:https://www.redhat.com/[7]基于容器的主要驱动开发:https://www.redhat.com/en/blog/red-hat-survey-reveals-career-progression-driving-developer-hunger-containers-and-kubernetes[8]什么是“意大利面条架构”以及如何避免它:https://data-sleek.com/what-is-spaghetti-architecture-and-how-to-avoid-it/[9]解耦:https://en.wikipedia.org/wiki/Decoupling[10]火星气候轨道器:https://en.wikipedia.org/wiki/Mars_Climate_Orbiter[11]消费者驱动的合同测试:https://pactflow.io/what-is-consumer-driven-contract-testing/[12]OpenAPI:https://swagger.io/specification/[13]SpringCloudContract:https://spring.io/projects/spring-cloud-contract[14]Pact:https://pact.io/