2017年,微软 AzureCAT 模式和实践团队在 Azure 架构中心发布了 9 个新的微服务设计模式,并给出了这些模式解决的问题、方案、使用场景、实现考量等。微软团队称这 9 个模式有助于更好的设计和实现微服务,同时看到业界对微服务的兴趣日渐增长,所以也特意将这些模式记录并发布。
下图是微软团队建议如何在微服务架构中使用这些模式:
微软:微服务设计模式
文中提到的9 个模式包括:外交官模式(Ambassador),防腐层(Anti-corruption layer),后端服务前端(Backends for Frontends),舱壁模式(Bulkhead),网关聚合(Gateway Aggregation),网关卸载(Gateway Offloading),网关路由(Gateway Routing),挎斗模式(Sidecar)和绞杀者模式(Strangler)。这些模式绝大多数也是目前业界比较常用的模式,如:
设计模式是对针对某一问题域的解决方案,它的出现也代表了工程化的可能。随着微服务在业界的广泛实践,相信这个领域将会走向成熟和稳定,笔者期望会有更多的模式和实践出现,帮助促进这一技术的进一步发展。
本文,主要介绍防腐层(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(域驱动的设计)中描述。
大多数应用程序依赖于其他系统的某些数据或功能。 例如,旧版应用程序迁移到新式系统时,可能仍需要现有的旧的资源。 新功能必须能够调用旧系统。 逐步迁移尤其如此,随着时间推移,较大型应用程序的不同功能迁移到新式系统中。
这些旧系统通常会出现质量问题,如复杂的数据架构或过时的 API。 旧系统使用的功能和技术可能与新式系统中的功能和技术有很大差异。 若要与旧系统进行互操作,新应用程序可能需要支持过时的基础结构、协议、数据模型、API、或其他不会引入新式应用程序的功能。
保持新旧系统之间的访问可以强制新系统至少支持某些旧系统的 API 或其他语义。 这些旧的功能出现质量问题时,支持它们“损坏”可能会是完全设计的新式应用程序。
不仅仅是旧系统,不受开发团队控制的任何外部系统(第三方系统)都可能出现类似的问题。
在不同的子系统之间放置防损层以将其隔离。 此层转换两个系统之间的通信,在一个系统保持不变的情况下,使另一个系统可以避免破坏其设计和技术方法。
在不同的子系统之间放置防损层以将其隔离
上图显示了采用两个子系统的应用程序。
子系统 A 通过防损层调用子系统 B。 子系统 A 与防损层之间的通信始终使用子系统 A 的数据模型和体系结构。防损层向子系统 B 发出的调用符合该子系统的数据模型或方法。 防损层包含在两个系统之间转换所必需的所有逻辑。
该层可作为应用程序内的组件或作为独立服务实现。
在以下情况下使用此模式:
如果新旧系统之间没有重要的语义差异,则此模式可能不适合。
在 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());
}
}
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