需同时支持RESTful API与消息通信的微服务设计最佳实践咨询
两种方案的不足分析
方案1(多仓库拆分)的核心问题
- 多仓库维护成本高:需要同时维护核心业务库、REST服务库、MQ消费服务库三个代码仓库,配套的CI/CD流水线、版本管理规则都要做三套,迭代效率低
- 版本对齐难度大:核心业务层迭代后需要主动通知两个上层通信服务同步升级依赖,非常容易出现版本不一致导致的业务逻辑不统一问题
- 适配逻辑易腐化:如果两个通信层有差异化的参数处理需求,很容易倒逼核心业务层增加大量兼容逻辑,逐渐失去纯业务属性
方案2(单仓库多入口)的核心问题
- 依赖易臃肿:如果没有做好模块化隔离,REST层的web依赖、MQ消费层的消息中间件依赖会全部导入到同一代码库,容易出现依赖冲突,最终打包的镜像体积也会更大
- 发布风险更高:如果代码边界划分不清晰,修改REST层逻辑时很容易意外影响MQ消费入口的逻辑,单独迭代某一个通信能力时需要做全量回归,验证成本高
- 配置复杂度上升:如果要在同一镜像里同时支持两种入口,启动配置、环境变量的判断逻辑会越来越复杂,排查问题的成本也会更高
该场景的最优实践
基于方案2做模块化优化,兼顾可维护性和部署灵活性:
- 同一代码库内做三层模块化拆分,模块之间严格限定依赖关系:
core-bl模块:纯业务逻辑实现,不依赖任何通信层组件,仅暴露通用的业务服务接口,所有入参出参使用和通信协议无关的通用DTOrest-adapter模块:仅依赖core-bl模块,实现REST接口的路由、参数校验、请求响应序列化逻辑,调用core-bl的接口完成业务处理mq-adapter模块:仅依赖core-bl模块,实现消息订阅、反序列化、消费重试、死信处理逻辑,调用core-bl的接口完成业务处理
- 打包阶段输出两个独立的可执行包/镜像,分别对应REST服务和MQ消费服务,也可根据团队习惯输出全量包,通过启动参数开关控制启用的入口
- 部署阶段两个服务完全独立运行、独立配置资源、独立扩缩容:承载大流量的MQ消费服务可分配更多CPU、内存资源,大促期间仅需要单独扩容MQ消费实例即可,不需要调整REST服务的资源
补充注意点:业务逻辑层必须保证无状态、不感知上层通信方式,所有和协议相关的处理逻辑全部收敛到对应的adapter层,避免逻辑耦合。
内容的提问来源于stack exchange,提问作者amirNamdar
相关产品推荐
相关产品推荐

