领域驱动设计下的服务高可用设计
我们知道领域驱动设计已经逐步应用落地,系统架构设计在后微服务时代,更快速的向DDD演进,微服务架构的设计面向系统维度的拆分,实现快速的独立部署,解决DevOps的效能问题,进入后微服务时代,领域模型的理解逐步深入,简单的设计微服务架构会使得系统过于松散,尤其在服务的高可用设计上,领域驱动设计的边界如何考量和把控,成为我们后微服务架构设计必须考虑的要素。
今天的话题是讨论领域驱动设计下的服务高可用设计,首先举个例子,A调用B,B的服务高可用如何设计?
方案一,A与B实现1:1的服务保障能力,RPC调用的SLA保障;
方案二,A与B通过共享资源,降低RPC损耗,基于共享资源实现SLA保障;
方案三,B提供二方包,封装RPC调用和存储资源,提供A本地调用的SLA保障。
如何进行三种方案的技术选型?
方案一,优点是架构简单,功能松耦合,领域定义清晰;缺点是1:1流量的服务保障,B服务的容器资源、调用性能、稳定性等衍生的稳定性风险,会有较大的高可用设计成本,尤其是若B提供的是一些配置数据,这个架构设计的性价比较低。
方案二,优点是架构不复杂,功能清晰,领域定义明确,解决了静态数据1:1流量调度的弊端;缺点是A服务依赖了B服务的存储资源,在一定程度上形成了耦合,这体现在变更后的整体发布。这个架构设计降低了高可用设计的成本,但是随着时间推移A和B会演进成大泥潭。
方案三,优点是功能清晰,领域定义明确,解决了A依赖B的耦合问题;缺点是架构复杂,B提供的Jar包变更仍需要A发布,存在一定的耦合。若A提供SPI的服务能力,成本会降低,但是A的高可用设计成本会加大。这个架构设计在选型时需慎重。
微服务的九个核心特征:围绕业务能力构建,分散治理,通过服务来实现独立自治的组件,产品化思维,数据去中心化,强终端弱管道,容错性设计,演进式设计,基础设施自动化。
其中,通过服务来实现独立自治的组件,微服务之所以强调通过服务Service而不是类库Library来构建组建,是因为类库在编译期静态连接到程序里,通过本地调用来提供功能,而服务时通过进程外调度,通过远程调度来提供服务。尽管远程服务有更高昂的调用成本,但这是为组件带来自治与隔离能力的必要代价。—— 摘自《凤凰架构》
那么,基于微服务的设计理论基础,以及通过实践得出效果来看,绝大多数的业务架构都应该基于通过服务Service的模式进行设计,那么这就涉及到高可用的设计归属域的边界问题?就我个人而言,A服务已经完成领域的建模,那么高可用的设计则归属A服务,并与B确认服务的SLA。
其中,数据去中心化,微服务明确提倡数据应该按领域分散管理、更新、维护、存储,那么通过共享资源的架构设计,这是否违背了微服务的设计原则?共享资源使得领域都必须修改和映射到同一个实体之中,这很可能使不同服务之间相互影响而丧失独立性。除此之外,共享资源带来的潜在隐患,B若是Ops系统,其发生问题可能影响到核心链路上的系统,比如A。
那么,回到最开始的话题,A调用B,B的高可用设计就有了设计的变化。
如何进行三个方案的调整?
方案二,共享缓存的架构设计,会造成A与B之间相互影响,进而调成独立缓存的架构设计。A与B共享缓存的设计,常见在系统已拆分,但组织架构未拆分的情况,这隐藏的约束是共享缓存专门服务于该业务,而非为领域服务。
方案三,B提供二方包嵌入A,会造成A与B之间的相互影响,进而调整对B服务进行架构拆分的设计。这其实是领域设计已经逐步演进成需要对B服务进行垂直拆分的诉求,这也是B Jar出现的原罪,由此更应对B进行领域内的系统拆分。
综述,今天讨论的内容就结束了,主要讨论了在分布式架构设计中服务间调用的高可用设计,以上不同的方案都有过实践,虽说代码写在哪里都可以,但领域驱动设计的愿景就是降低软件架构的设计复杂度,否则,终将是行走的恐龙巨兽。