架构 · 演进
从单体到微服务:一次完整的架构演进实战
很多团队拆微服务是"为了拆而拆",结果服务没解耦,反而多了分布式事务、链路追踪、运维复杂度三座大山。 本文记录一次真实的架构演进:从单体积压到按业务域拆分,重点讲清楚 什么时候该拆、怎么拆、拆完怎么稳——而不是一堆正确的废话。
1先判断:你真的需要微服务吗?
微服务不是银弹。在动手前,先用下面这条清单自检:
- 团队规模:少于 5 人、单仓库能跑,单体往往更划算;
- 发布频率:所有模块被迫一起发布、互相阻塞,是拆分的强信号;
- 故障边界:一个模块 OOM 拖垮整个应用,需要物理隔离;
- 技术异构:不同模块对语言/存储有不同诉求。
⚠️ 如果只是为了"显得先进"而拆,你会收获一个"分布式单体":服务是分开的,但所有调用强耦合、一个接口要串 8 个服务,比单体还难维护。
2服务如何划分:按业务域,而非按技术层
最常见的错误是按技术分层拆(UserController 服务、OrderController 服务),这只会制造大量跨服务调用。正确姿势是领域驱动设计(DDD)的限界上下文。
| 划分方式 | 例子 | 问题 |
|---|---|---|
| 按技术层(❌) | user-api / user-service / user-dao | 一次请求跨 3 个服务,强耦合 |
| 按业务域(✅) | user / order / payment / inventory | 高内聚,域间只通过接口通信 |
划分原则:
- 单一职责:一个服务只对一个业务概念负责;
- 数据库私有:每个服务独占自己的库,禁止跨服务直连对方表;
- 明确接口:服务间只通过 API / 消息契约通信,契约先行。
3网关:统一入口与横切关注点
拆完之后,客户端不该直接面对 N 个服务。引入API 网关作为唯一入口,集中处理鉴权、限流、日志、路由:
# 网关路由示例(伪配置) routes: - id: user-service uri: lb://user-service predicates: - Path=/api/user/** filters: - StripPrefix=1 - name: RequestRateLimiter # 限流 - id: order-service uri: lb://order-service predicates: - Path=/api/order/**
💡 网关只做"薄"的横切逻辑。业务判断(如"该用户能否下单")必须留在对应服务内,否则网关会慢慢变成第二个单体。
4熔断、降级、限流:分布式系统的三道防线
服务一多,局部故障会被放大成雪崩。必须给每个下游调用上保护:
// 用 Sentinel 给下游调用加熔断(伪代码) try (Entry entry = SphU.entry("orderService.query")) { return orderClient.query(id); } catch (BlockException e) { return fallbackOrder(); // 降级:返回缓存/默认值 }
- 熔断(Circuit Breaker):下游错误率超阈值,直接"跳闸",Fast-Fail 而非堆积;
- 降级(Fallback):依赖不可用时返回兜底数据,保住主流程可用;
- 限流(Rate Limit):保护自身不被突发流量冲垮,常见算法令牌桶/漏桶。
5数据拆分:最难的一公里
最难的是共享数据库。单体时期一张表大家共用,拆分时要把数据"连根拔起":
- 垂直分库:每个服务独立库,先切断直连;
- 双写迁移:新旧库同时写,校验一致后切换读流量;
- 跨域查询:用API 组合或数据冗余(CQRS 读模型)替代 JOIN。
⚠️ 跨服务事务是深坑。能避则避:优先用最终一致性 + 消息队列,而非强一致分布式事务(详见本博客《分布式事务终极指南》)。
6可观测性:看不见就管不了
单体靠看日志就能排错,微服务必须上"三件套":
- 日志聚合(ELK / Loki):跨服务检索;
- 指标监控(Prometheus + Grafana):QPS、延迟、错误率;
- 链路追踪(Jaeger / SkyWalking):一次请求串起所有服务。
// 一次请求应带统一 traceId,贯穿所有服务 traceId: "a1b2c3d4-..." // 网关生成 → 透传给每个下游
7演进小结
- 微服务是组织问题先于技术问题:团队边界决定服务边界;
- 按业务域而非技术层划分,数据库私有;
- 网关收口横切逻辑,熔断降级限流是标配;
- 数据拆分走双写迁移,跨域用最终一致性;
- 没有可观测性,不要上微服务。
架构演进没有"标准答案",只有"当时当下最合适的取舍"。先让单体跑顺,再在真实痛点出现时有的放矢地拆—— 这才是稳健的演进,而不是一场昂贵的重构豪赌。
© 2026 JokerChou's Blog · 用 ❤️ 与 ☕ 制作 · 返回博客首页