微服务下的系统设计(更新中)
记录一下微服务架构下的一些设计方案
微服务下同步调用结果的不确定性——超时
基于网络波动的超时在所难免,我们不能因为超时便认为下游处理失败。
这里假设A服务调用B服务,最需要注意的场景是:
- B服务收到请求处理成功,在响应时超时,或者被A服务超时中断,A系统此时无法确认B是否受理和处理成功
使用“过程(pending)”
因为A服务在超时时无法确认B的状态,所以我们需要补偿逻辑,使用“查询”,B系统提供查询接口,用于A查询刚刚的请求是否成功
- A –> B: 请求(创建资源),此时B响应超时
- A将其标记为“进行中(pending)”
- A –> B: 定时查询请求处理状态(查询pending资源是否已创建)
- 返回不存在或成功、处理中、失败等状态,A将状态标记为“最终状态”,进行后续流程
为了支持后续的查询,A在第一次请求时,入参需要传递一个唯一请求号,B的查询接口入参为该唯一请求号
幂等设计
在微服务环境下,请求出现重复非常正常,所以服务支持幂等非常重要。
在RPC请求里增加“唯一请求号”让我们在实现幂等上更加简单。
微服务下的数据查询
客户端所需展示的数据,往往分散在各个微服务的存储内,我们无法使用简单的一次join就取出所有字段
API组合模式
最常见和首选的方案是API组合模式,比如先查询主要条目,然后根据条目内关联的id,批量查询其他关联数据
这种模式实现较为简单,也会出现一些问题
- 降低可用性。同步的API调用增加了服务间的依赖、增加了服务耦合,除非我们可以缺少字段或提供默认字段的响应给到客户端
- 状态不一致。即使时同步调用,不同服务间存储的某些公有属性可能不一致,需要API组合方决定如何处理
CQRS
还有一种方案是CQRS,数据的读取和写入使用不同的Schema,甚至是不同的服务,基于事件驱动进行读视图的数据更新,保持最终一致性
这种方式缺点也比较明显:增加复杂性和开发成本、排查问题比较困难、同步延迟等