java架构师指南:微服务架构消费者驱动契约模式

读者容错模式(TolerantReader)是指如何在微服务中服务提供者和使用者之间的接口更改。从字面上讲,消费者需要设计与提供者提供的功能的兼容性,特别是服务提供者返回的内容,或者在服务提供者更改接口或数据格式时如何消费服务。
  java架构师指南:微服务架构消费者驱动契约模式

设计任何产品时,都无法预见将来可能会增加的所有需求。服务的开发人员通常会通过迭代及时添加新功能,或者让服务提供的API自然地发展。但是,由服务提供商提供的接口数据格式的更改,添加和删除将导致服务使用者无法正常工作。
  因此,在处理服务提供者返回的消息的过程中,服务使用者需要过滤服务返回的消息,仅提取他们需要的内容,并采取丢弃冗余或未知内容的策略,而不仅仅是丢弃它们。处理错误。
  在实施过程中,不建议使用严格的验证策略,而建议使用宽松的验证策略。即使服务使用者收到的消息发生更改,该程序也只需尽其所能提取所需的数据。忽略无法识别的数据。仅当服务使用者完全无法识别接收到的消息或无法继续通过识别的信息进行处理时,才可以引发异常。
  服务的消费者的容错模式忽略了新的消息项、可选的消息项、未知的数据值及服务消费者不需要的数据项。
  笔者当前在某个支付公司工作,公司里几乎每个业务都需要使用枚举类型,在微服务平台下,笔者在研发流程规范中定义了一条枚举值使用规范:
  在服务接口的定义中,参数可以使用枚举值,在返回值的DTO中禁止使用枚举值。
  这条规范就是读者容错模式在实践中的一个 消费者驱动的合同模型用于定义最佳规则,以更改服务中服务之间的交互界面。
  服务契约分为:提供者合同,消费者合同和消费者驱动的合同,它们从期望和约束的角度描述了服务提供者和服务消费者之间的联系关系。
  提供者契约:这是我们最常用的服务合同之一。顾名思义,提供者契约是以提供者为中心的。不管提供者提供的功能和消息格式如何,消费者都将无条件遵守这些协议。实际需要多少功能,并且当消费者接受提供者合同时,他们将根据服务提供者的规则来使用该服务。
  消费者合同:这是对特定消费者需求的更精确描述。在特定的服务交互方案中,它表示消费者需要提供商从功能中获取数据的哪一部分。消费者契约可以用于标识现有的提供者合同,也可以用于发现不清楚的提供者合同。
  消费者驱动的契约:一种约束,代表服务提供商对其所有当前消费者的承诺。一旦每个消费者将其特定期望告知提供商,提供商无论在什么时间或情况下都不应违反契约。
  在实际的服务交互设计中,上述三种契约同时存在。在作者所在的付款平台中,交易系统完成付款后,需要转到会计系统以输入商家帐户。在此过程中,服务契约的履行如下。
  生产者契约:账务系统提供Dubbo服务化接口,参数为商户账户ID、入账订单号和入账金额。
  消费者契约:账务系统返回DTO,包含商户账户ID、入账订单号、入账金额、入账时间、账务流水号、入账状态等,而交易系统只需使用其中的入账订单号和入账状态。
  消费者驱动的契约:为了确保资金的安全性,交易系统作为输入的发起者向会计提出请求,这需要幂等和过滤处理来拦截重复的输入请求;账务系统正在接受此契约后,即使将来有任何更改,也不能打破此限制,否则会导致资金损失,这是财务系统中最严重的问题。
  服务之间的交互需要使用的三种服务契约如图所示。
  java架构师指南:微服务架构消费者驱动契约模式

从上图中可以看到,服务提供者契约是服务提供者单方面定下的规则,而一个消费者契约会成为提供者契约的一部分,多个服务消费者可以对服务提供者提出约束,服务提供者需要在将来遵守服务消费者提出的契约,这就是消费者驱动的契约。实例,之所以在参数中允许使用枚举值,是因为如果服务的提供者升级了接口,增加了枚举值,若服务的消费者并没有感知,则服务的消费者得知新的枚举值就可以传递新的枚举值了;但是如果接口的返回DTO中使用了枚举值,并且因为某种原因增加了枚举值,则服务消费者在反序列化枚举时就会报错,因此在返回值中我们应该使用字符串等互相认可的类型,来做到双方的互相兼容,并实现读者容错模式。
  推荐阅读:java架构师指南之架构师的工作流程