什么时候该从单体走向微服务
单体应用在团队小、业务简单的时候其实很高效:一个工程、一个部署、一个数据库,跑起来轻快。但当业务涨大、团队变多,一次改动要全量发布、模块之间互相牵扯,拆分的价值才开始显现。
微服务不是目标本身,而是当单体的协作和交付成本高到一定程度时,用来换取独立演进能力的一种手段。为拆而拆,往往得不偿失。
微服务解决的是「组织如何独立演进」的问题,而不是让架构看起来更时髦。
- 按边界拆围绕业务能力拆服务,而不是按技术层切。
- 注册发现服务启动自动登记,调用方动态找得到。
- 配置中心配置集中管理、动态下发,不写死。
- 网关容错统一入口,挡住雪崩与级联故障。
- 渐进演进先拆最痛的一块,别一步到位。
服务拆分:按业务边界,不是按技术层
最常见的错误,是照着技术层拆:用户服务、订单服务、商品服务……听起来整齐,实际边界却经常交叉。更稳的做法是围绕业务能力和限界上下文来拆,一个服务负责一块内聚的业务。
| 拆分方式 | 问题 | 更稳的思路 |
|---|---|---|
| 按技术层切 | 边界交叉,改动要跨多个服务 | 按业务能力拆,一块职责一个服务 |
| 一上来拆很碎 | 调用链太长,运维复杂 | 先拆最痛的核心域,逐步细化 |
| 多个服务共用一个库 | 数据边界糊在一起 | 服务自己管自己的数据 |
# 判断边界是否合理的一个问题
- 这个服务能不能由一个小团队独立开发、独立部署?
# 能,说明边界切对了;不能,往往还需要重新划分。
好的拆分让每个服务职责清晰、数据自治,团队之间的协作摩擦自然下降。
注册与发现:服务怎么找到彼此
拆成多个服务后,调用方不能再写死对方地址——服务会扩缩容、会换机器。注册发现就是让服务启动时把自己登记到注册中心,调用方再从注册中心动态拿到可用地址。
- 服务启动:把自己的地址上报到注册中心。
- 服务下线:注册中心及时摘除不可用节点。
- 调用方:按需拉取可用实例列表,而不是硬编码。
# 注册发现解决的核心问题
调用方问注册中心:「订单服务现在有哪些可用地址?」
注册中心返回一组健康实例
调用方选一个发起调用,并在失败时切换其他实例
# 地址不再写死,扩缩容对调用方透明。
有了注册发现,服务的增删和扩缩容才不会牵动一大堆配置改动。
配置中心:别把配置写死在代码里
几十个服务、每个都带一堆环境配置,散在代码和部署脚本里,改一项就要重新发版,既慢又易错。配置中心把这些配置集中存放、统一管理、动态下发。
| 做法 | 问题 | 配置中心的改进 |
|---|---|---|
| 配置写进代码 | 改配置要重新发版 | 配置集中,改完动态生效 |
| 各服务各管各的 | 同类配置互相不一致 | 统一来源、统一版本 |
| 敏感配置明文存放 | 泄漏风险高 | 支持加密与访问控制 |
配置中心让「改一个开关、调一个地址」变成随时可做的事,而不是一次全员发版。
网关与容错:守住入口与稳定性
服务一多,请求入口怎么统一、某个服务挂了会不会拖垮整条链,就成了大问题。网关在入口统一处理路由、鉴权与限流;容错机制则在下游异常时快速失败、有限兜底,防止故障像多米诺骨牌一样蔓延。
# 容错的基本姿态
调用下游,设置超时
失败有限次重试,不无限重试
再失败就走兜底逻辑或快速失败
# 不把一个服务的故障放大成全站雪崩。
微服务的稳定性,很大程度取决于你有没有守住入口和容错这两道防线。
分布式的成本:别只看到拆的爽
拆分带来独立演进的好处,但也把一堆单体时代不存在的问题摆上了台面:网络调用的不确定性、分布式数据一致性、排障链路变长、运维复杂度上升。
- 调用不再是内存里的函数,而是可能失败的网络请求。
- 跨服务的数据一致性,要靠更小心的设计来保障。
- 一次请求串起多个服务,排障和监控都要跟得上。
这些成本不是劝退理由,但必须在拆分之前就看清、有准备,而不是拆完才发现处处是坑。
渐进演进,而不是一步到位
最健康的演进路径,是从单体里最痛、边界最清晰的一块先拆出去,把注册发现、配置中心、网关这些基础设施先跑通,再逐步扩大。而不是一次推翻重来。
- 先拆一个边界清晰、价值明确的核心服务。
- 先把配套的治理设施建起来,再谈拆更多。
- 每拆一块都验证收益,用实际反馈调整节奏。
微服务架构的成熟,从来不是一次设计出来的,而是随着业务与团队一起,一步一步演进出来的。