





















原文作者:Martin Fowler | 发布时间:2018-04-24
原文地址:https://martinfowler.com/articles/break-monolith-into-microservices.html
随着单体系统体量日趋庞大、维护成本激增,大量企业选择将其改造为微服务架构。这是一条值得投入但绝不轻松的落地之路。过往实践证明:稳妥的改造路径,要从边界简单的服务起步,优先抽取业务价值高、迭代频繁的垂直业务能力;拆分出的服务初期体量可以偏大,且尽量不再反向依赖遗留单体。每一轮迁移改造,都要让整体架构获得确定性优化(原子式演进)。
将单体系统改造为微服务生态是一场漫长工程。企业落地该改造的诉求通常包括:支撑业务规模化扩容、加速研发迭代效率、降低系统变更成本;依托微服务,企业可拆分多支团队并行交付、独立迭代;快速落地业务创新试验、摆脱单体改造成本高昂的桎梏。
改造过程中最核心的架构难题是:确定哪些业务能力要拆分、拆分时机、增量迁移方案。本文面向研发、架构师、技术管理者,提供一套落地方法论。
下文以多层架构在线零售系统为案例讲解,该系统前后端、业务逻辑、数据库深度耦合,是绝大多数企业单体项目的典型形态;选用它的原因是:技术栈成熟,适合渐进拆分而非全盘重写。
动工拆分前,团队必须对齐微服务生态的统一认知:微服务由若干服务组成,每个服务封装一项独立业务能力(Business Capability,即领域内为达成业务目标所需完成的业务动作)。
破除误区:微服务里的“微”不代表服务体量必须极小,服务规模取决于企业运维成熟度,Martin Fowler观点:微服务只是架构标签,不能用尺寸定义。
图1:服务封装业务能力,通过自助式API对外暴露数据与功能
改造单体改微服务整体改造成本高昂、需要多轮迭代落地,动工前架构团队务必审慎评估:是否真的需要拆分、微服务是否适配自身业务。确认方向无误后,按下述步骤落地。
落地微服务的前提是企业具备基础运维能力:按需开通部署环境、搭建支持服务独立构建/测试/发布的持续交付流水线、具备分布式架构的安全管控、问题排查、监控能力。无论新项目从零搭建,还是存量单体拆分,这套基建必不可少。近些年微服务配套基础设施飞速发展:服务网格(Service Mesh,专用微服务基础设施层,保障服务网络高速、可靠、安全)、容器编排、GoCD等CI/CD工具均已成熟可用。
落地建议:前两个拆分的服务同步完成基建、流水线、API网关建设;优先挑选和单体耦合极低、无需改动大量前端调用方、甚至无需自建数据库的业务能力拆分。
该阶段核心目标:验证交付流程、团队技能练兵、搭建基础平台,产出可独立部署、对外提供自助API的安全服务。
零售案例:第一个拆分:终端用户认证服务(单体调用该服务完成用户鉴权);第二个拆分:用户档案服务(为新客户端提供统一用户视图的门面服务)。
图2:从改动范围小的边缘能力起步,打磨整套运维落地能力,单体剥离鉴权逻辑,独立为鉴权服务
优先拆分边缘服务的原因:改造初期团队最大风险是不具备微服务运维能力,边缘服务用来练手补齐运维必备能力;等运维体系成熟后,再攻坚单体核心拆分难题。
核心原则:新拆分出的微服务尽量不要反向依赖单体(数据、逻辑、API)。微服务的核心优势是独立快速发版,一旦依赖单体,就会被单体的发布节奏捆绑,丧失独立迭代能力。
改造的初衷本是摆脱单体变更成本高、迭代慢的痛点,因此拆分设计要朝着单体依赖新服务,而非新服务依赖单体的方向演进。单体调用新服务是理想依赖方向,不会拖累新服务迭代。
零售场景举例:下单(Buy)、营销活动(Promotions)是两大核心能力,下单结算时需要调用营销活动校验优惠。拆分顺序:先拆营销服务,再拆下单能力。拆分后下单逻辑仍留在单体,由单体主动调用独立后的营销服务,无反向依赖。
极端场景:新服务不得不反向调用单体
解决方案:单体新增对外API,新服务通过防腐层(Anti-Corruption Layer)调用单体接口;防腐层做数据模型转换,杜绝单体老旧业务概念污染新服务领域模型。API设计遵循标准领域定义,忽略单体内部杂乱实现。代价:改动单体、同步联调,新服务发布被单体发布绑定。
图3:优先拆分无反向依赖的服务,理想依赖:单体→新服务;劣等依赖:新服务防腐层→单体接口
完成边缘服务拆分、团队掌握微服务落地能力后,会遇到瓶颈:剩下的业务能力拆分后必然反向依赖单体,根源是单体中存在高度粘连、领域边界模糊、全系统多处依赖的公共模块(粘性能力)。
解决思路:定位该粘性模块,拆解为标准领域概念,再拆分成多个独立服务。
经典案例:Web会话(Session)
单体里的Session是数据杂糅容器:混杂用户偏好(收货/支付偏好)、浏览记录、商品收藏、页面访问轨迹等跨领域数据。不拆分会话,后续所有关联模块拆分都会被Session牵绊。
避坑:不要直接整体拉出一个Session服务,只会把进程内紧耦合变成跨网络紧耦合。
正确落地:增量拆解,逐个拆分:先拆用户收藏服务→再拆支付偏好服务,循序渐进。
图4:拆解高耦合公共会话,拆分为用户档案、收藏、支付配置等独立服务
工具建议:使用Structure101等代码结构分析工具,定位单体中耦合最重、制约整体拆分的粘性模块。
拆分的终极目标是实现服务独立发布,该原则指导所有拆分决策。传统单体大多分层紧耦合、多模块共用一套数据库,很多团队拆分误区:只抽前后端门面服务,数据库继续共用。这种拆分只能快速优化前端迭代效率,但核心业务仍共用单体数据库,整体发布受制于最慢的单体,算不上真正的微服务(微服务核心特征:去中心化独立数据存储)。共享数据库是服务独立拆分的最大阻碍。
正确策略:垂直整段剥离业务+配套剥离自有数据库,全链路客户端切换至新服务API。多应用读写同一库是数据无法拆分的元凶,团队按需选用数据迁移方案;推荐参考Stripe四阶段增量迁移方案:业务不停机、应用逐步切库、从共用数据库逐步切到服务私有库。
图5:业务连同数据一起剥离为微服务,对外提供新接口,所有调用方切换接入新API
反模式警示:只拆前后端逻辑、不拆分配套数据库,本质仍是分布式单体。
单体拆分难度极高,Neal Ford曾用精密器官外科手术类比拆分:提取一项业务能力,要连带数据、业务逻辑、前端组件完整剥离,并切换调用链路。拆分要持续权衡改造成本与落地收益(提速迭代、支撑扩容)。
筛选标准:优先拆分业务价值高、频繁迭代、拖累整体研发速度的模块。可通过两点筛选:
零售案例:用户个性化推荐模块,持续迭代优化用户体验、产品频繁做A/B试验,是优质拆分目标。
图6:拆分对业务价值最高、改动最频繁的业务模块
工具建议:CodeScene代码提交分析工具,过滤构建脚本自动变更的无效提交,结合产品规划锁定待拆模块。
单体拆分两条路线:①直接搬运现有代码抽成服务;②重新落地业务能力、下线单体旧代码。
多数人本能倾向第一种:依恋自己编写的代码(宜家效应:对自己付出劳动的产物高估价值、不愿舍弃),但该思路会拖累拆分进度。
行业结论:绝大多数场景推荐重新开发新服务、下线单体旧代码,复用老代码弊端:
图7:高价值低冗余代码:抽取复用;低价值高坏味道代码:重新开发、旧代码下线
工具建议:CheckStyle等代码质量工具,评估代码毒性,决策重写还是搬迁。
DDD限界上下文是划分服务边界的有效手段,但大量团队走向另一个极端:单体直接拆成无数细碎CRUD小服务,形成贫血服务集群。弊端:无法独立发布、分布式事务泛滥、故障排查困难、远超团队运维承载能力。
落地原则:初期围绕完整领域拆粒度偏大的宏服务;等团队运维、多服务发布能力成熟后,再做二次细化拆分。微服务的“微”没有固定标准:以团队可独立运维、发布的服务数量上限为准。
零售案例:初期下单(Buy)服务统一收纳购物车+结算全逻辑;后续团队能力提升,再拆分为购物车服务、结算服务两个微服务。
图8:先粗粒度整合成大服务,后续运维成熟再细化拆分
技术选型:采用Richardson成熟度模型L3(超链接驱动API),通过资源链接实现未来无痛拆分,调用方无需提前感知内部拆分变化。
全盘推翻重写单体是伪命题,落地风险极高,很多拆分项目因预算耗尽、组织架构调整、业务方向变更中途搁浅。因此采用原子式演进迁移:单次拆分是不可分割的完整单元,要么全量落地、要么完整回滚;每一步改造后,系统架构必须向最终微服务目标靠近,不能越改越乱。(架构适配函数:每轮改造后架构指标向目标收敛)
鉴权服务落地举例(反面错误落地)
正确原子落地三步闭环(缺一不可)
图9:原子化三步闭环演进,持续向微服务目标收敛
高频反模式:新服务只给新业务使用,老单体旧逻辑永久保留,两套逻辑长期并存。
出现该问题根源:团队只盯着短期收益、新项目排期挤压老代码下线工作量。
解决思路:切分更小的原子改造单元,缩短单轮改造周期,拆分项目可随时暂停、重启。
单体拆微服务是长跑项目,依托原子化小步迭代、闭环下线旧代码,稳步蚕食老旧单体,平稳完成架构升级。
除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。