从单体到云原生:我的后端架构演进实战分享
我第一次面对系统性能瓶颈是在三年前,我们团队维护的电商后台服务逐渐从一个小而全的单体应用,变得越来越臃肿、难以维护。每天凌晨一点,用户量飙升带来的压力让服务器频繁报警,每次发布都要小心翼翼地祈祷:“别出错”。那段时间,我几乎每天晚上都在日志里打转,排查接口超时、数据库锁、内存泄露等问题。
这种“小作坊”式的开发方式在项目早期还勉强可以应付,但随着业务规模的扩大,问题就像滚雪球一样越滚越大。
今天我想和大家分享的,就是我自己参与过的、一次真实的后端架构演进过程:从最初的单体架构,逐步过渡到微服务、再迈向云原生架构的全过程。
背景:那个让人头疼的“万能单体”

项目的初始架构非常简单——一个 Spring Boot 应用承载了订单、库存、支付、用户中心等几乎所有模块。前端调用几个 API 接口就能跑通整个流程,开发效率确实高。最初几个月也没出过什么大问题,直到有一天运营说要做活动,我才知道这个系统连压测都没做过。
上线活动当天,系统直接崩溃,用户请求全部失败,客服电话被打爆。那一晚我和两个同事通宵修 bug,终于把数据库连接池从 20 改到了 100(你没看错)。虽然治标不治本,但也算缓了一口气。
那次事故后,我下定决心重构整个系统架构。
挑战:单体架构的痛,不止是性能问题

1. 部署耦合度高
每次上线一个新功能,必须整个系统重新打包部署。哪怕只是改了一个文案,也得重启所有模块,影响正常运行。
2. 技术栈僵化
因为历史原因,系统用了 MyBatis + MySQL,后来想引入 Redis 缓存层,结果发现很多逻辑已经写死在 DAO 层,强行加缓存反而让代码更复杂。
3. 性能瓶颈明显
高峰期,数据库 CPU 使用率常年保持在 90% 以上。有些慢查询甚至会导致线程池阻塞,引发级联故障。
4. 团队协作困难
随着业务增长,多个团队开始介入。大家修改同一份代码库,合并冲突频繁,代码评审走个形式,谁也不敢随便动核心逻辑。
最严重的时候,我们曾经为了一个功能改动,在测试环境调试了整整一周还没解决依赖问题。
分阶段架构升级:走向云原生之路

整个演进过程我们大致经历了以下几个阶段:
第一阶段:模块拆分 + 单体重构
我们首先把原本的 monorepo 项目按照业务逻辑拆分成若干模块,例如:
- user-center
- order-service
- payment-center
- inventory-service
这些模块一开始还在同一个进程中运行(使用 Spring Boot 多 Module 管理),但职责已经明确划分。我们做了以下事情:
- 接口抽象与协议统一:定义基于 RESTful 的通信规范,统一参数格式、错误码。
- 共享服务抽象:如配置中心、公共工具类、日志处理等都独立成 module。
- 数据隔离尝试:每个模块独立管理自己的数据库表,避免跨库关联。
这时候我们还没有正式上微服务,但代码结构清晰了不少,至少出了问题知道该找哪个模块负责。
第二阶段:引入微服务架构
接下来我们开始使用 Spring Cloud 和 Dubbo 做远程调用,把各个模块拆成独立的服务。
实际上我们当时先用的是 Dubbo,后来觉得 Spring Cloud 更符合公司技术栈,又做了一次迁移 😅
我们引入了 Eureka 做服务注册发现、Ribbon 做负载均衡、Feign 做客户端调用,并为每个服务独立部署 Tomcat 实例。
举个接口设计的例子:
比如订单服务的创建接口,我们要考虑幂等性、异步回调、失败重试机制。
public interface OrderService {
Order createOrder(CreateOrderRequest request);
}
我们在实现中加入了 RocketMQ 发送消息队列通知库存服务扣减库存,这样即使其中一个环节失败,也可以通过事务补偿或人工对账来处理。
第三阶段:全面容器化 + 云原生改造
当我们的服务越来越多,运维也开始吃力。这时我们开始拥抱 Kubernetes,并结合 Jenkins 做 CI/CD 自动化部署。
我们做的主要工作包括:
- 将每个服务构建为 Docker 镜像,标准化部署环境;
- 使用 ConfigMap 和 Secret 管理不同环境的配置文件;
- 引入 Istio 做服务治理,实现灰度发布、熔断限流;
- 采用 Prometheus + Grafana 监控服务健康状况;
- 使用 ELK 收集日志分析异常情况。
这个时候,我们的部署流程变成这样:
git commit -am 'fix: order creation failed'
git push origin develop
Jenkins Pipeline 启动 -> Build & Push Docker Image -> Helm Chart Upgrade on K8s Cluster
是不是感觉优雅多了?当然这背后也踩了不少坑,后面我会专门讲几个关键的问题。
踩坑经验:那些深夜让我睡不着的 BUG

1. 数据库死锁问题
在服务拆分初期,我们没有做好分布式事务管理,导致订单下单和库存减少操作经常出现数据不一致。
我们当时的解决方案是引入 TCC 事务模式(Try-Confirm-Cancel),并在关键流程中增加事务 ID 日志追踪。此外,通过定时任务每日对账补偿。
2. 微服务调用链路混乱
服务之间互相调用,一个错误日志可能分散在多个服务的日志里。我们最终引入了 Jaeger 做分布式追踪,给每个请求加上 TraceID,并在网关层统一注入上下文。
3. 容器资源限制不合理
最开始我们没设置合理的 resource limits,导致某些服务占用大量内存,影响其他服务运行。最后通过 Prometheus 监控各 pod 内存、CPU 使用率,调整了每个容器的资源配置:
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "100m"
成果与收获:从“救火队员”到“架构师”
这次架构重构不仅解决了稳定性问题,也带来了实实在在的收益:
| 评估维度 | 改造前 | 改造后 |
|---|---|---|
| 部署速度 | 半小时左右 | 几分钟内完成 |
| 系统响应时间 | 平均 800ms | 平均 200ms |
| 新功能上线周期 | 1~2周 | 最快一天交付 |
| 故障定位时间 | 数小时 | 十几分钟 |
| 扩容灵活性 | 人工扩容 | 自动扩缩容 |
更重要的是,团队协同效率提升显著。每个服务都有明确的 Owner,我们可以按需优化某个模块,而不必担心牵一发而动全身。
给正在转型中的开发者的一些建议
如果你也打算做类似的架构升级,我有几点建议:
1. 不要盲目追求“时髦技术”,从实际出发
当初我们也想过一步到位上 Serverless,后来发现不是每个场景都适合。你可以先用单体+模块化做起,慢慢拆解。
2. 架构演进是个长期过程,要有耐心
我们花了将近一年才稳定下来,中间还经历了多次回滚、重构。不要指望几个月就把一切搞定,关键是持续迭代和改进。
3. 技术债要及时偿还,否则代价更大
早年间为了赶工期快速实现的功能,后期往往要付出几倍的成本去修复。特别是数据库设计,一旦表结构不合理,后续很难重构。
4. 运维和监控体系必须跟上架构的步伐
微服务之后,光靠人盯着是不行的。建立完善的日志收集、监控告警、自动化部署机制,才能真正释放生产力。
5. 文档和接口管理至关重要
我们后来用 Swagger 做接口文档,结合 Apigateway 做权限控制和流量统计。接口设计不规范,会严重影响开发效率和系统稳定性。
写在最后:技术没有银弹,只有不断进化
回首这段旅程,我最大的感悟是:优秀的架构不是一开始就设计出来的,而是在一次次实践中打磨出来的。
从一开始面对单体架构的无力,到现在可以在 Kubernetes 上自由部署服务,每一次踩坑都是一次成长。希望这篇文章能对你有所启发,也欢迎你在评论区交流你的经验和疑问。
毕竟,作为程序员,最重要的不是你会多少技术,而是你能多快地学习和适应新的变化。
共勉之 🚀

评论 0