后端架构演进:从单体到云原生的实践与思考

云原生笔记本
2025-06-28 12:33
阅读 1397

背景介绍

背景介绍

我是一名有着五年后端开发经验的工程师,早期主要参与企业内部系统的开发,后来逐渐接触到高并发、分布式系统的设计。一路走来,见证了一个典型的项目从单体架构逐步演进为微服务再到云原生架构的过程。

今天我想通过一个真实的项目案例,聊聊我在架构演进过程中的一些经历、踩过的坑以及最终获得的收益。这不仅仅是一次技术升级,更是一次思维方式和团队协作模式的转型。


项目背景

项目背景

大概三年前,我加入了一个电商平台重构小组,目标是将一个已经运行五年的老电商系统进行重构。当时的系统是一个传统的Spring Boot单体应用,数据库用的是MySQL,接口全部暴露在同一个工程中,部署方式是物理服务器+Tomcat。

系统初期设计还算是规范,但随着业务迭代加快,代码变得越来越臃肿,每次上线都提心吊胆。更严重的是:

  • 接口响应变慢,尤其在促销活动期间经常出现超时;
  • 部署效率低,全量发布一次要花半小时;
  • 新人上手困难,因为模块之间的依赖关系复杂;
  • 功能修改常常牵一发而动全身。

我们意识到:再不重构,系统迟早会出大问题。


问题描述

问题描述

第一个挑战就是性能瓶颈。高峰期系统QPS超过2000,但单体应用扛不住这么高的并发请求,经常触发OOM异常,甚至出现数据库连接池被占满的问题。

其次是开发效率低。我们是一个8人小团队,但在需求高峰期,光是合并冲突就够折腾半天。不同模块之间调用混乱,没有统一的接口协议,导致很多Bug定位起来非常困难。

还有一个比较隐蔽的问题是可维护性差。比如某个支付模块有bug,我们需要把整个系统停掉才能修复并重新部署,这种“牵一发动全身”的架构让运维也非常头疼。


技术方案演进

服务器部署方案-1

第一阶段:微服务拆分(2021)

我们决定采用Spring Cloud Alibaba + Dubbo的技术栈来实现微服务化。首先根据业务域划分服务,比如用户中心、订单中心、库存中心、支付中心等,每个服务独立部署,使用Nacos做服务注册与发现。

这里有几个关键点:

  1. 接口设计采用OpenAPI + Swagger UI,统一分层结构,避免重复造轮子。
  2. 引入Feign做服务间通信,配合Ribbon做负载均衡。
  3. 数据一致性处理,对于跨服务操作,采用最终一致性的设计思路,比如通过MQ异步通知、状态机驱动流程等方式保证可靠性。

拆分完成后,部署效率明显提升,故障隔离也做得更好了。比如库存服务出了问题,不会影响用户的登录逻辑。

但我们很快遇到了新的问题:服务拆得太细,带来了大量的运维成本。每个服务都要单独打包部署,资源浪费也比较严重。

第二阶段:容器化与Kubernetes部署(2022)

为了进一步优化资源利用率,我们将所有微服务迁移到Docker环境,并搭建了基于Kubernetes的编排平台。

这一阶段的重点工作包括:

  • 将所有Java服务打成Docker镜像;
  • 使用Helm Chart统一部署配置;
  • 引入Prometheus + Grafana做监控告警;
  • 搭建CI/CD流水线,自动化测试、构建和部署。

这时候我们在阿里云上申请了一个EKS集群(虽然现在叫ACK),通过Ingress做网关路由,同时结合Service Mesh做流量治理,提升了整体可观测性和稳定性。

这个过程中的最大收获是:基础设施即代码(Infrastructure as Code) 的理念真正落地到了我们的日常开发中。

第三阶段:拥抱云原生(2023 - 至今)

到了2023年,公司开始推动全面云原生化改造。我们在这个基础上做了几个重要的优化:

  • 使用Serverless函数处理异步任务,比如发送短信、生成报表;
  • 将部分状态数据迁移至Redis + Elasticsearch,解决高频读取性能问题;
  • 引入消息队列解耦核心链路,降低系统间的强依赖;
  • 使用OpenTelemetry进行全链路追踪,方便快速定位故障。

此外,我们还将一些通用能力下沉到中间件层面,比如日志采集、权限控制、限流熔断策略等,形成了一套统一的平台级能力支撑多个业务线的架构体系。


代码实践示例

以下是我们当时在服务拆分中做的一段Feign远程调用的代码片段,大家可以参考一下基本结构。

@FeignClient(name = "order-service", path = "/api/orders")
public interface OrderFeignClient {

    @GetMapping("/{orderId}")
    ApiResponse<OrderDTO> getOrderById(@PathVariable("orderId") String orderId);

    @PostMapping("/create")
    ApiResponse<String> createOrder(@RequestBody CreateOrderRequest request);
}

还有Dockerfile的一个标准模板:

FROM openjdk:17-jdk-slim AS build-stage
WORKDIR /app
COPY *.jar app.jar
ENTRYPOINT ["java", "-jar", "-Xms512m", "-Xmx1g", "app.jar"]

Kubernetes Deployment 示例(简化版):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: registry.example.com/user-service:latest
        ports:
        - containerPort: 8080

数据流转过程-2

这些看似简单的配置,其实在部署和调试过程中帮我们节省了大量时间。


踩坑经验分享

说到踩坑,这里有几个我印象特别深刻的点。

1. 分布式事务的难题

最初我们在订单创建流程中涉及扣减库存、支付冻结、生成订单三个服务,一开始直接用了本地事务加HTTP调用来处理,结果遇到多次数据不一致的问题。

后来我们改成了基于RocketMQ的事务消息机制,虽然复杂了一些,但是能有效保障最终一致性。

教训是:永远不要试图用本地事务去保证分布式场景下的原子性

2. 网络延迟导致的雪崩效应

某次线上压测时,一个服务突然崩溃,引起连锁反应,其他服务也被拖垮。排查发现是因为服务调用链路上存在同步阻塞,且缺乏熔断机制。

最后我们在所有Feign客户端中引入了Sentinel做熔断降级和限流,设置合理的超时时间和重试次数,效果非常明显。

3. 环境差异引发的诡异问题

由于开发、测试、预生产、生产环境使用的JDK版本、Maven插件、启动参数都不一样,曾经发生过几次“线下没问题,上了生产就报错”的情况。

我们后来统一使用Docker标准化镜像构建流程,配合CI Pipeline自动注入环境变量,大大减少了环境差异带来的困扰。


效果总结

经过这两年多的演进,整个系统的变化可以用“脱胎换骨”来形容。

  • 性能方面:高峰QPS从2k提升到10k以上,响应时间从平均3s降到400ms以内;
  • 运维成本:故障隔离明显增强,部署频率提高,CI/CD流程缩短了发布周期;
  • 开发效率:模块清晰、职责明确,新人更容易理解系统结构;
  • 扩展能力:新业务模块可以直接接入现有平台能力,避免重复开发。

最重要的是,我们建立起了一个可持续演进的技术体系,而不是仅仅完成了某个功能或项目。


经验建议

如果你也在做架构演进,或者正考虑从小规模系统往云原生转型,以下几点建议或许能帮到你:

1. 架构不是越复杂越好,适合当前业务阶段才是最好的

早期没有必要搞太多微服务拆分,先把单体结构理顺,做好模块职责划分,后期再逐步拆分会更顺利。

2. 技术选型要谨慎,避免过度追求“时髦”

云原生确实有很多好工具,但如果基础没打好,盲目上马Kubernetes、Service Mesh可能会适得其反。

3. 注重可观测性,提前埋点

日志、指标、链路追踪一定要做全,尤其是生产环境。否则一旦出问题,连定位方向都没有。

4. 自动化是长期主义的关键

持续集成、持续部署、自动化测试不能省,哪怕初期投入看起来有点慢,但从长远看回报非常大。

5. 团队协同比技术更重要

架构演进从来不只是技术问题,很多时候是对组织结构和协作方式的挑战。只有大家形成共识,才可能走得更远。


写在最后

这几年的经历让我深刻体会到:一个系统的成长,就像一个人的成长一样,不可能一蹴而就,而是不断试错、反思、调整、沉淀的过程。

作为后端工程师,我们不仅要写好代码,更要对系统的可维护性、可扩展性负责;不仅要懂技术,更要理解业务、关注用户体验、注重安全和稳定。

未来的路还很长,也许还会遇到更多未知的挑战,但我相信只要保持学习的心态和解决问题的能力,就能在每一次架构演进中走得更稳、更远。

如果你也有类似的经验,欢迎留言交流,一起成长。

评论 0

最热最新
暂无评论
云原生笔记本Lv.1
0
影响力
0
文章
0
粉丝