下面需要说的是个人对于在构建微服务的过程中会面临的一些问题,或者说叫做挑战吧。
1、微服务的边界怎么定义。
上一篇文章已经提到过了,在定义微服务边界的过程中,DDD中的指导原则会帮助你大忙。 这可能是你在构建微服务过程中遇到的第一个难题,一个良好的微服务能够对其他微服务尽可能少的依赖,同一个应用程序中你需要用不同的上下文进行解耦,每个上下文有可能是使用不同的程序语言的。这些上下文应该被独立的定义和管理。比如一个User,在 Identity 上下文可能是一个用户,在 CRM 中是一个客户,在订单上下文是一个买家,等等。
2、如何跨微服务进行查询。
因为我们已经微服务化了,所以我们的应用程序数据可能分布在不同的数据库中,那么如何实现从多个为微服务器数据库中查询数据成为一个难题了。
比如,我们前台的数据展示页面需要一个销售统计的报表,其中的数据分别来源于订单,库存和商品。那么我们应该怎么样来处理这种复杂性呢? 目前流行的解决方案有以下几种:
API网关。 使用API网关来对多个微服务器的数据库进行聚合。 但是在实现这种模式的时候你需要非常的小心,它有可能是你系统中性能的瓶颈,甚至它有可能违背微服务的自治原则。为了尽可能避免这个陷阱,你需要设计多个细粒度的 API 网关,每个网关关注系统一个垂直领域的“切片”区域,或者是一个业务领域。现在大部分的云提供商都提供的有 API 网关相关服务,比如AWS的 Amazon API Gateway,Azure 的 Establish API Gateways 等,借助于这些服务可以方便的对 API 进行管理。
CQRS与读表。 不知道大家有没有听说话物化视图(Materialized View)这个名词。你可以理解为远程视图,使用这种方法,你可以提前准备好一个只读表,其中包括多个微服务的数据,这个只读表的结构和你展示给客户的页面数据是对应的。
那么有同学可能会存在这样一个问题,假如我基于不同的数据库建立一个物化视图,那么在我建立物化视图的过程中,我应该怎么样进行查询,因为对于单个数据库的查询可能仍然是复杂的。确实如此,在以前单个应用程序的时候,我们在呈现个客户端需要的数据的时候,可能会是一个复杂的SQL Join连接查询的结果。那么这里的解决方案就是,我们需要建立一个和我们业务无关的一个单独的数据库,然后这个数据库中会包含一些和界面上需要的数据进行一一对应的一些查询用的表,然后我们应用程序中引入 CRQS 这种模式,将需要的数据写入到这些查询表中。
这不仅解决了跨微服务查询这个难题,并且也提高了性能。但是引入CQRS也就意味着你需要拥抱最终一致性。
数据中心的 “冷数据”。 对于一些不需要做实时数据的复杂查询或者报表,通常是将微服务的“热数据”作为“冷数据”导出到数据中心以供报表。这个数据中心可能是一个基于大数据的系统,比如 Hadoop,AWS的Redshit,Azure的SQL Data warehosue等。
同步的过程你可以使用事件驱动这种通讯技术,或者是一些数据库提供的基础设施中的导入/导出工具等。如果使用事件驱动的话,其过程有点类似上面的CRQS查询过程。
3、如何实现多个微服务的数据一致性。
我们知道在每个微服务都是具有高内聚的特点的,外部想访问微服务的数据只能通过API访问,那么我们在实现一个微服务到另外一个微服务这种业务流程的时候,怎么同时保持多个微服务之间的一致性呢?
我们回到 eShop 这个微软的示例项目上来,来看看怎么处理的。 首先,Catelog 这个微服务是负责维护商品相关的信息,包括库存。 Ordering 这个微服务负责订单的管理,当新创建一个订单的时候,它必须验证这个订单的商品是否具有足够的库存(如果不够可能涉及到缺货登记),所以它就必须要和Catelog微服务打交道。在以前单服务的程序中可以简单的使用ACID事务来进行检查并且直接更新可用库存。但是现在不能这样了,每个微服务都拥有自己的数据库,当前的服务不能直接去操作其他服务的数据库的,这个时候我们为了实现我们需要的功能怎么办呢?我们可以使用异步通讯,比如消息或者事件驱动这种方式,这也是 eShop使用的方式。