后端架构演进:从单体到云原生,一个考公程序员的实战复盘

技术达人App
2026-04-22 10:36
阅读 2218

上周五晚上十一点,我盯着 MacBook 上那堆 Docker 日志,脑子里只有一个念头:再熬两个月,考上公务员就再也不碰线上事故了。但在这之前,还得把公司这套老旧系统给云原生化——毕竟简历上得有点硬货,不然面试官问我“你做过什么架构优化”,我总不能说“我用 Codeium 写过 CRUD”吧。

我在这家公司干了三年多,后端主力语言一直是 Java,技术栈稳得像老干部开会:Spring Boot + MyBatis + MySQL,前端用 Vue,部署靠 Jenkins 打包扔到几台物理机上。一开始还好,业务简单,日活几千,扛得住。可去年双11前,产品经理突然甩过来一个“全链路促销重构”的需求,还拍着胸脯说“流量最多涨三倍”。结果当晚峰值 QPS 直接飙到 5w+,数据库连接池爆了,API 平均响应时间从 80ms 涨到 2s,用户投诉电话打爆客服热线。

运维同事在群里发了个裂开表情:“兄弟,你这单体应用是打算用爱发电吗?”

那一刻,我知道,不能再躺平了。


单体架构:稳定,但迟早要炸

我们原来的系统是个典型的“大泥球”:所有功能模块——用户、订单、库存、优惠券——全塞在一个 Spring Boot 工程里。启动一次要两分钟,改一行代码就得全量回归测试。最离谱的是,前端同学提个“加个按钮颜色”的需求,后端 CI/CD 流水线跑完,QA 还得测支付流程,生怕牵一发而动全身。

性能瓶颈主要集中在两点:

  1. 数据库锁竞争:高并发下单时,库存扣减用的 SELECT FOR UPDATE 导致大量线程阻塞。
  2. 资源耦合:促销模块 CPU 爆满,连累用户登录接口一起变慢。

当时真想砸电脑。但冷静下来一想,这不就是很多传统企业系统的缩影吗?稳定、熟悉、开发快,但扩展性和容错性几乎为零。


微服务拆分:别被“拆”字吓到

领导拍板搞微服务改造,说是“对标大厂架构”。但团队没人真正落地过,只能边学边干。好在现在有 DeepSeek 这类国产大模型,写个 Spring Cloud Alibaba 的 demo 都不用翻文档了——当然,生产环境还是得自己看源码,AI 给的代码经常漏掉熔断配置。

我们按业务域拆成了四个服务:

  • user-service(用户)
  • order-service(订单)
  • stock-service(库存)
  • coupon-service(优惠券)

每个服务独立数据库,通过 OpenFeign 调用,Nacos 做注册中心,Sentinel 实现限流降级。关键改动在于异步解耦:下单成功后,用 RocketMQ 发消息通知积分、日志、风控等下游系统,避免同步链路过长。

// 库存扣减 + 发送消息示例
@Transactional
public void deductStock(Long skuId, Integer num) {
    // 乐观锁更新库存,避免 SELECT FOR UPDATE
    int updated = stockMapper.updateStockByOptimisticLock(skuId, num);
    if (updated == 0) {
        throw new BusinessException("库存不足");
    }
    // 异步发消息,不阻塞主流程
    rocketMQTemplate.convertAndSend("order-created", new OrderEvent(skuId, num));
}

注:这里用版本号实现乐观锁,比悲观锁性能提升明显,压测 QPS 从 1200 提升到 3500。

但微服务不是银弹。刚上线那周,因为 Nacos 配置没刷,coupon-service 调用了测试环境的 Redis,导致优惠券被白送了几百张。产品经理差点冲进机房拔网线。


云原生:不止是容器化

很多人以为上 Kubernetes 就是云原生,其实不然。真正的云原生,是设计思维的转变:从“让机器适应应用”变成“让应用适应平台”。

我们用了阿里云 ACK(容器服务),配合 Helm 管理应用发布。每个服务打成镜像,Dockerfile 尽量精简:

FROM eclipse-temurin:17-jre-alpine
COPY target/app.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:+UseG1GC", "-jar", "/app.jar"]

重点优化了 JVM 参数和健康检查探针。以前单体应用挂了整个站瘫痪,现在某个 Pod Crash,K8s 自动重建,前端几乎无感——当然,前提是你的接口设计得幂等。

说到前端,他们倒是乐开了花。以前每次后端改接口,都得等我们打包部署完才能联调。现在我们用 Swagger + YAPI 维护 OpenAPI 规范,前端直接 mock 数据,效率飞起。Codeium 甚至能根据注释自动生成 DTO 类,虽然偶尔字段名会拼错(笑)。


性能对比:数据不说谎

改造前后,我们做了三轮全链路压测,结果如下:

指标 单体架构 云原生架构 提升幅度
平均响应时间 (ms) 420 95 77% ↓
P99 延迟 (ms) 1800 320 82% ↓
最大 QPS 1800 6500 261% ↑
故障恢复时间 >10 分钟 <30 秒 99% ↓
发布频率 每周 1 次 每天 5+ 次 显著提升

最爽的是弹性伸缩:促销期间自动扩容到 20 个副本,结束后缩回 3 个,成本省了一半。运维大哥终于不用半夜被 PagerDuty 叫醒了。


血泪教训与心得

  1. 不要为了拆而拆:先识别真正的瓶颈。我们一开始想把“日志模块”单独拆出来,后来发现纯属浪费精力——直接上 ELK 更香。
  2. 可观测性必须前置:没上 Prometheus + Grafana 之前,排查问题全靠猜。现在 CPU、内存、GC、DB 连接数一目了然。
  3. 本地开发体验很重要:用 Skaffold 或 DevSpace 实现“改代码 → 自动构建 → K8s 更新”,比手动 build & apply 快十倍。
  4. 别信 AI 全能:DeepSeek 和 Codeium 能帮你写样板代码,但分布式事务、幂等设计、缓存穿透这些坑,还得自己踩。

写在最后:考公路上的技术沉淀

其实我挺感谢这段经历的。虽然每天被 deadline 追着跑,但逼着自己啃下了云原生这一整套体系。现在写简历,不再是“熟悉 Spring Boot”,而是“主导单体到云原生架构演进,支撑日活 50w+ 系统”。

当然,终极目标还是上岸。想象一下:以后在政务云上部署一套审批系统,用 Java 写,用 Mac 调试,Windows 只用来兼容老 IE 浏览器(如果还有人用的话)……嗯,这日子,稳了。

但在那之前,今晚还得去修一个因 K8s Ingress 配置错误导致的 502 错误。唉,程序员的命,也是命啊。

评论 0

最热最新
暂无评论
技术达人AppLv.1
0
影响力
0
文章
0
粉丝