首页技术专题博客目录关于与联系

为什么我抛弃了微服务,回归单体

两年前信心满满拆分微服务,两年后又合并回单体。讲讲这段经历和反思。

两年前,我们信心满满地把单体应用拆成了微服务。理由很充分:团队在扩张,代码越来越臃肿,部署一次要40分钟,一个小 bug 就得整个系统重启。

现在,我们又把微服务合并回了单体。

当初为什么选微服务

2023年底,公司拿到了B轮融资,团队从12个人扩到50人。CTO 说:"我们需要微服务架构,不然扩展不了。"

技术选型会上,大家讨论得很热烈:

  • 用户服务、订单服务、支付服务、通知服务分开部署
  • 每个服务独立开发、独立上线
  • 服务挂了不影响其他服务
  • 可以根据负载独立扩容

听起来很完美,对吧?

微服务带来的问题

1. 开发效率暴降

以前改个功能,改一个仓库,提交一次代码就完了。现在一个需求要改3个服务,提交3次代码,等3个 CI 流程跑完。

最蛋疼的是联调。本地跑不起来完整环境,必须连测试环境。测试环境又是共享的,你在调支付,别人在调订单,互相干扰。

2. 运维成本爆炸

以前一个应用,现在12个服务。每个服务都要配置:

  • Kubernetes Deployment
  • Service / Ingress
  • ConfigMap / Secret
  • 监控告警规则
  • 日志收集

配置文件比代码还多。

3. 分布式问题全来了

单体应用里,调用一个方法就完了。微服务里,调用一个服务就是一次 HTTP 请求。

  • 网络超时怎么办?
  • 重试多少次?
  • 服务挂了如何降级?
  • 分布式事务怎么保证?

为了解决这些问题,我们引入了 Istio、Saga、分布式链路追踪。技术栈越来越复杂,能完全理解整个系统的人越来越少。

4. 性能反而下降了

单体应用里,一个请求在进程内完成。微服务里,一个请求要经过:

API Gateway → 用户服务 → 订单服务 → 库存服务 → 支付服务

每跳一次,就多一次网络开销、序列化开销。原本20ms的请求,变成了200ms。

回归单体的过程

去年Q4,我们做了个艰难的决定:把微服务合并回单体。

不是一下子合并,而是分阶段:

第一阶段:合并核心服务

用户、订单、库存服务合并成一个应用。这三个服务耦合最紧密,80%的请求都要调用它们。

合并后,接口调用变成了方法调用,性能直接提升3倍。

第二阶段:保留边缘服务

支付服务、通知服务保持独立。这两个服务:

  • 调用频率低
  • 逻辑独立
  • 可能需要独立扩容

这是合理的拆分。

第三阶段:优化单体架构

我们不想重蹈覆辙,所以做了很多改进:

  • 模块化设计:代码按业务域划分,严格控制依赖关系
  • 独立部署:虽然是单体,但可以只部署某个模块
  • 数据库拆分:不同业务用不同的 Schema,物理上还是同一个数据库

现在的状态

回归单体3个月后:

  • 开发效率回来了,一个需求平均开发时间从5天降到2天
  • 运维成本降了60%,Kubernetes 节点从30个降到12个
  • 接口性能提升了3倍,P99延迟从500ms降到150ms
  • Bug 数量明显减少,分布式问题基本消失

我的反思

1. 别过早拆分

微服务是为了解决大规模团队协作的问题。如果团队不到50人,真的不需要。

2. 单体不等于落后

Shopify、GitHub、Basecamp 都在用单体架构,照样服务千万用户。

3. 架构要服务于业务

选架构不是追时髦,而是要看:

  • 团队规模多大?
  • 业务复杂度如何?
  • 有没有独立扩容的需求?

如果答案是"不大"、"不高"、"没有",那单体就够了。

总结

微服务不是银弹,单体也不是洪水猛兽。

我们花了两年时间,绕了一大圈,才明白这个道理。希望你们不用走这个弯路。

如果你的团队在考虑微服务,先问问自己:

  • 单体架构真的撑不住了吗?
  • 团队有没有能力驾驭微服务?
  • 收益是否大于成本?

想清楚了再做决定。


题图来源:我们的系统架构演进图,从单体到微服务再到单体,完美的圆。

评论区