使用聚合、事件溯源和CQRS开发事务型微服务(第一部分)

  关键要点:

  微服务架构将应用功能分解为多个服务,其中每个服务都对应于一种业务能力。

  开发基于微服务的业务应用时,一个主要挑战是功能分解在事务、领域模型和查询中受到了抵制。

  领域模型可分解为多个领域驱动设计(Domain Driven Design,DDD)聚合。

  每个服务的业务逻辑都是一个领域模型,该领域模型由一个或更多的DDD聚合所组成。

  在服务中,每个事务只对单一的聚合进行创建或更新。

  事件用于维持聚合间(服务间)的一致性。

  微服务架构 正变得越来越流行。作为一种实现模块化的方法,微服务架构将应用功能分解为一组服务。团队可使用微服务架构去开发大型复杂的应用,这样可以更块地交付更好的软件。微服务架构还使得在开发中更易于采用新的技术,因为团队可使用最新最适合的技术栈去对每个服务进行实现。此外,通过使每个服务都可以部署在最优的硬件上,微服务架构可改进应用的可扩展性。

  但是微服务并非是一剂良方。尤其是在领域模型、事务和查询中,功能分解受到了出乎意料地抵制。由于这个问题的存在,使用微服务架构开发事务性业务应用是一件具有挑战性的事情。在本文中,我将给出了一种微服务开发的方法,该方法使用领域驱动设计、事件溯源和命令查询职责分离(Command Query Responsibility Segregation,CQRS)技术解决了上述的问题。让我们首先看一下开发人员在编写微服务中所面对的挑战。

  微服务开发中的挑战

  在大型复杂应用的开发中,模块化是至关重要的。大多数现代应用的规模决定了它不可能由单个开发人员单枪匹马地开发实现,这些应用的复杂度也不可能被单个开发人员所理解。这样应用必须要被分解为模块,而模块是可被已形成团队的开发人员理解并开发实现的。在整体应用程序中,可使用诸如Java包这样的编程语言结构定义模块。但这种方法常常在实践中并不好用。长生命周期的 整体应用程序 通常会退化为一个“大泥球”(译者注:指一个微服务中的问题将会扩展到整个应用中)。

  微服务架构使用服务作为模块化单元。每个服务对应于一种业务能力,即企业为创造价值所执行的操作。这里以一个基于微服务的网店为例。该网店由各种服务所组成,其中包括订单服务(Order Service)、客户服务(Customer Service)和商品目录服务(Catalog Service)。

物联网

  每个服务都具有难以违反的防渗透边界。正是由于该原因,应用的模块化的保持是经得起时间考验的。微服务架构的其它优点还包括可独立地部署和扩展服务的能力。

  遗憾的是,将应用分解为服务实现起来并非听上去那么容易。应用中有很多不同的方面是难以被分解的,这包括了领域模型、事务和查询。下面让我们看一下为什么会这样。

  问题一:分解领域模型

  领域模型模式 是一种实现复杂业务逻辑的好方法。网店的领域模型可包括Order(订单)类、OrderLineItem(订单条目)类、Customer(客户)类和Product(商品)类等。在微服务架构中,Order类和OrderLineItem类是订单服务的一部分,Customer类是客户服务的一部分,而Product类属于商品目录服务。

物联网

  然而,分解领域模型的挑战性在于各个类之间的相互引用。例如,Order类会引用其Customer类,OrderLineItem类引用Product类。该如何去处理这些跨越了服务边界的引用关系呢?在本文后面的内容中,读者将读到如何使用源于领域驱动设计的聚合概念去解决这个问题。

  微服务和数据库

  微服务的一个特有特性是,服务所拥有的数据只能通过该服务提供的API访问。回到网店的例子上,订单服务的数据库中有一个ORDERS表,客户服务的数据库中有一个CUSTOMERS表。这种封装表明服务是松耦合的。在开发时,订单服务和客户服务的开发人员无需与其它服务的开发者进行协调,就可以去改变这两个服务的服务模式。在运行时服务之间是相互独立。例如,一个服务将永远不会因为等待其它服务所拥有的数据库锁而被阻塞。遗憾的是,该数据库按功能的分解导致了数据一致性难于维持,还导致一些类型的查询难于实现。