什么是分布式单体?如何避免微服务变成分布式单体?
简化版
分布式单体是指系统形式上拆成了多个服务,但服务之间强耦合、必须一起开发测试发布,实际仍像一个单体。避免它的关键是划清业务边界和数据边界,减少同步强依赖,让服务能独立演进。
详细版
分布式单体常见表现:
- 一个需求必须同时改多个服务。
- 多个服务共享同一个数据库,互相直接读写表。
- 服务接口暴露内部实现细节,字段一改全链路受影响。
- 发布必须按固定顺序一起发。
- 服务之间同步调用链过长,一个服务慢会拖慢整条链路。
- 没有契约测试和版本兼容,上游下游互相卡发布。
避免方式包括:按业务能力拆分、数据库归属单一、对外接口稳定、事件驱动解耦、接口版本兼容、设置超时熔断、用契约测试保证兼容性,并且组织上让服务有明确 owner。
完整版教学
一、为什么会出现分布式单体
分布式单体通常不是一开始故意设计出来的,而是在“想上微服务”的过程中慢慢长出来的。
团队可能先把代码拆成多个服务,但没有重新梳理业务边界;又因为改造成本高,数据库还是大家共用;为了快速完成需求,服务之间互相调用内部接口;上线时担心兼容问题,于是多个服务仍然一起发布。
结果就是:部署形态变成分布式,协作方式仍然是单体。单体里至少方法调用快、事务简单;分布式单体却把网络失败、链路延迟、运维复杂度都引进来了,同时没得到独立发布和独立演进的好处。
二、分布式单体的典型症状
可以用几个问题快速判断:
| 判断问题 | 如果答案是“是”,说明什么 |
|---|---|
| 服务 A 能直接改服务 B 的表吗 | 数据边界失守 |
| 一个接口字段改动会影响很多服务吗 | 契约不稳定 |
| 发布必须多个服务排队一起发吗 | 发布边界没有独立 |
| 一个小需求要改五六个服务吗 | 业务边界可能拆错 |
| 调用链十几层且都同步等待吗 | 运行时耦合过强 |
这些症状越多,系统越像分布式单体。
三、共享数据库为什么危险
共享数据库是分布式单体最常见的根。
假设订单服务、营销服务、客服服务都直接查 order 表。短期看很方便,长期会出现三个问题:
第一,表结构不敢改。订单服务想调整字段,必须确认所有直接查表的服务。
第二,业务规则绕过了服务。客服服务直接改订单状态,可能没有触发订单服务里的状态机校验。
第三,问题归属不清。数据异常时,很难知道是谁写坏的。
微服务强调“数据由服务拥有”,不是说每个服务物理上一定要一个数据库实例,而是写入权和业务规则必须归属清楚。其他服务需要数据,可以通过 API 查询、事件订阅、数据同步视图等方式获得。
四、接口耦合如何把服务绑死
接口如果暴露内部表字段,就会变成远程数据库访问。例如订单服务提供:
{
"order_status": 3,
"pay_status": 2,
"coupon_flag": 1
}
调用方必须理解这些编码含义。一旦内部状态机调整,调用方就可能出错。
更好的接口应该表达业务语义:
{
"orderState": "PAID",
"canCancel": true,
"afterSaleAvailable": false
}
接口越接近业务语义,调用方越不需要知道内部实现,服务越容易独立演进。
五、避免分布式单体的治理手段
避免分布式单体要同时做架构和工程治理。
架构上,要明确服务边界、数据 owner、调用方向。核心链路上的同步调用要克制,能异步解耦的尽量用事件。
工程上,要做接口版本管理、契约测试、灰度发布、兼容字段保留期。不能因为一个字段改名,就要求所有下游同一时间上线。
组织上,每个服务要有明确 owner。没有 owner 的服务会逐渐变成公共垃圾桶,什么逻辑都塞进去。
六、常见误区与追问
这道题要紧扣「分布式单体」本身回答,不能把它混成泛泛的微服务架构套话。面试官通常会沿着“为什么需要、流程怎么走、失败怎么兜、代价是什么”继续追问,所以回答要覆盖服务边界、通信方式、网关/BFF、数据归属、版本兼容和部署治理。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心结论 | 分布式单体表面是多个服务,实际仍强依赖、强耦合、同步调用链长,发布和故障像单体一样互相拖累 | 不要停在名词解释 |
| 流程机制 | 服务拆分过细 -> 接口相互依赖 -> 共享数据库或模型 -> 发布互相等待 -> 故障级联扩散 -> 重新梳理边界 | 要说清触发点、状态变化、确认点和失败兜底 |
| 工程取舍 | 下单必须同步调用 8 个服务且任一服务发布都要全链路回归,这就是分布式单体的典型信号 | 微服务提升团队自治和独立演进能力,但会带来分布式调用、数据一致性、依赖治理和运维复杂度 |
分布式单体 面试拆解:
1. 服务拆分过细
2. 接口相互依赖
3. 共享数据库或模型
4. 发布互相等待
5. 故障级联扩散
6. 重新梳理边界
记忆钩子:先给结论,再拆流程,再讲数字例子和失败边界;回答「分布式单体」时要围绕题目问法收束,不要把相邻概念堆成一段没有重点的名词清单。
- 误区:服务数量多就是微服务。 如果边界和自治不存在,只是把单体拆成了远程调用。
- 误区:分布式单体一定比单体先进。 它常常同时拥有单体耦合和分布式复杂度。
- 误区:只靠技术框架能解决。 根因通常是领域边界、团队协作和数据归属不清。
- 追问:如何识别分布式单体? 看共享数据库、循环依赖、同步链路长、统一发布和改一处动全身。
- 追问:怎么治理? 收敛边界、减少同步依赖、拆数据所有权、事件解耦和契约测试。
- 追问:要不要立刻拆更细? 不一定,先减少耦合和稳定接口,再按业务价值拆。
七、加强记忆
分布式单体的可怕之处在于“两头不占”:没有单体的简单,却也没有微服务的独立。避免它要盯住三条线:业务边界别乱、数据归属别乱、发布契约别乱。