【译】微服务设计模式(二)

571 阅读8分钟

原文链接

3.数据库模式

a.每服务一库

问题

如何定义微服务的数据库架构?需要解决以下问题:

  1. 服务必须松耦合,可以独立开发,部署,缩放。
  2. 业务事务会产生跨多个服务的不变量。
  3. 一些业务事务需要查询由多个服务拥有的数据。
  4. 为了缩放数据库有时必须进行复制和分片。
  5. 不同的服务有不同的数据存储需求。

解决方案

要解决这些问题,必须使用每服务一库,它对那个服务是私有的。仅能通过微服务的API访问,不能被其他服务直接访问。例如,对于关联的数据库,可以使用private-tables-per-service, schema-per-service或 database-server-per-service。每个微服务都应该有一个单独的数据库ID,这样才能为独立访问树立一道屏障防止使用其他服务的表。

b.每个服务共享数据库

问题

上面说了对于微服务而言每个服务一个数据库时最理想的,但那是对于尚未开发的应用,并将要使用DDD模式开发而言。对于一个现有的一体化应用,这并不简单。在这种情况下适合的架构是什么呢?

解决方案

每个服务共享数据库并不理想,但是对于上面的场景这是一个有用的解决方案。大部分人认为这是微服务的反模式,但是对于一个已有应用,这是将应用分成小的逻辑块的好的开端。这不应该应用于未开发的应用。在这个模式中,一个数据库对应于多个服务,但最多也只能有2-3个,否则,伸缩,自治与独立都难以实现。

c.命令查询职责分离(CQRS)

问题

一旦实现了每服务一库,就需要查询,需要从多个服务联合查询——那不可能。那么,在微服务中如何实现查询呢?

解决方案

CQRS建议将应用分为两个部分——命令部分与查询部分。命令部分处理增删改请求。请求部分使用实体化视图处理查询。通常与事件源模式一起使用。通过订阅事件流实体化视图保持更新。

d.Saga模式

问题

在每个服务拥有自己的数据库并有个跨多个服务的业务事务以后,如何确保数据的一致性?例如,对于一个电商应用,客户有信用额度,如何确保新订单不会超过信用额度。由于订单与客户是在不同的数据库中,应用不能简单地使用本地ACID事务。

解决方案

Saga代表高级业务过程,包括多个子请求,每一个都在一个服务中更新数据。每个请求在失败时都有一个补偿请求。可以以两种方式实现:

  1. Choreography——如果没有中心协调器,每个服务产生事件同时监听其他服务的事件来决定是否采取某种行动。
  2. Orchestration——协调器负责做出saga决定,及相应的业务逻辑。

4.可观测模式

a.日志聚合

问题

考虑这样一种情形,一个应用程序包含运行在多个机器上的多个服务实例。请求通常跨多个服务实例。每个服务实例以标准模式生成一个日志文件。对一个特定的请求,如何通过日志来了解应用程序的行为?

解决方案

我们需要一个中心化的日志服务,从每个服务实例中将日志聚合起来。用户可以搜索并分析日志。当某种信息出现在日志中的时候可以配置一个告警。例如,PCF有一个Loggeregator,从每个组件中收集日志(路由,控制器,diego等等)。AWS Cloud Watch也有同样的功能。

b.性能指标

问题

随着微服务集的扩大,监听事务并在问题发生时发出告警变得至关重要。我们如何手机指标来监控应用程序的性能呢?

解决方案

需要一个度量服务来收集个别操作的统计数据。需要聚合应用程序的指标,提供报表与告警。有两个方法来聚合指标:

  • Push——服务将指标推到指标服务,例如 NewRelic, AppDynamics。
  • Pull——指标服务从服务中获取指标,例如Prometheus。

c.分布式追踪

问题 在微服务架构中,请求常常跨越多个服务。每个服务通过执行多个跨服务的操作来处理请求。那么,如何追踪一个请求排查问题呢?

解决方案

需要一个服务,它能够:

  • 为每个外部请求分配一个唯一的外部请求ID。
  • 将外部请求ID传给所有服务。
  • 在日志信息中包含外部请求ID。
  • 在中心服务处理请求时,记录请求的信息(例如开始时间,结束时间)。

Spring Cloud Slueth以及Zipkin服务器,是常用的实现方案。

d.健康诊断

问题

微服务实现以后,服务可能已经上线但是不能处理事务,该如何确保请求不被转到这些失败的实例?使用一个负载均衡的实现。

解决方案

每个服务需要有一个终结点,可以用来检查应用的健康,例如/health。该API需要检查主机状态,到其他服务的连接,已经其他指定逻辑。

Spring Boot Actuator实现了一个/health端点,并且也可以自定义。

5.横切关注点模式

a.外部配置

问题

一个服务也会调用其他服务和数据库。对于每种环境例如开发,QA,UAT,生产环境,终结点URL或一些配置属性可能会有不同。任何配置的改变可能都需要重新生成和部署。如何避免配置改变时修改代码?

解决方案

外部化所有配置,包括终结点URL以及证书。应用程序应该在启动时或运行时加载它们。

Spring Cloud配置服务器提供了外部化属性到GitHub的功能,并能从那里加载环境属性。这些可以在应用启动时访问,不需要重启服务器也可以更新。

b.服务发现模式

问题

  1. 使用容器技术,IP地址是动态分配到服务实例的。地址一旦改变,就需要消费者断开并手动更改。
  2. 消费者需要记住服务URL,因而变得紧耦合。

解决方案

需要服务注册中心,这样就能记录生产者服务的元数据。当服务启动时需要注册到注册中心,在关闭时取消注册。消费者或路由应该查询注册中心并找到服务的位置。注册中心还要做生产者服务的健康诊断,确保仅工作的实例对消费者可用。有两种类型的服务发现:客户端和服务端。 Netflix Eureka就是客户端发现, AWS ALB是服务端发现。

c.熔断模式

问题

服务通常会调用其他服务取数据,有可能下游的服务崩了,这时会产生两个问题:首先,请求会继续下行,消耗网络资源,降低性能。其次,用户体验很差。如何优雅地处理级联错误呢?

解决方案

消费者需要通过代理调用服务,这个代理起到断路器的作用。当连续失败的次数超过阈值,断路器就会触发,在一个时间段里,所有调用服务的尝试都会立刻失败。一段时间以后,断路器允许一部分测试请求通过。如果这些请求成功了,断路器恢复正常。否则,重新计算超时时间。

d.蓝绿部署模式

问题

在微服务架构中,一个应用会有多个微服务。如果我们停止所有服务并部署一个新版本,停机时间会很长,会影响业务。当然,回滚也会是一个噩梦。在部署时如何减少停机时间呢?

解决方案 蓝绿部署策略可以减少停机时间。它实现的原理是运行两个完全一样的生成环境,蓝和绿。假设绿是已存在的系统,蓝是应用程序的新版本。在任何时候,仅有一个环境是在线的,在线的环境服务所有的生产业务。所有的云平台都提供蓝绿部署的功能。更多细节可以看这篇文章

微服务架构还有许多其他模式,像Sidecar, Chained Microservice, Branch Microservice, Event Sourcing Pattern, Continuous Delivery Patterns等等。随着微服务的发展,这个列表还会不断增长。我在这里抛砖引玉,希望能听听你在使用什么样的微服务模式。

【译】微服务设计模式(一)