单体项目如何"无感"演进微服务?Core+BFF分层架构实践
很多技术团队在进行微服务改造时,都会陷入两难困境:单体架构代码臃肿、维护成本高,但直接全量拆分微服务,又存在改造风险大、迭代停滞、线上稳定性不可控等问题。很多从单体转型的开发人员,都害怕为了架构升级而强行重构,最终引发大量问题。
在微服务改造的认知中,很多人存在误区:认为微服务等于彻底拆分、全量重构、多服务堆砌。本文介绍一种低侵入、可渐进、业务无感的改造思路:无需推翻原有单体代码、无需一次性大规模重构,通过 Core 核心下沉 + 双 BFF 分层剥离的方式,让单体架构平滑演进为微服务内容中台。
本文基于真实落地经验,拆解 Core + Admin BFF + App BFF 分层架构的设计思路、服务通信原理、协议规范与落地细节,帮助单体开发者理解渐进式微服务的改造逻辑,降低转型门槛。
一、为什么多数单体转微服务的改造效果不佳?
传统单体后台、CMS 系统的微服务改造,大多采用暴力拆分的方式:将用户、内容、权限、文件等模块逐一拆分为独立服务。这种方式看似符合微服务规范,实际落地中存在诸多问题,也是很多团队宁愿保留单体架构的主要原因。
暴力拆分模式主要存在三大痛点:
1. 改造侵入性高,无法平滑过渡
全量拆解业务逻辑、重构接口、拆分数据库,代码改动范围极大,业务迭代需要暂停,测试回归成本高,极易引发线上问题,无法做到业务无感升级。
2. 服务粒度过细,治理成本大幅增加
过度拆分容易造成服务数量爆炸,产生大量细粒度服务,随之带来服务注册发现、链路追踪、事务一致性、运维部署等一系列治理问题,中小团队难以承接。
3. 前后端耦合问题未从根源解决
即便完成了服务拆分,若前端直接对接底层业务服务,管理端、移动端、小程序等多端的差异化需求,依然会持续污染底层接口,最终形成"微服务架构、单体式代码"的尴尬局面。
相对合理的微服务演进思路,应当满足:业务无感知、代码低侵入、架构可持续迭代、性能稳步提升。
而 Core+BFF 分层架构,正是适配单体项目平滑升级的渐进式微服务方案。
二、什么是无感演进?分层架构核心改造思想
单体无感演进微服务,核心不是拆分服务,而是拆分职责、分层解耦。在不颠覆原有业务逻辑、不影响线上功能的前提下,通过分层设计,剥离前端定制、多端适配、流量承接等场景化逻辑,让底层专注通用核心能力,上层适配多样化业务场景。
本文采用三层极简分层模型,适配单体项目平滑升级:
1. Core 核心层:单体提纯后的业务内核
沉淀系统通用、稳定、无场景偏向的核心能力,包含数据持久化、基础业务规则、多租户底层、权限模型、内容建模、文件资源管理、定时任务等能力。Core 仅对内提供服务能力,不直接对外暴露接口,不对接任何前端端。
2. Admin BFF 层:管理后台专属场景层
承接管理后台的定制化场景需求,负责接口聚合、全量数据查询、批量操作、数据导出、操作日志记录、精细化权限控制等能力,适配 PC 管理端严谨、复杂的业务操作场景。
3. App BFF 层:用户多端场景适配层
承接用户端各类场景需求,适配 Web、小程序、移动端等多端,负责数据字段裁剪、接口合并、缓存优化、弱网适配、用户交互逻辑处理,屏蔽底层业务复杂度。
整体架构调用流向清晰:
管理前端 → Admin BFF → Core 核心
多端用户前台 → App BFF → Core 核心
核心演进逻辑:底层能力稳定沉淀、上层场景分层剥离、渐进式迭代升级,全程无需重构核心业务,实现单体架构的平滑迁移。
三、分步拆解:单体项目无感升级落地流程
这套演进方案适配绝大多数单体 CMS、后台管理系统,分为三个阶段稳步落地,风险可控、可回滚、不中断业务迭代。
阶段一:内核提纯,将单体稳定能力下沉至 Core
单体架构的核心问题是:核心业务逻辑、前端适配逻辑、场景定制逻辑高度耦合。
第一阶段不删除、不修改原有业务代码,仅做能力归集与分层剥离:
-
将数据 CURD、业务规则校验、租户逻辑、权限内核、内容模型、资源存储等通用稳定能力,统一抽离至 Core 服务;
-
由 Core 统一对接数据库、缓存、对象存储,作为系统唯一的数据出入口,保障数据一致性;
-
废弃单体中杂乱的对外接口,Core 仅提供标准化、通用化的底层能力接口。
本阶段业务功能完全无感知,仅完成代码分层与能力梳理,无线上改造风险。
阶段二:场景剥离,双 BFF 层承接全量前端流量
内核能力稳定后,搭建两个轻量 BFF 服务,接管所有前端流量,彻底解耦前后端逻辑:
1. Admin BFF 接管管理端流量
将单体中管理后台的定制逻辑统一迁移至 Admin BFF,包含接口聚合、全量数据返回、批量操作、数据导出、租户管理、精细化权限控制等。Core 不再处理任何前端场景逻辑,专注底层能力支撑。
2. App BFF 接管多端前台流量
针对用户多端差异化场景,在 App BFF 统一做适配处理:按需裁剪返回字段、合并高频接口、优化缓存策略、适配弱网环境、处理用户交互逻辑。
至此完成架构核心转型:Core 负责通用能力,BFF 负责场景适配,解决单体代码臃肿、逻辑混杂的问题。
阶段三:剥离单体冗余,实现服务独立迭代扩缩容
分层架构稳定后,逐步下线单体冗余混杂代码,实现三服务独立部署、独立迭代、独立扩容:
-
前台流量高峰时,仅扩容 App BFF 服务,不影响后台与核心服务;
-
管理后台迭代更新时,仅升级 Admin BFF,不干扰前台用户访问;
-
Core 服务长期稳定迭代,保障系统数据与能力底座的可靠性。
整体改造属于渐进式升级,无业务中断、支持随时回滚,是中小团队适配单体升级微服务的友好方案。
四、架构答疑:为什么需要双 BFF 层,前端不能直连 Core?
很多转型开发者会产生疑问:Core 已经封装好底层能力接口,为什么需要额外增加 BFF 层,是否属于多余设计?
实际上,BFF 分层是单体平滑演进微服务的关键设计,是实现低风险升级的核心保障。
1. 解决多端场景冲突,避免底层接口臃肿
若前端直接对接 Core 服务,底层接口需要同时适配管理端全量数据、Web 精简展示、移动端适配、小程序弱网等多类场景。最终底层接口会被迫兼容所有场景,重新变成单体时代的万能接口,架构分层彻底失效。
双 BFF 分层后,职责完全隔离:Core 定义通用标准,BFF 适配差异化场景,从根源解决多端场景冲突问题。
2. 实现分层迭代,降低核心代码变更频率
前端样式调整、交互优化、多端适配需求变更,全部在 BFF 层完成,无需改动 Core 核心代码。底层能力保持稳定,上层场景灵活迭代,解决单体架构"改一处、动全身"的问题。
3. 实现流量与故障隔离,提升系统稳定性
单体架构与传统微服务,普遍存在流量混杂问题:前台高并发流量挤占后台资源,后台运维操作影响前台用户体验。
Core+BFF 分层架构可实现流量、资源、故障的多层隔离:
-
App BFF 出现异常,仅影响前台用户访问,管理后台完全正常;
-
Admin BFF 升级迭代,不干扰前台用户浏览、交互;
-
Core 统一兜底数据与核心能力,保障数据一致性。
五、注册中心原理:单体开发者看懂 Etcd 服务注册与交互逻辑
单体转微服务的核心认知难点,是理解跨服务通信逻辑:多个独立服务如何互相发现、正常调用。
单体架构中,所有代码运行在同一进程内,模块调用可直接实例化调用方法,无需网络寻址、无需服务发现。拆分 Core、Admin BFF、App BFF 后,三个服务为独立进程、独立部署、独立端口,彼此完全隔离,需要依赖注册中心实现通信。
本节解答两个核心问题:
-
Core、BFF 如何自动注册、互相发现?
-
BFF 调用 Core 的完整链路是什么?Etcd 在其中承担什么作用?
1、单体与微服务调用的本质区别
单体架构:进程内本地调用,基于内存直接执行,无需网络、无需注册中心、无需寻址。
分层微服务架构:Core、App BFF、Admin BFF 为独立进程,属于跨进程远程调用,需要通过网络寻址完成服务调用。
由于服务支持多实例部署、动态扩缩容、容器动态 IP,无法通过硬编码 IP 端口的方式调用,因此需要注册中心统一托管服务实例信息。
Etcd 核心作用:统一托管所有服务实例信息,实现服务自动感知、动态寻址、故障切换。
2、Etcd 核心角色:服务集群的统一通讯录
可以将 Etcd 理解为服务集群的统一通讯录:
-
Core、Admin BFF、App BFF 均为集群内独立服务节点;
-
Etcd 负责统一记录所有服务的节点信息与健康状态;
-
注册:服务启动后主动上报自身服务名、IP、端口信息;
-
发现:服务调用前,从 Etcd 查询目标服务可用节点;
-
健康检测:通过心跳机制监控服务状态,自动剔除故障节点。
3、服务启动注册流程(全自动执行)
所有服务启动后,会自动完成注册逻辑,无需人工干预:
步骤1:服务初始化
Core、BFF 服务启动,加载自身服务名称、监听端口、版本等配置信息。
步骤2:连接 Etcd 集群
服务内置微服务组件,自动连接配置好的 Etcd 集群地址。
步骤3:上报服务信息
将自身服务名、运行 IP、端口、健康状态以键值对形式写入 Etcd。
常规存储路径示例:
-
/registry/gowind.core:存储 Core 服务实例列表 -
/registry/gowind.admin:存储 Admin BFF 实例列表 -
/registry/gowind.app:存储 App BFF 实例列表
步骤4:开启心跳保活
服务持续向 Etcd 发送心跳,维持在线状态。
若服务宕机、进程退出,心跳中断,Etcd 会自动过期清理故障节点,实现故障自愈。
4、BFF 调用 Core 完整交互流程
以用户前台查询内容场景为例,完整拆解跨服务调用链路:
场景:用户前台请求文章列表 → App BFF → Core 内核取数
步骤1:BFF 接收前端请求
前端通过 HTTP 协议访问 App BFF 对外 REST 接口。
步骤2:BFF 执行服务发现
App BFF 需要调用 Core 能力,主动从 Etcd 查询当前在线的 Core 服务实例。
步骤3:本地缓存节点信息
BFF 获取 Core 节点列表后本地缓存,同时监听节点变更,后续请求无需重复查询 Etcd,保障调用性能。
步骤4:负载均衡选择节点
Core 多实例部署时,BFF 通过负载均衡策略选择可用节点发起调用。
步骤5:内网 gRPC 远程调用
BFF 通过内网 gRPC 协议,携带结构化参数请求 Core 服务。
步骤6:Core 执行业务逻辑并返回数据
Core 完成数据查询、权限校验、业务处理后,通过 gRPC 返回结构化数据。
步骤7:BFF 场景适配后返回前端
BFF 根据前端场景裁剪字段、聚合数据,转为标准 JSON 格式返回前端。
极简链路总结:
前端 HTTP 请求 → BFF 服务发现 → 内网 gRPC 调用 Core → Core 处理业务 → BFF 适配格式化 → 前端响应
5、常见问题答疑
Q1:为什么不硬编码 IP 端口调用?
硬编码地址无法适配动态扩缩容、容器动态 IP、故障自动切换等场景,服务不具备弹性能力。注册中心可实现服务无状态、动态寻址,适配云原生部署模式。
Q2:服务注册与发现的主体是谁?
-
Core、所有 BFF 服务均主动向 Etcd 注册自身信息;
-
依赖方执行服务发现:BFF 依赖 Core,由 BFF 主动发现 Core 节点,Core 不依赖上层服务,无需发现其他节点。
完全贴合「底层沉淀、上层适配」的分层架构逻辑。
Q3:Etcd 宕机会导致服务瘫痪吗?
不会。服务启动后会本地缓存节点列表,Etcd 临时异常不会影响已有的服务调用。Etcd 仅负责节点变更通知与注册注销,不参与每一次业务调用,无单点调用瓶颈。
6、注册发现模式的架构优势
-
摒弃硬编码地址,实现全动态服务寻址;
-
支持节点故障自动剔除、新节点自动上线,提升集群稳定性;
-
三类服务注册信息相互隔离,流量互不干扰;
-
支持无感扩容,新增节点自动承接流量,业务无感知;
-
适配单体渐进式改造,无需一次性重构整套服务。
7、服务注册与调用极简链路图
整理整套架构注册发现与业务调用全链路流程:
plain
# 一、服务启动注册链路(所有服务自动执行)
Core服务 ──心跳注册──┐
Admin BFF ──心跳注册──┼──> Etcd注册中心(托管节点 + 健康检测)
App BFF ──心跳注册──┘
# 二、线上业务请求调用链路
多端前端(Web/小程序/后台)
↓ HTTP/REST(公网、JSON、多端适配)
┌──────────────┐ ┌──────────────────────────────┐
│ Admin/App BFF │──>│ 1.拉取Etcd中Core节点并本地缓存 │
│ 场景适配层 │──>│ 2.负载均衡筛选可用Core实例 │
└──────────────┘ └──────────────────────────────┘
↓ gRPC(内网、二进制、高性能)
Core 内核服务(数据持久化/核心业务/权限模型)
↓ 返回结构化数据
BFF层二次适配:字段裁剪 / 接口聚合 / 场景格式化
↓ REST JSON
前端页面渲染展示
链路核心:启动注册、运行发现、内网RPC通信、外网REST适配、分层各司其职,支持服务动态扩缩容与故障自动切换,支撑单体架构平滑升级。
六、通讯协议分层:内网gRPC、外网REST的设计逻辑
整套架构采用标准化分层协议设计:Core与BFF的内网服务通信统一使用 gRPC 协议,BFF 与前端的公网通信统一使用 RESTful HTTP 协议。两层协议隔离,适配不同通信场景。
1、内网选用 gRPC 的核心原因
Core 与 BFF 均为内网后端服务,通信场景可信、调用频次高,gRPC 更适配内网服务交互:
① 通信效率更高
gRPC 基于 HTTP/2 协议,采用 Protobuf 二进制序列化,相比 JSON 文本协议,传输体积更小、序列化速度更快、带宽占用更低,适合服务间高频聚合调用。
② 强契约约束,降低协作问题
Protobuf 可定义完整的数据结构、字段类型与接口约束,内网接口强类型、标准化,有效避免参数混乱、字段不统一等问题,让内核能力输出更规范。
③ 原生适配微服务治理
gRPC 原生支持注册发现、超时控制、熔断降级、流式传输等能力,适配微服务架构的治理需求,无需额外封装即可实现稳定的内网通信。
2、外网选用 REST 的核心原因
BFF 直接对接浏览器、小程序、移动端等多端,公网场景复杂、设备多样,REST 是兼容性最优的选择:
① 全前端生态原生兼容
所有前端框架、多端设备原生支持 HTTP/REST 请求,接入成本极低。而 gRPC-Web、GraphQL 等协议需要前端额外适配,不利于多端统一接入。
② 调试便捷,问题排查效率高
REST 基于 JSON 文本格式,可读性强,支持浏览器直接访问、抓包调试,大幅降低前后端联调与线上问题排查成本。
③ 适配公网基础设施能力
REST 接口天然适配浏览器缓存、CDN 加速、跨域配置、网关限流、SSL 加密等公网能力,更适合面向用户端的接口开放场景。
3、BFF 对外协议的可扩展性
REST 为默认最优方案,但 BFF 层不绑定固定协议,可根据业务场景灵活替换:
① GraphQL:适合复杂数据大盘、自定义字段查询场景,由前端按需获取数据;
② gRPC-Web:适合高并发、低延迟的实时数据展示场景;
③ 多协议共存:支持同一服务同时部署多种协议,按需适配不同业务场景。
4、协议分层的架构价值
分层协议设计为架构平滑升级提供底层支撑:
-
内外接口隔离,内核不暴露公网,规避外网参数污染、恶意请求风险;
-
内外协议独立迭代,内核升级不影响前端,前端适配不改动内核;
-
兼顾内网通信性能与外网兼容性,平衡后端效率与前端协作成本。
七、BFF 层 Protobuf 分层设计与团队落地规范
架构中核心的设计细节为:Core 与 BFF 完全拆分 Protobuf 定义,BFF 独立维护对外路由协议,通过包名与文件前缀分层隔离,BFF 仅负责路由定义,不重复定义业务模型。
很多开发者存在认知误区:Proto 文件应当全局共用、一处定义多处引用。这种模式适合简单微服务,并不适配分层架构场景。
1、为什么不全局共用一套 Protobuf?
传统共用 Proto 模式,会导致架构重新耦合:
① 内外契约耦合,无法独立迭代
Core Proto 是内网 RPC 契约,侧重严谨完整;前端 REST 契约侧重灵活适配。共用文件会导致内核字段不敢迭代、必须兼容所有前端场景,底层被上层绑架。
② 路由语义不匹配
Core gRPC 方法适配内网聚合调用,REST 路由适配浏览器 HTTP 规范,两者语义差异大,强行合并会产生不规范的接口定义。
③ 多端场景无法隔离
管理端与前台场景差异较大,路由规则、字段展示各不相同,共用 Proto 会导致场景逻辑污染内核定义。
2、BFF 独立 Proto + i_ 前缀的设计意义
这套设计的核心目的,是严格落地「Core 管能力、BFF 管场景」的分层思想:
① 包维度隔离两端接口
-
管理端协议统一归属包:
admin.service.v1 -
前台协议统一归属包:
app.service.v1
两端接口物理隔离,避免路由命名冲突、语义混淆,支持独立迭代。
② i_ 前缀区分分层属性
BFF 对外接口文件统一加 i_ 前缀(interface 对外接口层),区别于内核 Proto 文件,从命名上区分「内核能力文件」与「对外路由文件」,规避全局文件名冲突,也方便新人快速理解分层逻辑。
3、核心设计规则:BFF 只定义路由,不定义模型
这是分层 Proto 设计的核心:
-
BFF Proto:仅定义 Service 服务与 HTTP 路由映射规则;
-
所有数据结构体、枚举、业务模型,全部复用 Core Proto。
该设计兼顾数据统一性与场景灵活性:
-
全局数据模型统一,无重复定义,避免数据不一致;
-
BFF 可自由定制前端路由规则,适配多端场景;
-
内外协议解耦,内核与前端可独立迭代。
4、Core 与 BFF Proto 职责边界对照表
| 所属层 | Proto 职责 | 协议类型 | 是否定义数据模型 | 是否定义路由 |
|---|---|---|---|---|
| Core 内核 | 定义业务能力、数据结构、枚举、内核RPC方法 | 内网 gRPC | ✅ 全部业务模型 | ❌ 不对外暴露路由 |
| Admin BFF | 定义管理端 REST 路由、Http 映射规则 | 外网 REST | ❌ 复用 Core 模型 | ✅ 仅管理后台路由 |
| App BFF | 定义用户多端 REST 路由、Http 映射规则 | 外网 REST | ❌ 复用 Core 模型 | ✅ 仅前台用户路由 |
5、设计价值总结
-
隔离内外协议,保障内核稳定性与外层灵活性;
-
前后台路由物理隔离,规避场景冲突与命名干扰;
-
统一文件命名规范,规避编译冲突与代码混乱;
-
规范团队开发习惯,强化分层架构认知;
-
统一数据模型,同时保留多端路由定制能力。
6、团队极简落地:BFF 层 Proto 开发规范(统一标准)
为统一团队开发标准,规避新人开发不规范问题,BFF 层 Proto 严格遵循以下五条规范:
规则1:包路径分层隔离
管理端固定包名:admin.service.v1,前台固定包名:app.service.v1,禁止跨包、混包定义接口。
规则2:BFF Proto 文件统一 i_ 前缀
对外接口文件必须以 i_ 开头,如 i_user.proto,区分内核文件,规避全局命名冲突。
规则3:BFF 仅定义路由,不定义业务模型
BFF Proto 只编写 Service 定义与 HTTP 路由规则,所有请求体、响应体、结构体、枚举均复用 Core 内核定义,禁止重复创建业务模型。
规则4:内外协议各司其职
内网 gRPC 契约由 Core 维护迭代,外网 REST 路由适配由 BFF 维护,双方迭代互不影响。
规则5:专注前端场景适配
BFF Proto 仅用于生成对外 REST 接口,专注多端前端适配,不承担内网 RPC 与核心业务校验逻辑。
极简口诀:内核管模型、BFF管路由、文件带i前缀、两端分包写。
八、总结:微服务改造核心是分层解耦,而非盲目拆分
很多开发者存在误区:认为微服务的核心是服务拆分、数量越多架构越优秀。在存量单体项目改造场景中,盲目拆分只会增加治理成本、提升系统复杂度。
单体项目升级微服务的合理路径,不是推倒重来,而是:
提纯核心业务能力,剥离多端场景逻辑,通过分层解耦实现渐进式升级。
Core + 双 BFF 分层模式,保留了单体开发简洁、部署简单的优势,同时具备微服务可扩展、高可用、易维护、多端适配的特性,适合 CMS、内容中台、后台管理系统等单体项目的平滑微服务改造。