微服务架构设计
你有没有这种感觉:写代码一年,突然发现整个系统像一个巨大的意大利面条——这里改一行,那里就崩了;没人完全理解整个系统是怎么工作的;每次上线都像拆炸弹。
恭喜你,你可能正在经历「单体地狱」。
微服务架构,就是来解决这个问题的。
微服务的定义
微服务没有官方定义,但社区公认的核心特征是:
每个服务围绕业务能力构建,可独立部署、独立扩展。
翻译成人话:一个微服务只做一件事,而且这件事可以独立上线,不需要等其他团队。
比如:
- 用户服务:只管用户注册、登录、资料
- 订单服务:只管订单创建、支付、取消
- 库存服务:只管库存查询、扣减、返还
每个服务有自己的数据库,服务之间通过 API 通信。
微服务 vs 单体:不是「非此即彼」
很多人误解微服务,觉得它是银弹,恨不得第一天就把系统拆成 100 个微服务。
这是一个危险的想法。
微服务解决的是「大型团队的协作问题」,不是「代码组织问题」。
| 场景 | 推荐架构 |
|---|---|
| 小团队(< 10 人)、业务简单 | 单体起步 |
| 中型团队(10-50 人)、业务复杂 | 渐进式拆分 |
| 大型团队(> 50 人)、高并发 | 微服务 + 容器化 |
单体不是原罪。 Twitter、Netflix 早期都是单体,只是后来团队太大了,单体成了瓶颈,才拆的。
微服务拆分维度
拆分的核心原则是业务边界(Bounded Context),这是 Eric Evans 在《领域驱动设计》里提出的概念。
按业务边界拆分
强相关、同步调用的功能,拆到同一个服务。
比如「下单」这个功能,涉及到:
- 用户验证(用户服务)
- 库存扣减(库存服务)
- 支付扣款(支付服务)
- 订单创建(订单服务)
这些应该拆成 4 个服务吗?不一定。
如果「下单」是一个高频操作,需要强一致性,可能把「下单」做成一个服务,内部调用用户、库存、支付的 API 更合理。
按团队所有权拆分
一个服务应该由一个团队完全负责,从开发到部署到运维。
如果一个服务需要两个团队同时修改,那就是拆分失败的信号。
微服务的四大黄金原则
原则一:独立部署
每个服务可以独立部署,不需要协调其他团队。
如果你的「微服务」每次上线还需要通知其他 5 个团队,那它不是微服务,是「分布式巨石」。
原则二:无共享数据
每个服务有自己的数据库,表不共享。
如果服务 A 直接读写服务 B 的数据库表,恭喜你,你把网络调用变成了 SQL 调用,问题更多。
原则三:异构技术
每个服务可以用不同的技术栈。
Python 团队做机器学习服务,Java 团队做交易系统,Go 团队做高并发网关——这是微服务的优势。
但前提是:技术选型要服务于业务,而不是为了炫技。
原则四:故障隔离
一个服务挂了,不能导致整个系统崩溃。
常见的故障隔离手段:
- 舱壁模式:不同服务用不同的连接池
- 熔断器:服务不可用时快速失败,不无限重试
- 限流:保护服务不被突发流量冲垮
微服务的技术栈全景图
构建微服务需要很多组件:
┌─────────────────────────────────────────────────────────┐
│ 微服务架构 │
├─────────────────────────────────────────────────────────┤
│ 服务框架:Spring Cloud / Dubbo / gRPC │
│ 通信协议:HTTP REST / gRPC / Dubbo RPC │
│ 服务注册:Nacos / Eureka / Consul │
│ 配置中心:Apollo / Nacos Config / Spring Config │
│ 网关层:Spring Cloud Gateway / Kong / Zuul │
│ 认证鉴权:JWT / OAuth2 / Spring Security │
│ 分布式事务:Seata / TX-LCN / Saga │
│ 链路追踪:SkyWalking / Zipkin / Jaeger │
│ 日志聚合:ELK / Loki / EFK │
│ 容器化:Docker + Kubernetes │
└─────────────────────────────────────────────────────────┘每个组件都有其适用场景,后面会专门讲。
微服务陷阱
微服务不是银弹,它带来了新的问题:
陷阱一:过度拆分
把一个简单的 CRUD 应用拆成 20 个微服务,每个服务就 3 张表、5 个接口。
结果:20 个服务 = 20 个数据库 = 20 套配置 = 20 套监控 = 20 倍的运维复杂度。
建议:当一个服务的代码量超过 10 万行,或者团队超过 5 个人专门维护时,再考虑拆分。
陷阱二:分布式复杂性爆炸
单体里一个函数调用解决的问题,微服务里可能涉及:
- 网络调用
- 序列化/反序列化
- 服务发现
- 负载均衡
- 熔断降级
- 分布式事务
这不是换一套框架能解决的,是架构层面的复杂度转移。
陷阱三:数据一致性
单体里一个数据库事务解决的问题,微服务里需要分布式事务或最终一致性。
这是一道鸿沟,没有完美的解决方案,只有业务层面的 trade-off。
什么时候不该用微服务
微服务是有成本的,以下场景建议先不要用:
- 小团队:运维成本可能超过收益
- 业务简单:不需要高扩展、高可用
- 创业初期:快速验证业务比架构重要
- 强一致性场景:微服务天然是最终一致,强一致需要额外的工程成本
面试追问方向
微服务和 SOA 有什么区别?
SOA 有 ESB 总线,所有服务通过 ESB 通信;微服务去中心化,服务之间直接通信。SOA 是粗粒度,微服务是细粒度。
微服务如何保证数据一致性?
这是一个开放性问题,没有标准答案:
- 强一致:分布式事务(2PC/TCC/Saga)
- 最终一致:消息队列 + 补偿机制
- 业务层处理:乐观锁 + 重试 + 对账
服务拆分后,接口版本怎么管理?
- URL 路径:
/api/v1/users - Header:
API-Version: 1.0 - 蓝绿部署:新旧版本并行,流量切换
留给你的问题
微服务解决了「大型团队的协作问题」,但引入了「分布式系统的复杂度问题」。
你有没有遇到过这种情况:一个功能,单体里 1 小时搞定,微服务里需要 1 周(分布式事务 + 服务间联调 + 链路追踪 + ...)?
如果是你,会怎么权衡?
