后端架构演进:从单体到云原生
引言:为什么我要写这篇技术分享?

我在后端开发领域干了五年,亲历过从传统单体应用一路折腾到云原生架构的全过程。说实话,这中间踩过的坑、熬过的夜、调试过的代码、和运维杠过的锅,足够出一本书。
今天想结合自己参与的几个重要项目,聊聊这些年我经历过的后端架构演进过程:从单体架构 → 模块化拆分 → 微服务化 → 云原生改造。这是一条充满挑战的技术升级之路,但每一步都让我对架构设计有了更深的理解。
希望这篇文章能给你带来一些实用的参考,也顺便回忆一下那些熬夜改代码的往事。
背景介绍:我们的起点是个“四不像”

2019年的时候,我在一家中型电商平台做后端开发。当时的项目结构很典型:Spring Boot + MyBatis 构建的一个单体后端服务,运行在两台物理服务器上,数据库是MySQL主从读写分离,前端用Vue,接口通过Nginx转发。
项目背景听起来还行,但实际跑起来问题不少:
- 应用越来越臃肿,动不动就是几千个类文件
- 发布频率低,每次上线都要停机一两个小时
- 高并发时经常扛不住,稍微一促销,服务就挂
- 不同模块之间耦合严重,比如订单模块频繁改动商品库存逻辑
- 开发协作困难,一个需求可能牵扯三四个人,沟通成本极高
我们那时候最头痛的就是“改一个小功能要改十个地方”。更头疼的是,一旦出现生产故障,排查半天发现其实是某个看似无关的功能引发的问题。
那个时候我就意识到:系统不能再这样下去了,必须重构。
第一次转型:模块化拆分

挑战描述
随着业务增长,系统的瓶颈逐渐暴露出来。尤其是在大促期间,整个服务经常出现超时甚至崩溃的情况。而且新业务需求越来越多,不同团队之间的开发节奏无法协调。
我们当时最大的问题是单一代码库+高耦合模块=维护地狱。
解决思路
为了解决这个问题,我们决定先尝试进行模块化拆分。目标是:
- 将核心业务模块解耦(用户、商品、订单、支付)
- 每个模块独立打包、独立部署
- 保持共用的底层服务(如日志、缓存、工具类)共享
当时我们用的是 Spring Boot,所以模块划分主要围绕 Maven 的 module 结构来展开:
├── backend/
│ ├── user-service/
│ ├── product-service/
│ ├── order-service/
│ ├── common-utils/
│ └── pom.xml
每个 service module 对应一个子项目,common-utils 是公共依赖。虽然本质上还是跑在一个 JVM 里,但模块化的结构让代码变得清晰了不少。
接口调用方面,我们用了本地方法调用,也就是模块之间直接 import 包,没有引入远程通信。
收益与反思
这一阶段的收益主要是:
- 代码结构变清晰了,团队合作效率提升
- 部署依旧是一个 jar 文件,但内部职责划分明确
- 日常开发更可控,不至于动不动就牵一发动全身
但也存在明显的局限性:
- 并发压力依然集中在一台服务上
- 某个模块出了问题,整体服务还是会受影响
- 扩展性依旧不够,无法动态伸缩资源
这时候我开始意识到:模块化只是第一步,真正的挑战还在后面。
第二次架构迭代:迈入微服务时代

新问题的出现
随着业务量的增长,尤其是双十一和年终促销的到来,系统再次暴露了严重的性能问题。特别是在订单高峰期,整个服务频频出现 timeout 和 Connection Refused,用户投诉不断。
我们发现:
- 单实例处理能力到了瓶颈,扩容受限
- 订单服务和库存服务频繁争抢资源,导致响应延迟陡增
- 数据库连接池打满,慢查询频发
显然,光靠模块化已经不够用了。
微服务化改造
于是我们在 2020 年启动了微服务改造计划。这次选型采用 Spring Cloud Alibaba + Dubbo 作为服务框架。
技术方案简述:
- 拆分为多个独立服务(user, product, order, inventory, payment等)
- 使用 Nacos 做注册中心和服务发现
- 服务间通信采用 Dubbo RPC
- 网关统一接入,使用 Spring Cloud Gateway
- 统一日志管理、链路追踪(SkyWalking)、配置中心(Nacos)
- 数据库按业务垂直拆分,引入分库分表策略(ShardingSphere)
服务拆分逻辑示例:
// 用户服务接口定义
@DubboService
public class UserServiceImpl implements UserService {
// ...
}
// 订单服务调用用户服务
@Reference
private UserService userService;
数据库拆分:
| 原单库 | 拆分后 |
|---|---|
| mysql_single_db | mysql_user_db / mysql_product_db / mysql_order_db |
这种结构虽然复杂了一些,但在应对业务增长时确实有效缓解了压力。
实施过程中遇到的挑战
数据一致性难题
原来事务控制在同一个数据库中就可以搞定,现在服务分散,跨服务的数据操作变得复杂。我们引入了 TCC 模式来实现最终一致性。服务雪崩问题
有一次因为支付服务出错,导致所有调用方都被阻塞,整个系统连锁崩溃。我们后来加上了熔断降级机制(Sentinel),并在网关层做了限流。配置管理混乱
初期每个服务都有自己的 application.yml,非常难维护。后来我们统一迁移到 Nacos 配置中心,实现集中管理和动态刷新。
成果与体会
这次改造后,系统稳定性显著提升,QPS 提升了近3倍,线上故障频率降低了70%以上。虽然初期投入比较大,但从长远来看是值得的。
这个时候我也算是真正理解了那句话:“微服务不是银弹,但它是解决复杂业务的有效方式。”
第三次飞跃:拥抱云原生
又一次瓶颈到来
到了2021年底,随着业务进一步扩张,我们的基础设施又面临新问题:
- 服务器数量越来越多,人工运维压力巨大
- 环境不一致导致上线经常“在我机器上能跑”
- 自动化程度低,CI/CD 流程卡顿严重
- 成本越来越高,服务器闲置浪费严重
特别是有一次搞秒杀活动,预估流量暴涨,手动扩了十几台 ECS,结果活动结束后又得慢慢缩容,非常麻烦。
上云 & 容器化改造
我们决定全面向云原生转型,目标包括:
- 基于 Kubernetes 构建容器编排平台
- 所有服务 Docker 化打包部署
- 建立完整的 CI/CD 流水线(Jenkins + Harbor)
- 日志统一(ELK)、监控告警(Prometheus + Grafana)
- 服务网格初步探索(Istio)
Docker 镜像构建样例:
FROM openjdk:8u292-jdk-alpine
COPY *.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Kubernetes 配置片段:
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: harbor.example.com/backend/user-service:latest
ports:
- containerPort: 8080
CI/CD流水线流程图:

Git Push → Jenkins Build → Docker Build → Push to Harbor → Kubernetes Apply
整个流程自动化后,上线时间从原来的一小时缩短到5分钟以内,且版本回滚也非常简单。
遇到的实际问题及解决方案
环境差异问题
之前经常出现测试环境没问题,生产环境各种报错。后来我们强制要求所有服务统一基镜像,并标准化运行时参数。Pod 启动失败
有的微服务刚启动就因为依赖服务还没就绪而失败,导致重启次数过多。后来我们加上健康检查探针:livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10服务发现失败
在迁移到 K8s 的 Service Mesh 架构时,出现了部分服务注册不到 Nacos 的情况。排查后发现是网络策略配置问题,K8s 内部服务访问不通。我们调整了网络插件(Calico)的规则后恢复正常。
收益总结
这次云原生改造让我们彻底摆脱了过去靠人肉运维的日子。弹性伸缩、自动发布、统一监控这些能力让我们在后续的大促活动中从容了很多。
同时,成本方面也有明显改善——不再需要常年保留大量空闲资源,而是按需拉起 Pod,节省了将近30%的预算。
经验总结:技术演进中的心得体会

这几年下来,我总结了几点非常关键的心得,想送给正在做架构决策的朋友:
1. 别怕从简单的做起
很多同学一上来就想上微服务、上K8s,结果把自己绕进去。其实应该根据业务规模逐步演进,先把代码结构理清楚,再谈拆分,最后再考虑容器化和编排。
2. 不要盲目追求新技术
我见过太多团队为了“炫技”硬上 Istio、Service Mesh,结果连基础的日志都没收集好。任何架构都是为了解决现有问题,而不是制造新的麻烦。
3. 重视基础设施建设
技术选型不能只看编码爽不爽,还得考虑运维是否跟得上。比如你上了微服务,如果没监控、没日志聚合、没有链路追踪,那你就是在给自己挖坑。
4. 文档、规范、Code Review一样都不能少
越是复杂系统,越要注重规范化管理。否则新人接手会很痛苦,问题定位也会变成灾难。
5. 灰度发布和回滚机制很重要
上线不一定都能成功,一定要留好退路。比如我们可以先放一部分流量到新版本,确认无误后再全量推上线。
展望未来:云原生之后的方向
现在我们已经在云原生的基础上运行稳定了一段时间。下一步我们计划尝试:
- 探索 Serverless 架构,将部分非实时任务搬上去降低成本
- 引入 APM 工具精细化分析接口耗时瓶颈
- 用 Kafka 解耦异步任务,提升系统的可扩展性
- 推动 DevOps 文化,让开发和运维更加一体化
也许几年后我会再来写一篇《后端架构演进2:从云原生走向AI原生》,谁知道呢?但可以肯定的是,这条技术成长之路远未结束。
最后的话
回顾这些年走过的路,有时候真的挺感慨的。从最初一个人吭哧吭哧敲代码,到现在带着团队一起做架构设计,技术的变化之快令人应接不暇。
但我始终相信一句话:“好的架构不是设计出来的,是在一次次问题中打磨出来的。”
希望我的这段经历对你有所启发,也能帮你避免一些不必要的弯路。技术这条路不容易,但只要坚持走下去,总会看到曙光。
如果你们也在经历类似的架构演变过程,欢迎留言交流,我们一起成长!
(全文约 3282 字)

评论 0