从单体到微服务:三年老咸鱼的架构翻车实录

郑雨泽
2026-01-14 07:17
阅读 265

去年双11前两周,我差点被我们组的“祖传”Python单体应用送走。那玩意儿跑了快五年,代码量堪比《红楼梦》全集,启动时间比泡面还长——3分47秒。产品经理在站会上轻描淡写地说:“咱们加个实时库存预警吧,就明天上线。”我盯着屏幕,手里的咖啡突然不香了。

作为一名在当前公司摸爬滚打三年多的后端工程师,我早就想动这坨“技术债巨兽”了。但每次提重构,老板都笑眯眯地说:“系统跑得挺稳啊,别折腾。”直到上个月,因为一个简单的促销接口拖垮了整个支付链路,导致线上事故持续47分钟,运维兄弟在群里发了20个“求求了”,我才终于拿到了“微服务改造”的尚方宝剑。

单体之痛:不只是启动慢

我们的老系统是典型的Django+MySQL架构,所有业务逻辑——用户、商品、订单、支付、物流——全塞在一个项目里。表面上看,开发简单,部署方便(其实也不方便,毕竟每次改一行日志都要全量发布)。但问题在于:

  • 资源争抢:高并发下单时,连静态文件请求都变慢
  • 技术栈锁死:想用Java写高性能计算模块?门都没有
  • 测试地狱:改个用户头像功能,要跑800多个无关的集成测试
  • 部署恐惧症:上线前夜全员失眠,生怕一个空指针干掉整个系统

最离谱的是,有次实习生不小心把print("debug")提交到生产,结果日志文件暴涨到120GB,直接把磁盘写满。运维小哥一边删日志一边念叨:“你们Python佬能不能学学Java系的严谨?”

拆!但怎么拆?

微服务不是简单地把代码切成几块。我在上周五晚上加班时画了张草图,核心原则是:按业务边界拆,而非按技术层拆

我们最终划分了五个核心服务:

服务名 技术栈 职责 关键指标
user-service Java + Spring Boot 用户管理、认证授权 QPS 5k, P99 < 80ms
product-service Python + FastAPI 商品信息、库存 QPS 3k, P99 < 120ms
order-service Java + Spring Cloud 订单创建、状态机 QPS 8k, P99 < 150ms
payment-service Java + Dubbo 支付对接、对账 QPS 2k, P99 < 200ms
notification-service Python + Celery 短信、邮件、站内信 异步,延迟 < 5s

为啥混合用Java和Python?很简单:性能敏感的用Java,快速迭代的用Python。比如订单服务需要处理复杂的分布式事务,Java的生态和工具链更成熟;而商品服务经常要对接各种第三方API,Python的requests和pandas能让我少写一半代码。

踩坑现场:那些深夜的眼泪

坑1:数据库怎么分?

最初我想直接按服务分库,结果发现订单表里有user_id和product_id,跨库查询直接给我整不会了。后来采用了领域驱动设计(DDD) 的思路:

  • 每个服务拥有自己的数据库,绝不共享
  • 通过事件驱动同步冗余数据(比如order-service订阅user-service的UserUpdated事件)
  • 关键查询用物化视图ES索引解决
// Java订单服务中,通过Feign调用用户服务
@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    UserDTO getUserById(@PathVariable Long id);
}

但网络调用有失败可能啊!于是又加了熔断降级本地缓存。当时真的想砸电脑——以前查个用户信息一条SQL搞定,现在要处理超时、重试、缓存穿透……

坑2:分布式事务搞人心态

最开始用Spring的@Transactional,结果发现跨服务根本不生效。研究了一周,最后采用Saga模式

  1. 创建订单(状态:待支付)
  2. 扣减库存(异步消息)
  3. 如果支付失败,发送“取消订单”事件
  4. 库存服务收到后回滚

Python这边用Celery的acks_late=True保证消息不丢失,Java用RocketMQ的事务消息。虽然最终一致性有点反直觉,但总比系统挂了强。

坑3:链路追踪成了救命稻草

没上微服务前,排查问题靠grep日志。现在10个服务互相调用,光看日志根本不知道请求跑到哪去了。赶紧接入SkyWalking,效果立竿见影:

  • 一次完整的下单请求,耗时分布一目了然
  • 发现product-service的某个接口P99高达2s,原来是N+1查询
  • 优化后,整体下单链路从1.8s降到400ms

性能对比:真香!

改造完成后,我们做了压测(用locust写的,Python yyds):

指标 单体架构 微服务架构 提升
平均响应时间 1200ms 380ms 68% ↓
错误率(5k QPS) 12% 0.3% 97% ↓
部署时间 8分钟 45秒(单服务) 90% ↓
故障隔离 服务级熔断

最爽的是,现在改商品推荐算法,再也不用担心影响支付功能了。上周产品经理又提了个“紧急需求”,我淡定地说:“行,明天发product-service就行,其他服务不用动。”他愣了一下,然后默默给我点了杯瑞幸。

给想跳槽的兄弟几点建议

因为我最近在考虑换环境,所以特别关注微服务经验在面试中的价值。说真的,能讲清楚微服务拆分逻辑、容错机制、数据一致性的候选人,基本都能过技术面。但千万别为了微服务而微服务——我见过有人把一个CRUD应用拆成8个服务,结果运维成本爆炸,最后又合并回去了。

如果你也在重构路上,记住:

  • 先治理,再拆分:单体内部先做好模块解耦
  • 监控先行:没链路追踪的微服务等于裸奔
  • 灰度发布:别一次性全切,用Nginx或Service Mesh慢慢放量
  • 文档!文档!文档!:不然三个月后你自己都看不懂服务间依赖

最后唠叨两句

从单体到微服务,不是技术升级,而是思维升级。它逼你思考业务边界、容错设计、可观测性……这些才是高级工程师的核心能力。

上周参加QCon,听阿里P8分享他们的Service Mesh实践,我一边记笔记一边感慨:原来我们踩的坑,人家早就趟平了。不过没关系,每个架构师都是从“祖传代码”里爬出来的。

对了,如果你也在用Python/Java做微服务,欢迎评论区交流!说不定下家公司就是你领导呢(笑)。毕竟,我简历已经更新好了,关键词:微服务、性能优化、不背锅

评论 0

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