微服务设计模式:反腐层(Anti-corruption layer)

本文涉及的产品
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 微服务设计模式:反腐层(Anti-corruption layer)

微软:微服务设计模式

2017年,微软 AzureCAT 模式和实践团队在 Azure 架构中心发布了 9 个新的微服务设计模式,并给出了这些模式解决的问题、方案、使用场景、实现考量等。微软团队称这 9 个模式有助于更好的设计和实现微服务,同时看到业界对微服务的兴趣日渐增长,所以也特意将这些模式记录并发布。

下图是微软团队建议如何在微服务架构中使用这些模式:

微软:微服务设计模式

 

文中提到的9 个模式包括:外交官模式(Ambassador),反腐层(Anti-corruption layer),后端服务前端(Backends for Frontends),舱壁模式(Bulkhead),网关聚合(Gateway Aggregation),网关卸载(Gateway Offloading),网关路由(Gateway Routing),边车模式(Sidecar)和绞杀者模式(Strangler)。这些模式绝大多数也是目前业界比较常用的模式,如:

  • 外交官模式(Ambassador)可以用与语言无关的方式处理常见的客户端连接任务,如监视,日志记录,路由和安全性(如 TLS)。
  • 反腐层(Anti-corruption layer)介于新应用和遗留应用之间,用于确保新应用的设计不受遗留应用的限制。
  • 后端服务前端(Backends for Frontends)为不同类型的客户端(如桌面和移动设备)创建单独的后端服务。这样,单个后端服务就不需要处理各种客户端类型的冲突请求。这种模式可以通过分离客户端特定的关注来帮助保持每个微服务的简单性。
  • 舱壁模式(Bulkhead)隔离了每个工作负载或服务的关键资源,如连接池、内存和 CPU。使用舱壁避免了单个工作负载(或服务)消耗掉所有资源,从而导致其他服务出现故障的场景。这种模式主要是通过防止由一个服务引起的级联故障来增加系统的弹性。
  • 网关聚合(Gateway Aggregation)将对多个单独微服务的请求聚合成单个请求,从而减少消费者和服务之间过多的请求。
  • 边车模式(Sidecar)将应用程序的辅助组件部署为单独的容器或进程以提供隔离和封装。

设计模式是对针对某一问题域的解决方案,它的出现也代表了工程化的可能。随着微服务在业界的广泛实践,相信这个领域将会走向成熟和稳定,笔者期望会有更多的模式和实践出现,帮助促进这一技术的进一步发展。

本文,主要介绍反腐层(Anti-corruption layer)模式


反腐层(Anti-corruption layer)

在微服务(Microservices)架构实践中,人们大量地借用了DDD中的概念和技术,比如一个微服务应该对应DDD中的一个限界上下文(Bounded Context);在微服务设计中应该首先识别出DDD中的聚合根(Aggregate Root);还有在微服务之间集成时采用DDD中的反腐层(Anti-Corruption Layer, ACL)。

反腐层(Anti-corruption layer,简称 ACL)介于新应用和旧应用之间,用于确保新应用的设计不受老应用的限制。是一种在不同应用间转换的机制。

创建一个反腐层,以根据客户端自己的域模型为客户提供功能。该层通过其现有接口与另一个系统进行通信,几乎不需要对其进行任何修改。因此,反腐层隔离不仅是为了保护你的系统免受异常代码的侵害,还在于分离不同的域并确保它们在将来保持分离。

反腐层是将一个域映射到另一个域,这样使用第二个域的服务就不必被第一个域的概念“破坏”。

不共享相同语义的不同子系统之间实施外观或适配器层。 此层转换一个子系统向另一个子系统发出的请求。 使用反腐层(Anti-corruption layer)模式可确保应用程序的设计不受限于对外部子系统的依赖。 反腐层(Anti-corruption layer)模式最先由Eric Evans 在 Domain-Driven Design(域驱动的设计)中描述。


反腐层(Anti-corruption layer)提出背景

大多数应用程序依赖于其他系统的某些数据或功能。 例如,旧版应用程序迁移到新式系统时,可能仍需要现有的旧的资源。 新功能必须能够调用旧系统。 逐步迁移尤其如此,随着时间推移,较大型应用程序的不同功能迁移到新式系统中。

这些旧系统通常会出现质量问题,如复杂的数据架构或过时的 API。 旧系统使用的功能和技术可能与新式系统中的功能和技术有很大差异。 若要与旧系统进行互操作,新应用程序可能需要支持过时的基础结构、协议、数据模型、API、或其他不会引入新式应用程序的功能。

保持新旧系统之间的访问可以强制新系统至少支持某些旧系统的 API 或其他语义。 这些旧的功能出现质量问题时,支持它们“损坏”可能会是完全设计的新式应用程序。

不仅仅是旧系统,不受开发团队控制的任何外部系统(第三方系统)都可能出现类似的问题。


解决方案

在不同的子系统之间放置防损层以将其隔离。 此层转换两个系统之间的通信,在一个系统保持不变的情况下,使另一个系统可以避免破坏其设计和技术方法。

在不同的子系统之间放置防损层以将其隔离

 

上图显示了采用两个子系统的应用程序。

子系统 A 通过防损层调用子系统 B。 子系统 A 与防损层之间的通信始终使用子系统 A 的数据模型和体系结构。防损层向子系统 B 发出的调用符合该子系统的数据模型或方法。 防损层包含在两个系统之间转换所必需的所有逻辑。

该层可作为应用程序内的组件或作为独立服务实现。


Anti-corruption layer注意事项

  • 防损层可能将延迟添加到两个系统之间的调用。
  • 防损层将添加一项必须管理和维护的其他服务。
  • 请考虑防损层的缩放方式。
  • 请考虑是否需要多个防损层。 可能需要使用不同的技术或语言将功能分解为多个服务,或者可能因其他原因对防损层进行分区。
  • 请考虑如何管理与其他应用程序或服务相关的防损层。 如何将其集成到监视、发布和配置进程中?
  • 确保维护并可以监视事务和数据一致性
  • 请考虑防损层是要处理不同子系统之间的所有通信,还是只需处理部分功能。
  • 如果防损层是应用程序迁移策略的一部分,请考虑该层是永久性的,还是在迁移所有旧功能后即会停用。
  • 经常和绞杀者模式(strangler)一起使用


Anti-corruption layer使用场景

在以下情况下使用此模式:

  • 迁移计划为发生在多个阶段,但是新旧系统之间的集成需要维护
  • 很多人一看到旧系统就想要赶快替换掉他,但是请不要急著想著去替换旧系统,因为这条路充满困难与失败,而且 旧系统通常反而是系统目前最赚钱的部分。更好的做法是在使用旧系统时包上一层 ACL,让你的开发不受影响,甚至可以一点一滴的替换旧系统的功能,达到即使不影响目前功能下也能开发新功能,达到重构的效果!
  • 两个或更多个子系统具有不同的语义,需要对外部上下文的访问进行一次转义
  • 例如:对接第三方系統。缴费软件中的收银台系统,需要对接不同的支付方式(支付宝、各个银行、信用卡等),这是就需要收银台系统充当一个Anti-corruption layer,将用户的缴费支付信息,转换成各个三方支付系统需要的数据格式。
  • 如果内部多个组件对外部系统需要访问,那么可以考虑将其放到通用上下文中。
  • 例如:我们有一个抽奖平台,包含有现金券、折扣券、外卖券、出行券等组件,但他们都需要对接用户信息服务,这时就需要在抽奖平台中,搭建一个Anti-corruption layer,作为抽奖平台对接用户信息的通用适配层。

如果新旧系统之间没有重要的语义差异,则此模式可能不适合。


Anti-corruption layer 示例1:JDK集合

在 JDK1.0 时我们用的集合还是 Vector(后来推荐使用 ArrayList),我们用的迭代器还是 Enumeration(后来推荐使用 Iterator)。现在我们需要一个适配器,搭建Anti-corruption layer (EnumerationAdapter ),让 Vector 也能使用 Iterator 迭代器,即在 Enumeration 和 Iterator 之间做适配。

/**
 * 1、Iterator 是新版本的迭代器。
 * 2、Enumeration 是旧版本的迭代器。
 * 3、EnumerationAdapter 是适配者(Adapter)角色,相当于Anti-corruption layer 在 Enumeration 和 Iterator 之间做适配
 */
public class EnumerationAdapter implements Iterator {
    private Enumeration enumeration;
    public EnumerationAdapter(Enumeration enumeration) {
        this.enumeration = enumeration;
    }
    @Override
    public boolean hasNext() {
        return enumeration.hasMoreElements();
    }
    @Override
    public Object next() {
        return enumeration.nextElement();
    }
    @Override
    public void remove() {
        throw new UnsupportedOperationException("remove");
    }
}
// main方法
public static void main(String[] args) {
  Vector vector = new Vector();
  vector.add("java");
  vector.add("python");
  vector.add("javaScript");
  Enumeration enumeration = vector.elements();
  Iterator iterator = new EnumerationAdapter(enumeration);
  while (iterator.hasNext()) {
    System.out.println(iterator.next());
  }
}

 

Anti-corruption layer 示例2--企业员工管理系统新旧版本对接

  • 在企业员工管理系统中,我们经常需要通过ID查询雇员信息(EmployeeAccessService.findEmployee)
  • 但,我们在企业员工管理系统版本迭代中,可能存在老员工的信息在旧版本企业员工管理系统,新员工的信息在新版本企业员工管理系统。
  • 当我们查询老员工的信息,就需要委托给EmployeeAccessAdapter适配器,从旧版本企业员工管理系统(EmployeeAccessFacade)中获取一个员工信息。
  • 并通过EmployeeAccessTranslator,以将旧版本员工信息转换为应用程序模型中的域对象。

 

EmployeeAccessService(查询雇员信息

public Employee findEmployee(String empID){
    return adapter.findEmployee(empID);
}

EmployeeAccessAdapter (Anti-corruption layer,对接旧版本企业员工管理系统

// 旧版本 员工信息
private EmployeeAccessFacade facade;
public Employee findEmployee(String empID){
    EmployeeAccessContainer container = facade.findEmployeeAccess(empID);
    return translator.translate(container);
}

EmployeeAccessTranslator(将旧版本员工信息转换为应用程序模型中的域对象

public Employee translate(EmployeeAccessContainer container){
    Employee emp = null;
    if (container != null) {
        employee = new Employee();
        employee.setEmpID(idPrefix + container.getEmployeeDTO().getEmpID());
        ...(more complex mappings)

 


参考链接:

https://docs.microsoft.com/en-us/azure/architecture/

https://stackoverflow.com/questions/909264/ddd-anti-corruption-layer-how-to

https://docs.microsoft.com/zh-cn/azure/architecture/patterns/strangler

https://ithelp.ithome.com.tw/articles/10218591

https://tech.meituan.com/2017/12/22/ddd-in-practice.html


相关文章
|
设计模式 Java API
【设计模式】JAVA Design Patterns——Aggregator Microservices(聚合器微服务模式)
【设计模式】JAVA Design Patterns——Aggregator Microservices(聚合器微服务模式)
|
11月前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
设计模式 前端开发 Java
10个微服务设计模式
微服务设计模式是一种指导微服务架构设计和开发的一系列原则和实践。微服务设计模式的目的是为了解决微服务架构中遇到的一些常见的问题和挑战,比如服务划分、服务通信、服务治理、服务测试等。微服务设计模式可以帮助我们构建出高效、可靠、可扩展、可维护的微服务系统。
596 2
|
设计模式 存储 运维
微服务架构中的服务发现与注册中心设计模式
在现代软件工程实践中,微服务架构已成为构建灵活、可扩展系统的首选方案。本文将深入探讨微服务架构中至关重要的服务发现与注册中心设计模式。我们将从服务发现的基本原理出发,逐步解析注册中心的工作机制,并以Eureka和Consul为例,对比分析不同实现的优劣。文章旨在为开发者提供一套清晰的指导原则,帮助他们在构建和维护微服务系统时做出更明智的技术选择。
|
设计模式 监控 Java
探索微服务架构的弹性设计模式
【7月更文挑战第19天】在现代后端开发中,微服务架构因其灵活性、可扩展性而受到企业的青睐。本文将深入探讨微服务架构中的弹性设计模式,包括其定义、重要性以及如何通过技术手段实现服务的高可用性和容错性。我们将通过实例分析,展示如何在微服务系统中应用这些模式以提高系统的整体稳定性和响应能力。
145 1
|
设计模式 负载均衡 安全
探索微服务架构下的API网关设计模式
【6月更文挑战第14天】本文将深入探讨在微服务架构中,API网关的设计模式及其对系统性能和安全性的影响。通过分析不同的设计模式,我们将了解如何在保障服务高可用性和可扩展性的同时,确保系统的灵活性和响应速度。
|
设计模式 Java 关系型数据库
BAT等大厂年薪30W+面试清单:JVM\MySQL\设计模式\分布式\微服务
疫情影响下招聘名额缩减不少,但阿里、腾讯、抖音、快手等互联网公司却加快了人才招聘的节奏。这里根据自身的实际经历,整理了一份面试这些大厂的清单,希望能帮助到大家查漏补缺,攻克面试难关。
|
设计模式 存储 API
微服务架构及设计模式
逛github时看到了一篇很好的文章,转载过来分享给大家,版权归原作者所有,侵删,原文地址为:https://colstuwjx.github.io/2020/01/%E7%BF%BB%E8%AF%91-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E5%8F%8A%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/
java初中级面试题(SSM+Mysql+微服务(SpringCloud+Dubbo)+消息队列(RocketMQ)+缓存(Redis+MongoDB)+设计模式+搜索引擎(ES)+JVM
java初中级面试题(SSM+Mysql+微服务(SpringCloud+Dubbo)+消息队列(RocketMQ)+缓存(Redis+MongoDB)+设计模式+搜索引擎(ES)+JVM
635 0
java初中级面试题(SSM+Mysql+微服务(SpringCloud+Dubbo)+消息队列(RocketMQ)+缓存(Redis+MongoDB)+设计模式+搜索引擎(ES)+JVM
java初中级面试题(SSM+Mysql+微服务(SpringCloud+Dubbo)+消息队列(RocketMQ)+缓存(Redis+MongoDB)+设计模式+搜索引擎(ES)+JVM
781 0