作者:气质未央若 | 来源:互联网 | 2024-09-28 19:06
12.1微服务的原则
我们在第2章讨论过,微服务原则可以发挥什么样的作用。它们主要描述了该如何做,以 及为什么应该这样做的问题。这些原则可以帮助我们在构建系统时做出各种决定。你绝对 应该定义自己的原则,但微服务的一些关键原则,如图12-1总结的,我认为值得在这里洋 述。这些原则将帮助我们,创建出一系列可以很好地进行协同工作的自治的小服务。到目 前为止,微服务的所有内容我们在本书中已经至少提过一次了,所以本章没有新的内容, 但是精炼出它们的核心精华也是有价值的。 二 : ;
你可以选择全部采用这些原则,或者定制采用一些在自己的组织中有意义的部分。但请注 意,组合使用这些原则的价值:整体使用的价值要大于部分使用之和。所以,如果决定要 舍弃其中一个原则,请确保你明白其带来的损失。
对于每个原则,我已经在本书中尝试列出了一些支持它们的实践。俗话说的好:条条道路 通罗马。你可能会使用自己的方式来实现这些原则,但下面列出的实践能够给你带来一个 好的开始。
图12-1:微服务的原则
12.1.1围绕业务概念建模
经验表明,围绕业务的限界上下文定义的接口,比围绕技术概念定义的接口更加稳定。针 对系统如何工作这个领域进行建模,不仅可以帮助我们形成更稳定的接口,也能确保我们 能够更好地反映业务流程的变化。使用限界上下文来定义可能的领域边界。
12.1.2接受自动化文化
微服务引入了很多复杂性,其中的关键部分是,我们不得不管理大量的服务。解决这个问 题的一个关键方法是,拥抱自动化文化。前期花费一定的成本,构建支持微服务的工具是 很有意义的。自动化测试必不可少,因为相比单块系统,确保我们大量的服务能正常工作 是一个更复杂的过程。调用一个统一的命令行,以相同的方式把系统部署到各个环境是一 个很有用的实践,这也是采用持续交付对每次提交后的产品质量进行快速反馈的一个关键 部分。
请考虑使用环境定义来帮助你明确不同环境间的差异,但同时保持使用统一的方式进行部 署的能力。考虑创建自定义镜像来加快部署,并且创建全自动化不可变服务器,这会更容 易定位系统本身的问题。
12.1.3隐藏内部实现细节
为了使一个服务独立于其他服务,最大化独自演化的能力,隐藏实现细节至关眞要。限界 上下文建模在这方面可以提供帮助,因为它可以帮助我们关注哪些模型应该共享,哪些应 该隐藏。服务还应该隐藏它们的数据库,以避免陷入数据库耦合,这在传统的面向服务的 架构中也是最常见的一种锅合类型。使用数据泵(data pump)或事件数据泵(event data pump),将跨多个服务的数据整合到一起,以实现报表的功能。
在可能的情况下,尽量选择与技术无关的API,这能让你自由地选择使用不同的技术栈。 请考虑使用REST,它将内部和外部的实现细节分离方式规范化,即使是使用RPC,你仍 然可以采用这些想法。
12.1.个让一切都去中心化
为了最大化微服务能带来的自治性,我们需要持续寻找机会,给拥有服务的团队委派决策 和控制权。在这个过程初期,只要有可能,就尝试使用资源自助服务,允许人们按需部署 软件,使开发和测试尽可能简单,并且避免让独立的团队来做这些事。
在这个旅程中,确保团队保持对服务的所有权是重要的一步,理想情况下,甚至可以让团 队自己决定什么时候让那些更改上线。使用内部开源模式,确保人们可以更改其他团队拥 有的服务,不过请注意,实现这种模式需要很多的工作量。让团队与组织保持一致,从而 使康威定律起作用,并帮助正在构建面向业务服务的团队,让他们成为其构建的业务领域 的专家。一些全局的引导是必要的,尝试使用共同治理模型,使团队的每个成员共同对系 统技术愿景的演化负责。
像企业服务总线或服务编配系统这样的方案,会导致业务逻辑的中心化和哑服务,应该避 免使用它们。使用协同来代替编排或哑中间件,使用智能端点(smart endpoint)确保相关 的逻辑和数据,在服务限界内能保持服务的内聚性。
12.1.5可独立部署
我们应当始终努力确保微服务可以独立部署。甚至当需要做不兼容更改时,我们也应该同 时提供新旧两个版本,允许消费者慢慢迁移到新版本。这能够帮助我们加快新功能的发布 速度。拥有这些微服务的团队,也能够越来越具有自治性,因为他们不需要在部署过程中 不断地做编配。当使用基于RPC的集成时,避免使用像javaRMI提供的那种使用生成的 桩代码,紧密绑定客户端/服务器的技术。
通过采用单服务单主机模式,可以减少部署一个服务引发的副作用,比如影响另一个完全 不相干的服务。请考虑使用蓝/绿部署或金丝雀部署技术,区分部署和发布,降低发布出 错的风险。使用消费者驱动的契约测试,在破坏性的更改发生前捕获它们。
请记住,你可以更改单个服务,然后把它部署到生产环境,无需联动地部署其他任何服 务,这应该是常态,而不是例外。你的消费者应该自己决定何时更新,你需要适应他们。
12.1.6隔离失败
微服务架构能比单块架构更具弹性,前提是我们了解系统的故障模式,并做出相应的计 划。如果我们不考虑调用下游可能会失败的事实,系统会遭受灾难性的级联故障,系统也会比以前更加脆弱。
当使用网络调用时,不要像使用本地调用那样处理远程调用,因为这样会隐藏不同的故障 模式。所以确保使用的客户端库,没有对远程调用进行过度的抽象。
如果我们心中持有反脆弱的信条,预期在任何地方都会发生故障,这说明我们正走在正确 的路上。请确保正确设置你的超时,了解何时及如何使用舱壁和断路器,来限制故障组件 的连带影响。如果系统只有一部分行为不正常,要了解其对用户的影响。知道网络分区可 能意味着什么,以及在特定情况下牺牲可用性或一致性是否是正确的决定。
12.1.7高度可观察
我们不能依靠观察单一服务实例,或一台服务器的行为,来看系统是否运行正常。相反, 我们需要从整体上看待正在发生的事情。通过注入合成事务到你的系统,模拟真实用户的 行为,从而使用语义监控来査看系统是否运行正常。聚合你的日志和数据,这样当你遇到 问题时,就可以深入分析原因。而当需要重现令人讨厌的问题,或仅仅查看你的系统在生 产环境是如何交互时,关联标识可以帮助你跟踪系统间的调用。
12.2什么时候你不应该使用微服务
这个问题我被问过很多次了。我的第一条建议是,你越不了解一个领域,为服务找到合适 的限界上下文就越难。正如我们前面所讨论的,服务的界限划分错误,可能会导致不得不 频繁地更改服务间的协作,而这种更改成本很高。所以,如果你不了解一个单块系统领域 的话,在划分服务之前,第一件事情是花一些时间了解系统是做什么的,然后尝试识别出 清晰的模块边界。
从头开发也很具有挑战性。不仅仅因为其领域可能是新的,还因为对已有东西进行分类, 要比对不存在的东西进行分类要容易得多!因此,请再次考虑首先构建单块系统,当稳定 以后再进行拆分。
当微服务规模化以后,你面临的许多挑战会变得更加严峻。如果你主要采用手工的方式做 事情,当只有一两个服务时还可以应对,如果是5到10个服务呢?坚持老式的监控实践, 查看诸如CPU和内存指标的这种方式,在只有几个服务时还好,但服务间的协作越多, 你就会越痛苦。随着增加更多的服务,你会发现自己在不断触及这些痛点。我希望这本书 的建议,可以帮你预见其中的一些问题,并且了解一些如何解决这些问题的具体技巧。我 之前说过,REA和Gilt在有能力大规模使用微服务之前,花费了一定时间来构逢工具和实 践,帮助管理微服务。这些经历让我更加相信逐步开始的重要性,它可以帮助你了解组织 改变的意愿和能力,这将有助于正确地采用微服务。
12.3临别赠言
微服务架构会给你带来更多的选择,也需要你做更多的决策。相比简单的单块系统,在微 服务的世界里,做决策是一个更为常见的活动。我可以保证,你总会在一些决策上出错。 既然知道了我们难免要做一些错事,那该怎么办呢?嗯,我会建议你,尽量缩小每个决策 的影响范围。这样一来,如果做错了,只会影响系统的一小部分。学会拥抱演进式架构的 概念,在这种概念下,系统会在你学到一些新东西之后扩展和变化。不要去想大爆炸式的 重写,取而代之的是随着时间的推移,逐步对系统进行一系列更改,这样做可以保持系统 的灵活性。
希望到目前为止,我给你分享了足够多的知识和经验,能帮助你决定微服务是否适合你。 如果微服务适合你,我希望你把它看作一个旅程,而不是终点。逐步前行。一块块地拆分 你的系统,逐步学习。习惯这一点:从很多方面来说,持续地改变和演进系统,这条规则 比我在本书中分享给你的任何一个知识都要重要。变化是无法避免的,所以,拥抱它吧!