后端架构演进:从单体到云原生,我在字节的五年搬砖路

代码不眠人
2026-04-06 06:37
阅读 1794

大家好,我是成都字节基础架构组的一名后端开发,入行刚好五年。平时除了写 Java、调接口、看监控大盘,还特别喜欢在闲暇时折腾前端动画——别笑,这真的能缓解 debug 到凌晨三点的精神创伤。

上周五晚上十一点半,我刚修完一个诡异的内存泄漏问题(又是某个第三方 SDK 的锅),顺手刷了下 GitHub Copilot 的新更新日志。突然想到,去年双11前我们还在为单体架构的扩容焦头烂额,如今却已经在 Kubernetes 上跑着十几种微服务,还能用 Gemini 自动分析链路追踪数据。这五年,变化真快得让人恍惚。

今天这篇不是教程,也不是八股文,就是想和大家唠唠:我们是怎么一步步从“一个 jar 包打天下”的单体架构,走到今天的云原生世界的。中间踩过的坑、熬过的夜、被产品经理催过的 deadline,都会提到。如果你也在经历类似转型,或许能少走点弯路。


一开始,我们连“架构”这个词都懒得提

刚入职那会儿,我们团队负责的是公司内部的一个中台系统,代码库叫 monolith-core,听名字就知道是什么画风。整个系统就一个 Spring Boot 应用,数据库用 MySQL,缓存靠 Redis,部署方式?直接 nohup java -jar 丢到几台物理机上。

那时候最怕的就是大促。每次双11前一周,运维大哥就会在群里@所有人:“各位老板,明天开始扩容,请提前准备好 jar 包。”然后我们后端就得手动改配置、打镜像(其实是打包)、上传、重启……一套流程下来,人仰马翻。

最离谱的一次是 2021 年春节活动,因为一个 SQL 没加索引,高峰期数据库 CPU 直接飙到 100%,整个服务雪崩。我当时坐在工位上看着 Grafana 大盘一路红到底,心里默念:完了,年终奖没了。

但说实话,单体架构也有爽的时候——本地启动快、调试方便、发布简单。你改个接口,mvn clean install 一跑,本地就能测。哪像现在,改个配置得等 CI/CD 跑十分钟,还得去 K8s 里捞日志。


微服务拆分:不是技术驱动,是业务逼的

真正让我们下定决心拆微服务的,不是什么“高可用”“弹性伸缩”的理想,而是产品同学甩过来的一份需求文档:“我们需要支持多租户隔离,每个客户要有独立的数据空间和配置策略。”

那一刻,我知道,单体架构的棺材板盖不住了。

拆分过程堪称“边飞行边换引擎”。我们先把用户中心、权限管理、通知服务这些边界清晰的模块拎出来,用 Dubbo + Nacos 搞了一套微服务框架。Java 技术栈没变,但复杂度指数级上升:

  • 接口调用从本地方法变成 RPC
  • 分布式事务怎么搞?最终一致性还是 TCC?
  • 日志分散在十几个服务里,排查问题得开十几个 tab
  • 链路追踪成了刚需,不然根本不知道请求卡在哪一步

记得有次上线新功能,测试同学报了个 Bug:“用户登录后看不到菜单。”我查了半天本地没问题,最后发现是权限服务的缓存没刷新,而菜单服务又强依赖这个缓存。两个服务之间的状态不同步,坑死人。

这时候,GitHub Copilot 真帮了大忙。虽然它有时候会一本正经地胡说八道(比如给我生成一个不存在的 Dubbo 注解),但在写重复的 DTO、Feign Client 或者单元测试模板时,效率提升明显。尤其是在赶 deadline 的时候,它就像个不会抱怨的实习生——虽然偶尔写错,但至少能帮你把架子搭起来。


容器化:从“能跑就行”到“标准化交付”

微服务拆完,部署又成了新痛点。每个服务依赖的 JDK 版本、JVM 参数、环境变量都不一样,运维同学天天在群里哀嚎:“你们能不能统一一下配置?”

于是我们开始上 Docker。最初的做法很粗暴:每个服务写个 Dockerfile,FROM openjdk:11,然后把 jar 包 COPY 进去。看起来很美,直到某天生产环境因为时区问题导致定时任务全部错乱——原来基础镜像默认是 UTC 时间!

痛定思痛,我们搞了一套内部的镜像规范:

FROM registry.byted.internal/jdk:11-slim-zh

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

COPY target/app.jar /app/
WORKDIR /app

EXPOSE 8080
CMD ["java", "-Xms512m", "-Xmx512m", "-XX:+UseG1GC", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

这套模板后来被全公司推广,连前端同学打包 Node.js 应用都来抄作业。容器化最大的好处不是“一次构建到处运行”,而是强制标准化——你不能再随便改系统参数、装奇奇怪怪的库,一切都要声明式管理。


云原生:不只是上 K8s,而是思维升级

真正的转折点发生在 2023 年初。公司决定全面推进云原生战略,目标是:所有新服务必须基于 K8s 部署,老服务逐步迁移

一开始我们都觉得是“为了上云而上云”。但用了几个月后才发现,云原生的核心不是技术,而是对资源、弹性、可观测性的重新定义

比如,以前我们扩容靠人工评估流量峰值,现在直接配 HPA(Horizontal Pod Autoscaler):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-service
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60

流量一上来,Pod 自动扩;低峰期自动缩。再也不用半夜被 PagerDuty 叫醒去手动扩容了。

更爽的是服务网格(Service Mesh)。我们用 Istio 做了灰度发布、熔断降级、流量镜像,连接口超时时间都能动态调整,不用改代码。有一次线上出了个慢查询,我们直接在 Sidecar 里配置了 500ms 超时,瞬间止损,等第二天再慢慢优化 SQL。


AI 工具:从玩具到生产力

说到工具,最近团队里聊得最多的就是各种 AI 编程助手。除了前面提到的 GitHub Copilot,我们也在试用 Gemini文心一言

Gemini 在分析日志和链路追踪方面有点东西。比如把一段 Trace ID 扔给它,它能自动总结出“90% 的延迟发生在 DB 查询阶段,建议检查索引”。虽然不能完全信,但至少能快速定位方向。

文心一言呢?说实话,在 Java 后端场景下表现一般,经常生成过时的 Spring Boot 配置(比如还在用 @EnableEurekaClient)。但它在写文档、生成接口说明时还不错,尤其适合应付那些“请补充设计文档”的周报任务。

不过我一直觉得,这些工具再强,也替代不了工程师的判断。它们更像是“高级 grep”+“智能补全”,真正的架构决策、性能调优、故障排查,还得靠人。


架构对比:一张表看清楚演进代价

维度 单体架构 微服务 云原生
开发效率 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
部署复杂度 ⭐⭐⭐ ⭐⭐⭐⭐
弹性伸缩 ⚠️(需自研) ✅(原生支持)
故障隔离 ✅✅
资源利用率
学习成本 极高

可以看到,每一步演进都在牺牲短期效率,换取长期可维护性和弹性。这也是为什么很多小公司没必要一上来就搞云原生——你连用户都没几个,搞那么复杂干嘛?

但在字节这种体量,每天百万级 QPS、上千个微服务,不用云原生根本扛不住。尤其是成都这边的生活节奏虽舒服,但业务压力一点不比北京上海小。上周我们组还在为一个新业务做压测,目标是单集群支撑 10w 并发,这要放在单体时代,光数据库连接池就得炸。


血泪教训:别踩这些坑

  1. 不要为了拆而拆
    微服务不是银弹。如果业务耦合严重,硬拆只会让问题更隐蔽。我们有个模块拆完后,两个服务之间每天要同步几十万条数据,最后又合并回去了。

  2. 可观测性必须前置
    上云原生之前,先把日志、指标、链路追踪(Logging, Metrics, Tracing)三件套搞齐。不然出问题就是“盲人摸象”。

  3. 数据库是瓶颈
    无论架构怎么变,DB 依然是最容易出事的地方。分库分表、读写分离、缓存策略,这些都得提前规划。我们吃过太多“缓存击穿导致 DB 挂掉”的亏。

  4. 自动化是生命线
    CI/CD、配置管理、蓝绿发布,这些流程必须自动化。否则人力成本会爆炸。现在我们一个新服务从代码提交到上线,全程不到 15 分钟,靠的就是完善的 DevOps 流水线。


写在最后

从单体到云原生,表面上是技术栈的升级,本质上是工程思维的进化。你不再只关注“这个接口能不能跑通”,而是要考虑“这个服务能不能被观测、能不能被调度、能不能在故障时优雅降级”。

现在的我,虽然还在基础架构组“搬砖”,但已经习惯了在 K8s Dashboard 里看 Pod 状态、用 Prometheus 查指标、拿 ArgoCD 做 GitOps。偶尔怀念单体时代的简单,但更多时候,是享受这种“掌控感”——知道系统每一层在哪里,出了问题能快速定位。

至于未来?听说公司已经在试水 Serverless 和 Dapr 了。不过我觉得,与其追逐新名词,不如先把眼前的服务治理好。毕竟,再牛的架构,也挡不住一行 bug 的威力

对了,如果你也在成都搞后端,欢迎约咖啡聊聊——我知道几家不错的店,debug 到崩溃时特别管用 ☕️。


本文纯属个人经验分享,不代表字节跳动官方观点。文中提到的工具仅为实际使用反馈,无任何商业合作。

评论 0

最热最新
暂无评论
代码不眠人Lv.1
0
影响力
0
文章
0
粉丝