微服务设计的原则:IDEALS,而不是SOLID( 四 )


微服务设计的原则:IDEALS,而不是SOLID

文章插图
 
六、松耦合在软件工程中,耦合是指两个软件元素之间相互依赖的程度 。对于基于服务的系统来说,传入耦合是指服务用户如何与服务交互 。我们知道这种交互应该通过服务契约来实现,并且该服务契约不应该与实现细节和特定技术紧密结合 。服务是可以由不同程序调用的分布式组件 。有时候,服务提供方不知道所有服务用户在哪里(公共API服务通常就是这样) 。因此,服务契约应该避免变更 。如何服务契约与服务逻辑或技术紧密耦合,那么当逻辑或技术需要演化时,它也需要同时发生变化 。
服务通常需要与其他服务或其他类型的组件交互,从而产生传出耦合 。这种交互建立了直接影响服务自治的运行时依赖关系 。如果一个服务的自治性较低,它的行为就不那么可预测:最好的情况就是,该服务将与他需要调用的最慢的,最不可靠的和最不可用的组件一样快速、可靠和可用 。
 
微服务的松耦合策略
IDEALS中的L表示要关注服务及微服务的耦合 。可以使用并组合多种策略来改进传入和传出的松散耦合 。这些策略包括:
  • 点对点和发布-订阅(Point-to-point and Publish-subscribe):这种通过消息传递的模式改进了耦合性,因为发送方和接收方彼此不知道对方 。响应式微服务(如Kafka消费方)的契约将成为消息队列的名称和消息的结构体 。
  • API网关和BFF:这些解决方案规定了一个中间组件,该组件处理服务契约与客户端需要的消息格式和协议之间的差异,从而有助于分离他们 。
  • 契约优先设计(Contract-first design):通过设计与任何现有代码相关的契约,从而避免创建与技术和实现紧密耦合的api 。
  • 超媒体(Hypermedia):对于REST服务,超媒体帮助前端更加独立于服务端点 。
  • Facade和Adapter/WrApper模式:这些GoF模式的变体在微服务架构中可以规定内部的组件和服务,可以防止在微服务实现中传播不良的耦合性 。
  • 每个微服务一个数据库模式:该模式使得微服务不仅获得了自治性,而且避免了与数据库共享带来的直接耦合 。
 
七、单一职责最初的单一职责原则( Single Responsibility Principle,SRP)是关于在OO类中具有内聚功能 。在一个类中拥有多个职责自然会导致紧耦合,并导致脆弱的设计,在变更时会发生意想不到的结果 。SRP这个想法很简单,也很容易理解,但要用好并不容易 。
单一职责的概念可以扩展到微服务中服务的内聚性 。微服务体系结构风格部署单元应该包含一个服务或几个内聚服务 。如果一个微服务包含太多的职责,也就是说,有太多不太具有内聚力的服务,那么它就可能会承受一个巨大的痛苦 。膨胀的微服务在功能和技术栈方面变得更难发展 。而且,持续交付将会变得繁重,因为他们将会使许多开发人员在同一个部署单元开发不同的内容 。
 
另一方面,如果微服务过于细粒度,则其中的几个服务可能需要交互来满足用户请求 。在最坏的情况下,数据变更可能会跨多个微服务,可能会产生分布式事务的场景 。
 
粒度适中的微服务
微服务设计成熟度的一个重要方面是创建粒度适中的微服务的能力 。这里的解决方案不是任何工具或技术中,而是在适当的领域建模上 。为后端服务建模并为其定义微服务边界可以通过多种方式完成 。业界流行的一种驱动微服务范围的方法是遵循领域驱动设计(Domain-Driven Design,DDD)原则 。简而言之:
 
一个服务(例如:REST服务)可以具体DDD聚合的作用域 。一个微服务的作用域可以是DDD限定的上下文 。该微服务中的服务将对应于该限定上下文的聚合 。
对于微服务间的通信,我们可以使用:当异步消息满足需求时使用领域事件(Domain Event);当请求-响应更适合时,使用某种形式的中间层进行API调用;当一个微服务需要另一个可用区的大量数据时,可以使用数据复制保证最终一致性 。
 
八、结论IDEALS是在大多数典型的微服务设计中要遵循的核心设计原则 。然而,遵循IDEALS并不是使我们的微服务设计成功的良药 。通常,我们还需要对质量需求有一个很好的理解,并使设计决策意识到他们的权衡 。此外,我们还应该学习可以用来帮助实现设计原则的设计模式和架构策略 。还应该掌握可用的技术选型 。
 
多年来,我一直使用IDEALS设计、实现和部署微服务,在设计研讨会和讲座中,我与来自不同组织的数百名软件开发人员讨论这些核心原则以及每一个原则背后的许多策略 。有时候,会让人觉得微服务的工具、框架、平台和模式层出不穷,我相信,对微服务IDEALS更好的理解,能够帮助我们更清晰的了解技术领域 。


推荐阅读