微服务架构的核心要点和实现原理
微服务去中心化治理
上图中, 外部服务和内部服务属于 API 网关, 所有的服务由统一的 API 网关进行管理.
比如外部应用要调用服务1, 就会经过 API 网关(外部服务), 内部应用也是一样的. 如果服务N要调用服务2, 则也需要通过 API 网关进行调用.
这样看起来很规范, 但是每个用户请求时只要有服务之间的交互, 则都会从 API 网关进行路由, 业务量增大后, 在很大程度上增加了 API 网关的调用 TPS, API 网关很快就遇到了性能瓶颈.
微服务倡导去中心化的治理, 不推荐每个服务都使用相同的标准和技术来开发和使用服务. 也就是说你可以使用 C++ 开发一个服务, 来对接 Java 开发的另一个服务.
对于异构系统之间的交互标准, 可以使用 Thrift 远程调用框架使用中间语言 (IDL) 来定义接口, 中间语言是独立于任何语言的, 并提供了工具来生成中间语言, 以及在中间语言与具体语言之间的代码转换.
最后谈下微服务架构是否就一定是去中心化的, 如果一个微服务架构没有使用微服务网关那它一定是去中心化的, 如果使用了微服务网关就需要进行判断.
微服务网关是否只提供了类似Dubbo服务注册和发现能力, 实际访问仍然是点对点的服务调用, 如果是这种模式也可以理解为整个微服务架构是去中心化的. 如果一个微服务网关提供了完全的对被调用系统的安全隔离, 包括提供了对每次消息调用的日志追溯能力, 那么微服务网关就是一个不可绕过的中心节点, 整个微服务架构也不再是去中心化的架构.
微服务的交互模式
读者容错模式
读者容错模式指微服务化中服务提供者和消费者之间如何对接口的改变进行容错. 也就是说, 消费者获取到提供者返回的数据时, 无论这个数据如何变化, 我们只需要从中获取到我们想要的数据, 可以忽略新的消息项、可选的消息项等不需要的数据.
只有当消费者不能完全识别接收到的消息, 或者无法通过识别的信息继续处理流程时, 才抛出异常.
去数据共享模式
在微服务领域, 微服务之间的交互通过定义良好的接口来实现, 不允许使用共享数据来实现.
在实践的过程中, 有些方案的设计使用缓存或者数据库作为两个服务之间的纽带, 在业务流程的处理过程中, 为了处理简单, 前一个服务将中间结果存入数据库或缓存, 下一个服务从缓存或数据库中拿到数据继续处理. 如下图:
这种交互流程的缺点如下:
- 使得微服务之间的交互除了接口契约, 还存在数据库存储契约.
- 上游的数据库格式发生变化时, 可能导致下游的处理逻辑出现问题.
- 多个服务共享一个资源服务, 对资源服务的运维难以划清职责和界限.
- 在做双机独立部署时, 需要考虑服务和资源的路由情况, 跨机房的服务调用不能使用独立的资源部署模式, 因此难以实现服务自治.
因此, 在设计微服务架构时, 一定不要共享缓存和数据库等资源, 也不要使用总线模式, 服务之间的通信和交互只能依赖定义良好的接口, 通过使用 RESTful 样式的 API 或透明的 RPC 调用框架.
消费者驱动契约模式
消费者驱动契约模式用来定义服务之间交互接口改变的规则. 分为: 提供者契约、消费者契约、消费者驱动的契约.
- 提供者契约: 提供者提供了什么功能和消息格式, 各消费者不论实际需要多少功能都要无条件地遵守这些约定.
- 消费者契约: 是对某个消费者的需求进行更为精确的描述, 在一次具体的服务业交互场景下, 代表消费者需要提供者提供功能中的哪些部分数据. 消费者契约可以被用来标识现有的提供者契约, 也可以用来发现一个尚未明确的提供者契约.
- 消费者驱动的契约: 代表服务提供者向其所有当前消费者承诺遵守的约束. 一旦各消费者把自己的具体期望告诉提供者, 则提供者无论在什么时间和场景下, 都不能打破契约.
在实现的服务交互设计中, 上面这三种契约是同时存在的, 笔者(这本书的作者)所在的支付平台里, 交易系统在完成一笔支付后, 需要到账务系统为商户入账, 这个过程中, 服务契约表现如下.
- 生产者契约: 账务系统提供 Dubbo 服务化接口, 参数为商户账号ID、入账订单号和入账金额.
- 消费者契约: 账务系统返回 DTO, 包含账户账户ID、入账订单号、入账金额、入账时间、账务流水号、入账状态等, 而交易系统只需要使用其中的入账订单号和入账状态.
- 消费者驱动的契约: 为了保证资金安全, 交易系统作为入账的发起者向账务提出要求, 需要账务做幂等和滤重处理, 对重复的入账请求进行拦截; 账务系统在接受这个契约后, 即将来有任何改变, 也不能打破这个限制, 否则就造成资金流失, 这在金融系统中是最严重的问题.
服务提供者契约是服务提供者单方面定下的规则, 而一个消费者契约会成为提供者契约的一部分, 多个服务消费者可以对服务提供者提出约束, 服务提供者需要在将来遵守服务消费者提出的契约, 这就是消费者驱动的契约.
上面的资料是我抄书加自己写的, 如果难以理解可以看看 文章1 和 文章2
总结
- 当调用任意一个服务时, 都需要经过同一个服务(API 网关, 也就是说每个服务都不能绕过这个节点), 这就是中心化; 微服务提倡去中心化治理, 因为当业务量增加后可能会导致 API 网关出现性能瓶颈.
- 不推荐每个服务都使用相同的标准和技术来开发和使用服务. 可以使用 C++ 开发一个服务来调用 Java 服务.
- 微服务推荐使用 RESTful 样式的 API 或透明的 RPC 调用框架, 进行交互, 不推荐使用数据共享模式.
- 读者容错模式就是在消费者或提供者接口改变时进行容错, 比如提供者返回数据中新增项后, 消费者指获取需要的数据.
- 提供者契约: 服务提供者提供了哪些约定, 比如提供了什么功能和消息格式.
- 消费者契约: 是对某个消费者的需求进行更为精确的描述, 在一次具体的服务业交互场景下, 代表消费者需要提供者提供功能中的哪些部分数据.
- 消费者驱动契约: 例如服务端调整架构或接口调整而对消费者不透明, 导致接口调用失败, 而CDC则是以消费者提出接口契约, 交由服务提供方实现, 并以测试用例对契约进行产生约束, 所以服务提供方在满足测试用例的情况下可以自行更改接口或架构实现而不影响消费者.