提示:在这篇文章中,我会描述一种开发微服务的方法,这个方法可以解决这些问题。主要是通过领域模型设计,也就是DDD以及事件源(Event Sourcing)以及CQRS。

文章目录

  • 微服务中的大难题
  • 微服务开发过程中的挑战
  • 拆分领域模型
  • 跨服务分布式事务实现
  • 跨服务查询



微服务中的大难题

微服务架构变得越来越流行了。它是模块化的一种方法。它把一整块应用拆分成一个个服务。它让团队在开发大型复杂的应用时更快地交付出高质量的软件。团队成员们可以轻松地接受到新技术,因为他们可以使用最新且推荐的技术栈来实现各自的服务。微服务架构也通过让每个服务都被部署在最佳状态的硬件上而改善了应用的扩展性。

但微服务不是万能的。特别是在 领域模型事务以及查询这几个地方,似乎总是不能适应拆分。或者说相对于过去的单体架构,这几块也是微服务需要专门处理的地方。

让我们首先来看看开发人员在开发微服务的时候会遇到哪些问题吧。

微服务开发过程中的挑战

模块化在开发大型复杂的应用的时候是非常有必要的。
现在许多应用大到一个人根本无法完成。而且复杂到光靠一个人去理解是不可能的。

这种情况下,应用就必须被拆分成一个个模块。在单体应用中,模块被定义为比方一个java package。然而,这种做法在实践中并不是很理想,时间长了,单体应用就变得越来越庞大。微服务架构把服务作为一个模块单元。
每个服务对应一个业务能力,这个业务能力是组织为了创造价值而需要的。例如,基于微服务的在线商店包括各种服务,包括订购服务(Order Service),客户服务(Customer Service),目录服务(Catalog Service)。


API 
         

           OrderService 
         

           CustomerService 
         

           CatalogService


每个服务都有一个不可渗透且很难违反的边界。也就是每个微服务要提供一种单独而独立的能力。这样的话,应用程序的模块化就更容易随时间保存。
微服务架构还有其他优点。包括独立地部署服务,独立地扩展服务等等这些能力。相比单体来说。
不幸的是,拆分并没有听起来那么容易。相当难。
应用的领域模型,事务,查询这三个东西就是拆分过程中和拆分后你所面临的拆分难题。让我们来看看具体原因吧。

拆分领域模型

拆分领域模型——就是class们通常会引用一个或多个其他类 领域模型模式是实现复杂业务逻辑的一种非常好的方式。比如针对一个在线商店,领域模型将会包含这么几个类: Order, OrderLineItem, Customer 和 Product。

在微服务架构中,Order和OrderLineItem类是OrderService的一部分;Customer是Customer Service的一部分;Product属于CatalogService的一部分。

如何体现微服务设计 微服务领域模型设计_领域模型


拆分领域模型的挑战之一就是class们通常会引用一个或多个其他类。

比如,

现在有三个服务OrderService、Customer Service、CatalogService,Order类引用了该订单的客户Customer;OrderLineItem引用了该订单所订产品Product。

对于这些想要横跨服务边界的引用,我们该怎么办呢?

领域模型设计的概念:聚合(Aggregate)。我们通过聚合来解决这个问题。

微服务架构的一个非常明显的功能就是一个服务所拥有的数据只能通过这个服务的API来访问。
在一个电商网站中,比如,OrderService占有一个数据库,里边有一张表ORDERS;CustomerService也有自己的数据库包含表CUSTOMERS。
通过这样的封装,微服务之间就解耦了。
在开发期间,开发人员可以独立修改自己服务的数据库shema而不需要与其他服务的开发协调勾兑。
但是在生产上,服务之间都是隔离的。比如,一个服务从来不会因为另外一个服务占有了数据库的锁而导致阻塞等待。所以就导致这种数据库的拆分让管理数据的一致性以及不同服务间跨表查询变得困难。

跨服务分布式事务实现

在单体应用中,如果Orders和Customers都在同一个库中,那么就可以使用ACID事务来搞定:
ACID事务
原子性(Atomicity):是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
一致性(Consistency):针对一个事务操作前与操作后的状态一致
隔离性(Isolation):针对多个用户同时操作,主要是排除其他事务对本次事务的影响
持久性(Durability):表示事务结束后的数据不随着外界原因导致数据丢失

在微服务架构中我们无法通过这种方式管理数据的一致性。
ORDERS和CUSTOMERS表被不同的服务所拥有,只能通过各自的服务API访问。他们甚至可能在不同的数据库。
一种比较常见的做法就是使用分布式事务来搞定,比如2PC等。但是这种做法对于现代应用来说也许不是一种可行的方案。CAP定理要求你必须在可用性和一致性之间选择,可用性通常是较好的选择。
而且,许多现代技术,例如大多数NoSQL数据库,甚至不支持ACID事务,更不用说2PC。
所以管理数据的一致性需要使用其他的方式。

对于这些想要跨服务分布式事务实现,我们该怎么办呢?

我们使用事件驱动架构中的一种技术叫事件源(event sourcing)来解决分布式事务。

跨服务查询

SELECT *
FROM CUSTOMER c, ORDER o
WHERE
   c.id = o.ID
     AND o.ORDER_TOTAL > 100000
     AND o.STATE = 'SHIPPED'
     AND c.CREATION_DATE > ?

但我们无法在微服务架构中实现这样的查询。
就像前面提到的那样,ORDERS与CUSTOMERS表分属不同的服务,只能通过服务API来访问。而且他们可能使用了不同的数据库。

对于这些想要跨服务查询的情况,我们该怎么办呢?

CQRS(Command Query Responsibility Segregation)做法来解决分布式查询问题。