微服务架构到底是什么?
你是红衣战士,空手道全明星,也是变形金刚战士的领袖。你坐在巨型佐德的头部;巨型佐德是由其他战士的佐德组成的,是一个能击退外星人、挥舞长剑的机器人。在巨型佐德里,你是无敌的——丽塔·雷普尔萨派来的任何怪物都无法与你强大的力量相抗衡。你盯着今天的“本周怪物”:一个全身布满眼球、手臂是触手的巨大外星人。你的脸上露出一丝羞涩的笑容;只要挥动你那摩天大楼般大小的长剑,这场仗就该结束了。“好了,战士们,”你大喊,“快来干掉他!”
没有比这更好的了。
“呃,可能有问题?”粉红战士金伯利紧张地说道。
“那是什么?”
“比利患有单核细胞增多症,所以他没法来。”
你低头凝视,意识到巨型佐德的左腿不见了。几乎就在这时,巨型佐德开始失控地摇晃起来。一声巨响,你重重地摔在地上。世界仿佛慢动作般移动,你被抛向驾驶舱的墙壁。你慢慢从恍惚中回过神来,抬头看到怪物正快速逼近。
“接我们!”你对控制着超级佐德手臂的黑衣战士扎克大喊。
“又是坏消息,”他回答道,“但QA仍在对我们上周在我的Zord中发现的bug进行回归测试。它今天还不能发布。”
可能这就是你现在的感受。
先不说超级佐德(Megazord)本身显然比其各个组件更强大(因为如果一个超酷的巨型机器人最终分裂成几个客观上不那么酷的小型机器人,那场面就没那么壮观了),我想尝试向大家介绍一下微服务的概念,以及为什么它们在过去几年里成为了一种流行的架构模式。这并非一个完美的比喻——我只是想借此机会引用一下《恐龙战队》。
如果你在过去几年里看过软件开发人员的招聘信息,很有可能看到过“熟悉微服务架构”这句话。你可能不太清楚它到底是什么,但你几乎可以立刻推断出一些信息:它涉及小型服务,是一种架构模式。你可能会想:“好吧,我在简历上写了 Ruby on Rails,而我所做的只是编写一个 Hello World 应用程序——我肯定能凭借在网上读到的一篇文章就掌握一些微服务的知识。” 我不会做出任何承诺,但希望读完我的文章后,你能直视面试官的脸说:“是的,我熟悉微服务架构!” 然后发出一声嘶哑的嚎叫,撕掉面试上衣的袖子,然后一甩,把面试台的桌子掀翻。
如果您阅读过我关于声明式编程的文章,您可能已经看到我提到过声明式编程有一个对立面。微服务也有一个对立面,称为单体架构。这只是描述作为单个逻辑单元构建的系统的一种方式。简单来说,这只是意味着包含功能不同的层(例如:服务器端应用程序,表示层,数据库层等)的单个代码库。从历史上看,这就是企业构建应用程序的方式。但是,将所有应用程序代码放在一个地方也存在一些缺点。随着代码库在永无止境的运营流失周期中增长,维护它的能力也会随之增长。您将开始承担技术债务。新功能变得更难实现。错误更难找到。开发人员将开始反抗高层管理人员。沙皇将在暴力抗议中被推翻。
太快了?
微服务架构模式的诞生源于企业应用程序规模扩大后,降低维护难度的需求。多年来,各种模式应运而生,例如领域驱动设计,有助于管理功能与应用程序不同区域耦合过度时可能产生的副作用。然而,随着时间的推移,这种架构的持续维护变得越来越困难,这时微服务应运而生。微服务致力于将通用功能从代码库中剥离出来,并将其抽象成独立的服务。由于该服务独立运行,它现在可以专注于特定的业务边界。
我将尝试将微服务分解为其各个特征(有点像将应用程序分解为微服务 - 这是您的第一个例子,哈哈)。
它们很小
“好吧,显而易见!”你对着正在阅读这篇文章的屏幕大声说道。是的,我知道这可能从名字就可以看出来,但可能不太明显的是它们应该有多小。不幸的是,答案并不那么简单:视情况而定。如果你把一个服务拆分成太多的微服务会怎么样?如果最终一个臃肿的微服务处理了太多功能会怎么样?
这里有一个很好的经验法则:确定服务的业务边界,然后从那里开始。举个例子,假设你有一个应用程序,用户可以在其中创建个人资料和撰写文章(这听起来很熟悉)。你创建了一个处理照片上传的功能。这张照片需要转换并上传到 AWS S3 存储桶,然后需要将元数据保存到数据库中。这有一个非常明确的业务边界(照片上传管理),这似乎很适合剥离出来,成为一个微服务。
你可能在网上听到过“两个披萨”规则(由亚马逊推广),这意味着微服务应该足够小,以便开发它的团队可以吃两个披萨就能吃饱。大学时我曾经一口气吃掉了一整块特大披萨,所以我对这个指标不太有信心。而且我认为没有确切的公式,虽然这个公式可能对大型企业有效,但微服务的价值远不止于此。这应该由最适合你个人和/或组织需求的因素来决定。
这不是我吃的那个披萨,只是一种戏剧效果。
单一职责原则
你可能对这个术语很熟悉(SOLID中的“S” )。如果你不熟悉,让我解释一下。它的意思是将出于相同原因而变化的事物分组。既然我已经给出了一个非常模糊的答案,让我们更深入地探讨一下。
SRP 坚持认为一个类应该只因一个原因而改变。如果有两个原因可能导致其改变,则应将其拆分为两个类。这听起来可能有点夸大其词,但随着应用程序复杂度的增加,保持代码的弹性至关重要。当一个类有多个原因需要改变时,很难预测其副作用。一个改变可能会无意中影响到同一个类中其他职责的实现方式。所有功能都会变得紧密耦合;如果某个功能需要更改,可能会破坏该类中的其他功能。
微服务借鉴了同样的原则,即每个服务应该只管理一项职责。每个服务都有自己的任务,但可以与其他服务通信,以解决更大、更复杂的业务问题。毕竟,团队合作才能让梦想成真。
如果您的微服务看起来像这样,那么您做错了。
沟通
在微服务架构中,每个服务都应封装各自的领域知识,并且每个服务的实现细节对其他服务隐藏(这又一次回顾了我关于声明式编程的文章)。这意味着在与我们的照片上传微服务通信时,客户端无需了解其实际处理图像的方式。它只需关心如何将要处理的图像交付给微服务即可。对于微服务而言,精心设计定义明确的 API 至关重要。妥善处理版本控制也至关重要,以免破坏依赖它的服务。花时间妥善设计微服务的 API 将为您省去日后繁琐的麻烦。
它们可以独立部署
单体系统的痛点之一是变更周期紧密相连;对应用程序的一个小部分的变更就需要重建和部署整个应用程序。微服务应该能够独立部署,而无需在其他任何地方进行更改。如果对微服务的更改需要更改主应用程序,则很可能是微服务的功能与代码库耦合过紧。
去中心化
这是什么?区块链?(笑声响起)。去中心化治理是微服务的重要组成部分。如果服务与其他业务流程耦合过于紧密,就会失去微服务架构的一些主要优势。如果你的服务是去中心化的,你就不会被任何特定的技术栈、库或框架所束缚。你可以通过 Golang 运行照片上传功能,但通过 Node API 来处理账户管理。
不仅应用程序的概念模型可以去中心化,数据存储也一样。微服务负责持久化自身的数据和状态。单体系统会使用数据层来管理整个应用程序的数据持久化,而微服务则更加灵活。您可以让服务运行同一数据库的不同实例,或者,如果您觉得更大胆一些,也可以运行一个完全不同的数据库系统。
为什么选择微服务?
可扩展性
对于单体应用,您可以通过在负载均衡器后运行多个应用实例来实现水平扩展。然而,这需要扩展整个应用,而不仅仅是需要额外资源的部分。理论上讲,如果您网站上 90% 的流量都流经某个函数,那么您需要扩展整个应用来管理该端点。由于微服务是独立部署的,因此它们也可以独立扩展以满足需求。真是太棒了。
弹性
微服务的优势之一是,即使发生故障,也不会让整个应用程序彻底沉入海底。但需要注意的是,必须部署适当的故障保护措施——因为服务是自治的,客户端在向微服务发送请求时无法获知其健康状况/状态。因此,务必结合监控和其他故障保护措施(例如重试请求、短路以避免瓶颈等)来应对这些情况。
更快的开发
拥有自主服务意味着可以更轻松地添加功能和管理错误修复。更改可以独立于主应用程序进行。如果更新出现问题,您可以安全地回滚到以前的版本。您可以实施更改,而不必担心它是否会对应用程序的其他地方造成副作用;这意味着测试时间更少,需要解决的整体问题也更少。
设计微服务
设计微服务没有完美的公式。它需要仔细考量应用程序的业务领域和目标。定义各个服务的边界将是最大的挑战,但确保遵循单一职责原则将有助于判断您的服务是否承担了过多的任务。围绕业务边界设计的微服务应该是“垂直的”,也就是说,不应该围绕应用程序的水平层进行设计。您不会将整个数据层都迁移到微服务,因为不同的数据会根据应用程序中的不同领域进行上下文关联。微软整理了一份便捷的微服务设计模式列表,您可以点击此处阅读。
并非没有缺点
等一下,我们需要谈谈。
微服务架构听起来很酷,但并不总是能满足组织的需求。微服务架构就像跷跷板效应;尽管它带来了诸多好处,但管理架构的复杂性也随之增加。你可能会说:“但是 Keith,微服务架构的诞生不就是为了管理单体系统中应用程序的复杂性吗?” 别担心,我明白其中的讽刺之处——但你实际上是在用一个问题换另一个问题。
在单体系统中,添加新功能或更新现有功能变得非常困难,因为职责或功能可能广泛分布于整个应用程序中。一项服务的变更可能会对应用程序的其余部分产生连锁反应。这会导致集成过程非常漫长,因为所有团队都需要了解正在实施的变更。微服务通过确保每个服务管理单一职责(因此,不同的团队可以管理不同的微服务)来解决这个问题。这听起来很棒,但现在您需要尝试管理一个庞大的自治服务网络。
你有没有遇到过这种情况:需要把一堆东西搬到另一个房间,但又不想跑一趟?于是你小心翼翼地把东西夹在胳膊之间;你的左手小指勾住了某个东西的把手,而这个东西比你平时用小指搬动的要重得多。你开始慢慢挪动双脚,小心翼翼地平衡着那些东西,因为它们不可避免地会从你的手中滑落。这基本上就是管理微服务架构的原理。
还有其他需要考虑的因素。由于每个微服务都负责自身的数据持久化,因此很难维护跨多个服务的数据完整性。服务过于繁琐可能会导致请求在服务之间来回跳转,从而增加延迟。此外,由于去中心化,代码缺乏治理。如果没有制定规范或标准,这些服务的独立性可能会使维护变得困难(尤其是在使用不同语言编写的情况下)。管理这种高度分布式的架构需要一套不同的技能,因此这可能会成为组织的另一个障碍。
重要的是了解您的组织需求,并权衡成本和收益。如果您认为微服务架构适合您,那就尽情发挥吧!关于设计微服务架构,还有很多值得探讨的地方,如果您想继续研究,也有很多优秀的资源可供参考。
因此,下次面试官询问您是否熟悉微服务架构时,只需回想一下这篇文章并说:“我认为这与 Power Rangers 有关?”
感谢您的阅读,我希望能够教您一些东西!
祝好,
Keith Brewster(推特)