目录
微服务划分目标
业务、技术、团队导向规划服务
领域检查
依赖DAG检查
分布式事务检查
性能分布检查
稳定(易变)性检查
调用链检查
微服务划分目标
我们常说服务的合理划分是微服务成功的重中之重,一个合理的服务划分应该符合一下几点:
- 符合团队结构 服务的落地与维护靠人,靠的是执行团队(包含业务、产品、技术、测试与运维团队),所以服务的设定一定是与团队结构相辅相成的,同一个系统不同的执行团队往往会有不同的且都合理的服务划分方案
- 业务边界清晰 各服务有清晰的责任及边界,一个服务对应一块业务,服务间多为单向依赖
- 最小化地变更 新增或变更业务上有很明确的服务对应,或是新增服务或是扩展某些服务,很少出现既可以在这个服务上实现也可以在那个服务上实现这种摸棱两可的情况,在符合上述条件前提下某一业务需求地变更受影响的服务应该尽可能地少
- 最大化地复用 服务的复用是服务化的一个重大优势,服务设定要考虑复用的场景,在符合上述条件的前提下应该尽可能最大化地实现服务复用
- 性能稳定简洁 上述条件更多的是业务导向,从技术上服务设定的核心要关注对性能的影响、是否稳定及架构是否简洁,是否要引入额外的中间件等
业务、技术、团队导向规划服务
我们必须明确的是,服务不是越细越好,服务划分的第一要素是先以业务域拆分,再以技术视角拆分,结合团队的规模、能力确定服务间的关系与边界。服务划分完毕要做进行以下几方面的检查确保服务划分的合理性。
1、领域检查
领域检查可以为我们的服务划分提供方向性的指导,使服务划分更明确、各有规划性。
领域通用语言检查:确保在一个领域内产研描述的同一个对象就是同一个对象,比如质量验收中的巡检,北京的“鲁班行动”由于历史原因既是鲁班巡检也是验后巡检,都是同一类人在做(品质监察),西部的从验收模版就进行了区分鲁班巡检和验后巡检吗,这就是典型的同一个领域内语言描述不统一,导致的问题也很多既有线上数据记录错误也有BI侧的同学统计出错,反复确认该问题。
界限上下文检查:从业务特征上对领域进行划分形成子域,检查界限上下文是否划分合理。代码层面是否按照界限上下文进行继承关系、实体、聚合、值对象、领域服务等设计。比如我们的很多老的不同的服务都是共用一个DB这个现象不管是在微服务设计还是领域驱动设计范式里都是不提倡的。
领域防腐层检查:防腐层隔离不仅是为了保护自身领域模型免受其他领域模型的代码的侵害,还在于分离不同的域并确保它们在将来保持分离。咱们目前很多项目没有防腐层概念设计,导致大部分同学在开发的时候就是堆砌代码而不在意领域范围内结构的完整性,最终导致代码风格迥异,从系统上边界混淆。
领域对象、领域上下文不明确导致,定则生成业务(其实是统一业务)拆分在不同的领域服务里,带来的影响也有很多不便:
- 定则业务从技术层面没有收口出了问题排查就要拉多方逐一确认,只有很熟悉代码的同学才知道原来“主材补退货”的定则是否生成是供应链服务控制的!!!但是产品同学肯定不知道。
- 后期技术同学维护交接容易遗漏,后期迭代开发容易遗漏影响面。
- 产品迭代需要不同的团队支持,其实是同一个业务,这也是不太合理的情况。
2、依赖DAG检查
DAG在数学上是有向无环图,指从任何一点出发都不会回到这个点,即不存在环路,我们服务的依赖也应如此。服务间要尽量避免双向或循环依赖,否则可能会导致灾难性的后果。质量领域中的业主线下验收就存在一个有向环图,下图中第一个就是业主发起线下申请人出现的有向有环图问题,究其原因就是系统边界划分不清晰导致质量领域事件出现在了验收单领域里,增加了系统间交互的复杂性和系统边界模糊,调用链路复杂等情况发生。经过领域界限上下文重新规划和代码优化之后的教系统交付如下图二,可以看到边界清晰了,系统交互简化了,调用链路也减少了。
图一
图二
3、分布式事务检查
分布式事务调用的成本很高,服务拆分尽量避免产生跨服务事务,能合则合。如无法合并则优先考虑TCC或基于MQ的柔性事务,尽可能规避2PC等对性能影响很大的事务方案。TCC可完全替换2PC,但开发成本偏高,需要调用各方都同步修改以支持Try、Confirm和Cancel操作,某些场景会调用三方服务,其代码不受我们控制,此时可以考虑使用MQ实现异步消息和补偿性事务。咱们的业务比较复杂系统间的交互协作比较多,分布式事务在所难免。
举一个比较典型的case就是,验收报告确认的时候,因为会产生延期会同步修改排期时间(排期领域)、有验收不合格项会记录整改工单(整改领域)、同步修改验收报告为代项目经理确认或待业主确认(验收单领域)、有延期赔付的话需要确认延期赔付(服务承诺领域)等等,者么多的领域服务调用都要确保成功才能算该节点验收通过,采用分布式事务显然成本很大,必然导致接口耗时增加很多影响接口性能和系统稳定。
咱们具体看看一下这几个领域的特点。其中排期领域和整改领域是同一类领域在发生错误或者修改的时候要做到始终以最后一次提交为准,那就要领域服务内做到“幂等”。最好能从产品层面达成一致,比我们整改领域就是和产品同学达成产研层面的一致:始终以最后一次提交的整改为准。我们会记录本次验收提交的整改单,若有重复提交只记录最后一次提交的整改。当然这是在业务场景教低频的情况下的解决方案,大家按照自己的实际的情况采用最适合自己业务场景的技术方案。
而验收单领域、延期赔付(服务承诺领域)就是同步更新操作,天然的幂等操作。在这种业务场景下即使重复提交也是更新到目标状态所以也是没有问题。
4、性能分布检查
对于特别耗资源的操作应尽量独立。这部分咱们系统中应该没有类似场景大家知道这方面的范式即可。
5、稳定(易变)性检查
一个服务中如存在稳定和不稳定的模块,应该将两者拆分。这部分也是暂时没有在咱们的业务场景中遇到,基本上都分别部署的,质量领域中目前验收模版配置是频繁发生的也是单独拆分成子领域迭代,验收模版配置的变更不会影响验收应用层,大家在进行领域划分系统设计的时候关注这方面的影响即可。
6、调用链检查
服务间调用有IO消耗且不易追踪,应控制调用链路的长度。通过服务间的调用链路可以很清晰的发现历史无效代码的调用,需求迭代查产生的无效逻辑,以及潜藏的重复调用、循环依赖、以及系统可优化点等等。如下图就是一个验收提交的case,由于迭代时间太长,其中有很多废弃的逻辑没有删除,代码臃肿不说调用其他服务的接口、发送的消息、都是资源成本,若能及时梳理清楚代码整洁性提高了,维护成本降低,切服务稳定性也有了提升。