后端架构演进:从单体到云原生——一个前测试转开发的踩坑实录

Vue快乐水
2026-01-03 10:11
阅读 1184

作者:小林,3年前从测试岗转做后端开发,现居上海浦东,和女友合租在张江地铁站旁的老小区。月薪从15k涨到22k,房租3500,每天通勤40分钟,代码写得一般但爱复盘。


上周五晚上十点半,我瘫在沙发上刷着钉钉群消息,手指滑到一条:“生产环境服务挂了,用户登录不上。”
我瞬间从半睡状态弹起来,手忙脚乱地打开终端。女友小雅探出头:“又崩了?你这周第三次了吧?”
“嗯……可能又是那个单体应用扛不住流量高峰了。”我苦笑着,一边连上服务器一边想:要是当初没把整个系统塞进一个 Go 服务里,现在是不是能睡个安稳觉?

这事得从去年十月说起。


起点:一个人、一个单体、一堆债

去年9月,我刚接手公司核心业务系统的重构工作。那时我才转开发不到一年半,之前干了两年多自动化测试,写过不少 Python 和 JavaScript 的 E2E 脚本,对 CI/CD 流程熟得不能再熟。但真要自己搭后端架构?心里其实虚得很。

项目背景很简单:老系统是 PHP 写的,跑在一台阿里云 ECS 上,数据库是 MySQL,前端用 Vue。老板说:“小林,你不是会 Go 吗?重写一遍,性能提上去,顺便加点新功能。”

我热血上头,拍胸脯答应。心想:Go 并发强、编译快、部署简单,搞个单体服务不就完了?于是花了三周时间,把用户中心、订单、支付、通知全塞进一个 Go 二进制文件里,用 Gin 框架搭了个 MVC 结构,前端还是原来的 Vue,API 接口用 RESTful 风格。

上线那天,我和运维小王在办公室守到凌晨两点。一切正常!第二天晨会,老板夸我“效率高”。我心里美滋滋,甚至开始幻想年终奖能不能多拿一个月。

但技术债这东西,就像合租房里的蟑螂——你以为清理干净了,结果半夜它又从厨房爬出来。


第一次崩溃:流量一涨,全家桶炸

问题出现在双十一预热当天。市场部搞了个“邀请好友得红包”活动,用户量暴增三倍。我们的单体服务 CPU 直接飙到 98%,数据库连接池打满,Redis 缓存穿透,连带前端 JavaScript 请求超时,用户页面白屏。

我坐在工位上疯狂 kubectl logs(对,后来我们上了 Kubernetes,但当时还没),手抖得差点把咖啡泼到键盘上。运维小王叼着烟走过来:“兄弟,你这服务是不是没做熔断?也没限流?”

我愣住。熔断?限流?我在测试岗时听说过 Hystrix,但自己写 Go 服务时根本没考虑这些。更糟的是,所有模块耦合在一起,一个支付接口慢,整个进程都卡住。用户登录不了,因为用户模块和支付模块共享同一个 goroutine 池。

那天晚上,我和小雅视频通话时她问:“今天加班这么晚?脸色好差。”
我说:“系统崩了,我在改代码。”
她沉默了几秒:“你转开发之后,好像天天在救火。”

那一刻,我突然意识到:我用“快速交付”的名义,给自己挖了个巨坑。


转折点:从“能跑就行”到“必须拆”

崩溃之后,老板没骂我,反而说:“趁这次机会,好好想想怎么重构。”
这句话救了我。

我开始恶补微服务和云原生知识。白天查文档,晚上看极客时间的《Go 微服务实战》,周末窝在浦东图书馆啃《Cloud Native Go》。还厚着脸皮约了前司做 SRE 的老哥喝咖啡,请教他怎么设计弹性系统。

他一句话点醒我:“单体不是原罪,耦合才是。 你得先解耦,再谈分布式。”

于是我们定了三步走:

  1. 垂直拆分:把用户、订单、支付拆成三个独立 Go 服务
  2. 通信解耦:内部调用改用 gRPC + Protobuf,异步任务走 Kafka
  3. 基础设施云原生化:上 Kubernetes + Helm + Prometheus

听起来很理想,但实操全是坑。


踩坑实录:那些让我深夜流泪的细节

坑1:gRPC vs REST,选错了沟通协议

一开始我图省事,内部服务间还是用 HTTP+JSON。结果发现序列化开销大,延迟高。后来换成 gRPC,但团队里前端同事不会写 .proto 文件,抱怨“你们后端又搞新花样”。

我只好写了个小工具,用 Go 自动生成 TypeScript 客户端代码(其实就是封装了 grpc-web + protobuf.js),前端直接 import 就能调。小雅看到后笑我:“你这是不是有点像你以前写测试脚本的路子?”
我一愣——对啊!我以前就是靠自动化帮前后端联调的,现在不过是换个形式罢了。

坑2:K8s 不是银弹,YAML 能逼疯人

第一次写 Deployment YAML 时,我把 resources.limits.cpu 设成了 500m,结果 Pod 频繁被 OOMKilled。查了半天才发现,Go 应用在容器里默认会占用所有可用内存,得手动设置 GOGCGOMAXPROCS

更惨的是,Helm Chart 版本管理混乱,测试环境和生产环境配置混在一起。有一次我误把 dev 的数据库地址 deploy 到 prod,差点删库跑路(还好有备份)。

那晚我蹲在阳台抽烟,看着黄浦江对岸的陆家嘴灯火,心想:月薪22k,值不值这个心力交瘁?

坑3:监控告警太多,反而麻木了

上 Prometheus + Grafana 后,我兴奋地配了一堆告警规则:CPU > 80%、请求延迟 > 500ms、错误率 > 1%……
结果某天半夜手机狂震,我爬起来一看,全是“磁盘 IO 等待过高”——其实是日志轮转没配好,/var/log 撑爆了。

小王吐槽我:“你这告警跟微信未读红点一样,多了就没人看了。”
后来我们学乖了:只对“影响用户体验”的指标设 P1 告警,其他一律降级为 dashboard 曲线。


技术之外:人、钱、和选择

转开发第三年,我渐渐明白:架构演进从来不只是技术问题。

比如拆微服务,光技术可行不够,还得说服老板接受短期交付速度下降。我做了个对比表格:单体每月故障4次,每次损失约2万元;微服务初期投入2人月,但长期可减少70%故障。老板看完点点头:“干吧。”

再比如,我和小雅商量要不要搬离合租房。她说:“你最近总加班,是不是压力太大?要不我们换个离公司近点的?”
我算了算账:现在房租3500,如果搬到金桥,得5500,但通勤省下1小时。技术人的价值,不该被通勤耗尽。 最后我们咬牙签了新合同。

还有一次 HR 谈晋升,问我:“你觉得你最大的成长是什么?”
我没说“掌握了 K8s”或“精通了 Go”,而是说:“我学会了在‘快’和‘稳’之间找平衡——这比写一万行代码都重要。”


给同行者的几点建议(血泪总结)

如果你也正从单体走向云原生,听我几句大实话:

  1. 别为了微服务而微服务
    如果团队不到10人,业务没到百万 DAU,先做好模块化(比如 Go 里的 internal 包隔离),比强行拆服务更实际。

  2. Go 是好语言,但不是万能胶
    我们有些轻量任务(比如数据清洗)后来改用 Node.js + JavaScript 写,因为生态工具多、启动快。技术选型要看场景,别被“信仰”绑架。

  3. 云原生 ≠ 上 K8s
    先搞定日志、监控、CI/CD 这些基础能力。我们花两周配好 GitLab CI + ArgoCD 自动部署后,发布效率提升3倍,比调 K8s 参数实在多了。

  4. 保留“回滚”的勇气
    有次新支付服务上线后偶发超时,我们果断切回旧单体中的支付模块,等查清问题再上。线上稳定,永远高于技术先进性。


写在最后:架构是长出来的,不是设计出来的

现在我们的系统跑在 ACK(阿里云 K8s)上,三个核心服务独立伸缩,Prometheus 告警精准,甚至能自动扩缩容。上周压测,5000 QPS 下 P99 延迟稳定在 120ms。

但我知道,这远不是终点。Service Mesh、Serverless、Dapr……新技术层出不穷。可真正的架构师,不是追逐潮流的人,而是知道什么时候该停、该退、该妥协的人。

回望这三年,从测试岗转开发,从写脚本到扛生产,从焦虑失眠到学会在 chaos 中保持 calm——技术只是载体,成长才是主线。

前几天小雅问我:“如果重来一次,还会转开发吗?”
我想了想:“会。但下次,我会更早告诉自己:慢,就是快。稳,才能远。

共勉。


附:实用资源清单(亲测有效)

  • Go 微服务模板:https://github.com/xxx/go-micro-template(我自己维护的,含 gRPC + JWT + tracing)
  • JavaScript 前端调 gRPC 教程:用 grpc-web + protoc-gen-grpc-web 生成 TS 客户端
  • K8s 入门避坑指南:重点看 resource requests/limits 和 readiness probe 配置
  • 云原生日志方案:Fluentd → Kafka → Elasticsearch,比直接 stdout 到 CloudWatch 稳得多

技术分享不易,如果这篇踩坑文对你有帮助,欢迎点赞/转发。也欢迎留言聊聊你的架构演进故事——毕竟,每个程序员的深夜崩溃,都值得被看见。

评论 0

最热最新
暂无评论
Vue快乐水Lv.1
0
影响力
0
文章
0
粉丝