从单体到云原生:一个后端工程师的成长之旅
引言

作为一名有五年工作经验的后端工程师,我经历过不少技术演进的过程。记得五年前刚加入第一家公司时,项目还是典型的单体架构,所有代码都在一个工程里,部署在一台物理服务器上。那时的我们,对“服务拆分”、“微服务”这些词都停留在理论层面。直到公司业务增长、用户量激增,系统的瓶颈才一步步显现。
这篇文章想通过我参与的一个真实项目,分享一下我这几年亲历的系统从单体架构 → 微服务架构 → 云原生架构的整体演进过程,以及我在其中踩过的坑和收获的经验。希望对正在面临或准备转型的你有所帮助。
背景介绍:老项目的烦恼

项目是做电商平台的后台系统,最初是一个 Spring Boot 单体应用,包含了商品管理、订单处理、支付结算、用户中心等模块。一开始只有十几万用户,性能问题并不明显。但随着营销活动频繁上线,用户暴涨到百万级别,系统逐渐暴露出以下问题:
- 部署困难:一次发布需要重启整个应用,导致所有模块停摆;
- 性能瓶颈:某个模块(比如商品详情)并发高,拖累其他模块;
- 扩展性差:无法针对某个功能快速扩容;
- 维护复杂:多人协作开发冲突频发,代码臃肿难读。
当时我们团队尝试过纵向拆分,将商品和订单做成两个 WAR 包部署在同一台 Tomcat 上,但本质上仍属于“伪微服务”,没有解决核心问题。
那时候我就意识到,真正的架构演进不是靠口号喊出来的,而是被需求倒逼出来的。
架构演进第一步:向微服务迈出试探的脚步

技术选型与目标
我们决定使用 Spring Cloud Alibaba + Nacos + Feign + Sentinel + Gateway 来搭建一套微服务架构。初期目标:
- 拆分商品、订单、用户、支付为独立服务;
- 支持服务注册发现与负载均衡;
- 接入服务熔断机制提升容错能力;
- 使用网关统一处理鉴权、路由逻辑。
实施细节
1. 服务拆分
我们按照业务领域划分了四个基础服务,并各自作为一个 Spring Boot 项目:
- product-service
- order-service
- user-service
- payment-service
每个服务之间通过 OpenFeign 进行远程调用,Nacos 做服务注册中心。
// 示例:order-service 调用 product-service 获取商品信息
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/products/{id}")
Product getProductById(@PathVariable("id") Long id);
}
2. 网关集成
使用 Spring Cloud Gateway 搭建统一网关,负责请求转发和权限控制:
spring:
cloud:
gateway:
routes:
- id: product
uri: lb://product-service
predicates:
- Path=/api/product/**
filters:
- StripPrefix=1
3. 服务治理初探
引入 Sentinel 对接口进行限流降级,防止雪崩效应。例如,我们在商品查询接口上加了 QPS 控制:
@GetMapping("/products/{id}")
@SentinelResource(value = "getProduct", blockHandler = "handleBlock")
public Product getProduct(@PathVariable Long id) {
return productService.getProduct(id);
}
public Product handleBlock(Long id, BlockException ex) {
return new Product().setName("当前访问人数过多,请稍后再试");
}
踩的坑
- Feign 调用超时:默认超时时间太短,需要手动配置 Ribbon 的 timeout 参数;
- Nacos 启动慢导致服务注册失败:调整启动顺序或者引入健康检查;
- 服务依赖混乱:多个服务之间存在循环调用,后来通过事件驱动方式解耦(如 RabbitMQ);
- 事务一致性问题:跨服务更新状态时容易出错,后续引入了分布式事务框架 Seata 来处理关键路径。
第二阶段:拥抱容器化和 DevOps 自动化
随着微服务数量增加,运维压力陡然上升。每次部署都要登录到服务器,手动执行脚本,效率低还容易出错。于是我们开始引入 Docker + Kubernetes + Jenkins 的组合,开启容器化之路。
Docker 化改造
为每个服务编写 Dockerfile,构建镜像并推送到私有仓库:
FROM openjdk:8-jdk-alpine
COPY *.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
Jenkins Pipeline 实现自动打包推送:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Docker Build and Push') {
steps {
sh 'docker build -t harbor.example.com/project/order-service:latest .'
sh 'docker push harbor.example.com/project/order-service:latest'
}
}
}
}
Kubernetes 编排部署
Kubernetes 的 YAML 文件大致如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: harbor.example.com/project/order-service:latest
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- protocol: TCP
port: 8080
targetPort: 8080
同时我们将 MySQL、Redis、RabbitMQ 等中间件也容器化部署,并使用 Helm 进行版本管理。
成果与挑战
- 部署效率大幅提升:从小时级缩短到分钟级;
- 环境一致性更好:本地、测试、生产环境一致性强;
- 资源利用率更高:可以动态调度 Pod,避免资源浪费;
但也有一些新问题:
- 日志收集变得复杂:引入 ELK Stack 统一收集;
- 服务间通信延迟变高:优化网络策略和服务粒度;
- K8s 学习曲线陡峭:安排专项培训,逐步掌握核心概念。
第三阶段:走向真正的云原生
当我们的服务全部运行在 Kubernetes 上之后,下一步自然就是深入利用云原生的优势:弹性伸缩、自动恢复、监控告警、服务网格等。
引入 Prometheus + Grafana 监控体系
Prometheus 定期采集各服务的 /actuator/metrics 数据,Grafana 展示各种指标:
- JVM 内存 & GC 情况
- HTTP 请求成功率/延时
- DB 连接数/慢 SQL 数量
- Redis 缓存命中率等
这为我们排查线上问题提供了极大帮助。
弹性伸缩实践
通过 HPA(HorizontalPodAutoscaler)设置根据 CPU 使用率自动扩缩容:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
这样在促销高峰期,系统能自动扩容应对流量洪峰,节省成本的同时保障用户体验。
引入 Service Mesh 提升可观测性
我们最终采用了 Istio,将服务治理从代码中抽象出来,实现了:
- 零信任安全模型
- 分布式追踪(Jaeger)
- 流量管理(金丝雀发布、AB 测试)
- 更细粒度的熔断和重试规则
比如我们可以对订单服务设置如下虚拟服务:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: order-vs
spec:
hosts:
- order-service
http:
- route:
- destination:
host: order-service
subset: stable
weight: 90
- route:
- destination:
host: order-service
subset: canary
weight: 10
这样就能实现平滑的灰度上线流程。
效果总结与经验沉淀
经过三年多的努力,这个平台已经稳定运行在公有云上,支撑着每天千万级 PV 和上亿订单量。回顾这次旅程,我想分享几点心得体会:
收获与成果
- 稳定性大幅提高:通过 Kubernetes 和 Istio 实现自动恢复;
- 研发效率提升:CI/CD 全自动化部署;
- 成本显著降低:按需扩缩容 + 云厂商弹性计算;
- 运维更轻松:日志、监控、告警一站式管理;
- 可拓展性强:新业务可快速接入已有基础设施。
我的几个建议
- 不要为了拆分而拆分:微服务不是银弹,前期评估好是否真的需要拆;
- 先做好基础设施建设:日志、监控、配置中心一定要同步跟上;
- 选择适合团队的技术栈:不要盲目追新,适合自己最重要;
- 注重文档和交接机制:否则你会在某一天被自己写的服务困扰;
- 多动手少空谈:很多问题是只有真正落地之后才会暴露出来的。
结语
从最初的单体架构一路走到今天的云原生架构,这条路看似光鲜亮丽,其实每一步都走得不容易。每一次技术升级的背后,都是无数次踩坑、重构、争论和学习。
作为后端工程师,我们要做的不仅是写出漂亮的代码,更是要站在更高的角度去思考如何让系统更健壮、更高效、更容易维护。架构的演变,其实是对我们综合能力的考验。
如果你现在正处在一个小团队、小项目中,也不要觉得微服务离你很遥远。不妨从一个小模块做起,试试用 Docker 封装一下你的服务,试着用 Grafana 监控一下你的接口性能。
技术的成长,从来都不是一蹴而就的,它藏在每一个真实的项目里,也在每一个深夜加班调试的 bug 中。
愿你在自己的技术道路上,越走越远。
文章作者:张远
GitHub:zhangyuan
微信公众号:后端修炼之道

评论 0