从单体到微服务:我在小红书拆系统的真实血泪史

技术拾荒者
2026-05-19 12:00
阅读 1000

大家好,我是小红书推荐算法组的一名工程师,入职两年,坐标上海张江。每天早上8点雷打不动出现在工位——别误会,不是我多卷,纯粹是因为我家就在公司隔壁小区,走路上班5分钟,赖床都省了。最近半年,我被拉进了一个“历史遗留项目重构”专项,任务是把一个跑了五年的Python单体应用,拆成现代化的微服务架构。今天就想和大家聊聊这段“痛并快乐着”的经历。


这事还得从去年双11说起。我们那个老系统,说白了就是一个Django巨石应用,所有功能——用户画像、内容召回、排序打分、A/B实验配置——全塞在一个repo里。平时还好,一到大促流量高峰,CPU直接飙到90%+,数据库连接池爆满,运维兄弟半夜打电话:“哥们,你那个recommendation service又挂了!”

产品经理还一脸无辜地问:“能不能快点加个新策略?就改两行代码。”
我心里苦笑:改两行?这代码耦合得像我妈织的毛衣,牵一发而动全身。

领导终于拍板:“拆!不拆不行了!”于是我和另外两个后端小伙伴,开始了这场“外科手术式”的架构改造。


别信教科书,真实拆分没那么简单

很多人以为微服务就是“把大应用切成小服务”,听起来简单,实操起来全是坑。比如最开始我们天真地按业务模块切:用户服务、内容服务、推荐服务……结果发现,跨服务调用链路爆炸,一个请求要串5个服务,延迟直接翻倍。

更惨的是数据一致性问题。以前在单体里,一个事务搞定的事,现在要搞分布式事务,Saga模式写得我头秃。有一次测试环境跑A/B实验配置,因为服务间状态不同步,导致一部分用户看到新UI,另一部分还是旧版,PM差点冲过来把我键盘泡面里。

后来我们调整策略:先识别高频高内聚的子域,再结合数据边界来划分。比如“实时特征计算”这个模块,它读写Redis和Kafka特别频繁,但和其他模块交互少,就优先独立出来。这个思路,其实是受GPT-4o启发的——别笑!我们团队确实用它辅助做架构分析。

怎么用?把老系统的接口文档、调用日志、DB schema喂给GPT-4o,让它帮我们画调用依赖图谱(当然要人工校验)。虽然它偶尔会一本正经胡说八道,比如建议我们用ZooKeeper做服务注册(现在谁还这么干啊),但至少能快速梳理出哪些函数调用了哪些表,哪些API被前端高频调用。效率提升不少,尤其适合赶deadline的时候。


技术栈选型:务实比炫技重要

我们最终定了这套组合拳:

  • 服务框架:FastAPI(Python系,轻量、异步友好,和我们算法同学的技术栈无缝衔接)
  • 服务注册与发现:Consul(运维团队已标准化,别和公司基建对着干)
  • 通信协议:gRPC(内部高性能调用) + RESTful(对外或低频场景)
  • 消息队列:Kafka(扛住实时行为流)
  • 部署:K8s + Helm(CI/CD流水线早就搭好了)

特别提一下Bolt.new——这是小红书内部基于Go开发的服务治理平台,集成了熔断、限流、链路追踪、配置中心。刚接触时觉得文档写得像天书,但一旦上手真香!比如上周五晚上,我上线了一个新召回策略,结果因为特征缺失导致下游超时。Bolt.new自动触发熔断,只影响了5%流量,而不是全站崩盘。那一刻我默默给平台组点了杯奶茶。


数据库怎么拆?别让DB成为瓶颈

最头疼的其实是数据库拆分。老系统就一个PostgreSQL主库,所有服务共用。拆微服务的第一原则:每个服务独享自己的数据库,不能共享schema!

但我们又不能让用户数据和服务数据完全割裂。解决方案是:

  • 核心用户信息(uid, gender, age等)保留在“用户中心”服务,其他服务通过gRPC同步或缓存获取
  • 推荐相关的行为日志、特征向量、模型版本,全部迁移到新服务的专用DB
  • 历史数据迁移用Airflow写pipeline,每天增量同步,持续两周才搞定

这里有个血泪教训:千万别在高峰期跑DDL!有一次我凌晨2点加了个索引,结果锁表30秒,线上报警炸了。运维大哥在群里@我:“兄弟,下次操作前记得发变更申请,不然我就把你工牌照片贴服务器机柜上辟邪。”


性能对比:拆完真的变快了吗?

当然要看数据说话。我们在灰度发布阶段做了压测对比:

指标 单体架构 微服务架构
P99延迟(ms) 420 180
错误率(%) 2.1 0.3
扩容粒度 整体扩容 单服务扩缩容
新功能上线周期 3天 4小时

最爽的是,现在算法同学想试个新召回模型,只要改自己那个服务,不用求爷爷告奶奶协调整个后端团队。昨天还有个实习生,自己fork repo、改代码、提PR、上线,全程不到半天——这在以前简直是天方夜谭。


给想拆微服务的同学几点真心话

  1. 别为了微服务而微服务:如果你的系统QPS不到1000,拆了反而增加复杂度。先优化单体,比如引入缓存、异步、读写分离。
  2. 监控和可观测性必须先行:没有完善的链路追踪(我们用Jaeger)、日志聚合(ELK)、指标采集(Prometheus),等于蒙眼开车。
  3. 自动化测试是生命线:我们写了大量contract test(契约测试),确保服务接口变更不会偷偷break掉别人。
  4. 人比技术更重要:拆分过程中,和上下游团队对齐接口、数据格式、SLA,沟通成本远高于写代码。建议每周固定sync meeting,别等线上炸了才开会。

最后说句实在的:架构演进没有银弹。微服务不是终点,Serverless、Service Mesh也在路上。但对我们当前阶段来说,这次拆分确实解决了燃眉之急。上周团建吃饭,leader举杯说:“感谢你们把那个‘祖传代码’送进了博物馆。” 我笑着回敬:“下次重构,记得提前给我配个GPT-4o Plus账号。”

毕竟,在这个卷成麻花的行业里,能用工具省下的每一分钟,都是多睡一会儿的希望。而我,还想继续当那个8点就能开工的早起选手呢。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝