微服务架构实践原则

文摘   科技   2024-07-13 08:42   上海  

好的微服务架构可以帮助团队加快产品发布,为用户提供更好的服务体验。但什么才是好的微服务架构?这篇文章简单介绍了微服务架构的设计原则。原文:Medium Microservice Architecture Practice[1]

许多初创公司的技术栈会从单体Node.js应用开始,然后构建几个卫星通信服务,但并没有系统采用微服务架构。随着系统变得越来越复杂,团队必须构建一个更好的解决方案来最小化对系统的影响。微服务体系架构的目标就是帮助工程师团队更快、更安全、更高质量的交付产品。

在微服务体系架构中,多个松散耦合的服务一起工作,每个服务专注于一个目标,并与相关行为和数据保持高度内聚。其定义包括3条设计原则:

  1. 单一职责——每项服务都应该专注于一个目的并把它做好

  2. 松耦合服务——服务之间没有太多的联系,对一个服务的变更不应该要求更改其他服务,服务之间的通信只能通过公开的服务接口进行。

  3. 高内聚性——每个服务都将所有相关的行为和数据封装在一起,如果需要构建新功能,所有的更改都应该局限于一个服务中。


这些原则是充分利用微服务体系架构潜力的唯一途径,任意两者的缺乏都将使之成为一种反模式。如果没有一个单一的职责,每个微服务最终都会做很多事情,并成长为多个“单体”服务,因此我们没法从微服务架构中获得好处,但却需要支付运营成本。如果没有松耦合,对一个服务的更改会影响到其他服务,因此我们没法快速安全的发布变更,而这正是微服务体系架构的核心优势。更重要的是,由紧耦合引起的问题可能是灾难性的,比如数据不一致甚至数据丢失。如果没有高内聚性,我们将最终得到一个分布式的单体系统,一组混乱的服务,必须在构建单一功能的同时进行更改和部署。由于多服务协调(有时跨多个团队)的复杂性和成本,分布式单体系统通常比集中式单体系统还要差劲。

此外,微服务不是代码行更少或处理小任务的服务,只要满足了这3个原则,服务就可以实现复杂而重要的功能。事实上,由于我们可以直接从单体服务中提取逻辑,因此微服务并不总是采用新技术或者从头开始构建的。


Node.js单体应用在很多方面已经成为瓶颈。首先,最大的瓶颈是性能。某些计算量大、I/O量大的任务不适合Node.js。我们一直在逐步改进这个整体应用程序,但事实证明这种努力收效甚微。其次,另一个紧迫的瓶颈是单体应用程序减缓了产品开发。所有工程师都在一个应用程序中构建功能,所以这些服务通常是紧密耦合的,因为对系统某一部分的更改也会影响到其他部分,因此很难对系统进行灵活的变更。因为影响难以预测,我们也害怕做出重大变更。整个应用程序作为一个整体部署,如果部署由于不正确的提交而停滞,则无法完成其他所有变更。在这种情况下,微服务体系架构适合于交付更好的复杂系统。在我们新的微服务体系架构中,更改可以一小时内发布到生产环境,工程师不必担心会影响系统的其他部分。第三,单体应用程序很难为特定任务扩展系统。单体应用程序只能扩展整个系统,这将导致其他简单任务的过度配置。我们分割了不同类型的请求来分离Node.js进程,但因为这些单体服务的迷你版本仍然是紧耦合的,因此伸缩性仍然受限。最后,最紧迫的瓶颈是它阻止我们尝试新技术。微服务体系架构的主要优点之一是,每个服务都可以使用不同的技术栈构建,并与不同的技术集成。这样,我们就可以为特定的工作找到合适的工具,并安全快速地完成任务。


在采用微服务体系架构时,我们会面临什么问题?

微服务也有可能出问题,并在实际上损害生产环境。有7种策略可以帮助我们:

  1. 用清晰的思路构建新的服务

  2. 单一的持久化存储是有害的

  3. 解耦“构建服务”和“运行服务”

  4. 详细一致的可观测性

  5. 注意失败

  6. 从一开始就避免“微服务综合症”

用清晰的思路构建新的服务
  • 有人可能认为,采用新的服务端架构意味着需要长期暂停产品开发并且重写所有内容。但实际上这是一种误解,我们永远不应该为了构建新的服务而构建。每当我们建立一项新服务或采用一项新技术时,我们必须有一个清晰的产品理念或工程价值。产品价值是造福用户,与单体Node.js应用相比,新服务需要提供更多的价值或更好的性能。工程价值指的是使工程团队更好、更快的合作。如果构建一个既没有产品价值也没有工程价值的新服务,我们还不如仍然停留在单体应用中。

单一的持久化存储是有害的
  • 为微服务建模只是微服务架构的一部分工作,另一大部分工作是为持久化存储的数据建模。跨服务共享持久数据存储似乎是集成微服务的最简单方法,然而,它实际上是有害的,我们应该不惜一切代价避免。首先,持久化数据存储与实现细节有关,跨服务共享数据存储将向整个系统公开服务的实现细节。如果服务更改了数据格式,或添加了缓存层,或切换到不同类型的数据库,那么其他服务也必须相应的更改,而这违反了松耦合原则。

  • 另外,如何修改、描述和使用数据并不是一种服务行为。如果我们跨服务共享数据存储,意味着其他服务也必须复制这些服务行为,而这违反了高内聚原则,会将给定域中的行为泄露给多个服务。如果我们修改一个行为,将不得不同时修改所有这些服务。

  • 在微服务体系架构中,只有一个服务应该负责特定类型的数据,所有其他服务都应该通过服务API请求数据,或者保留只读的非规范(可能是具化的)数据副本。

  • 这听起来可能有点抽象,这里有一个具体的例子。假设我们正在构建一个新的推荐服务,需要来自发布数据表中的一些数据,该数据表目前存储在AWS Dynamo DB中。我们可以通过以下两种方式为新的推荐服务提供发布数据:


参考文献

Microservices Best Pratices: https://medium.com/@kmdkhadeer/microservices-best-practices-5fe3e28394b3

References:
[1] Medium Microservice Architecture Practice: https://jinlow.medium.com/medium-microservice-architecture-practice-5a2d61fff9fa

你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。
微信公众号:DeepNoMind

DeepNoMind
你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。