我从单体架构逃回微服务,又逃回单体——一个后端开发的自白

🔑 关键词:单体架构,微服务,分布式事务,重构,技术债务

📖 摘要:一个后端开发在单体与微服务之间反复横跳的真实经历,拆解两种架构的隐性成本与认知误区,提出基于团队规模和故障半径的实用决策框架。

第一回合:被微服务的光环闪瞎了眼

图片

那是2021年,我们团队维护着一个运行了7年的Java单体应用。每次发布都要等半小时,代码合并冲突永无止境,测试环境比生产环境还难伺候。终于有一天,技术总监在周会上拍板:"我们要全面微服务化!"当时全组沸腾,仿佛看到了救世主。我甚至偷偷买了本《微服务设计》,把每个章节都划了重点。

我们花了三个月把用户、订单、支付拆成了独立服务。前两周确实爽,每个团队守着自己的一亩三分地,部署互不干扰。但很快,第一个坑来了:跨服务调用怎么处理事务?下单要扣库存、减余额、发消息,三个服务各自为政,分布式事务方案从2PC到SAGA讨论了一个月。最后选了个现成的SAGA框架,但一上线就出问题——订单服务挂了,库存却已经扣了,用户疯狂投诉。

图片

更魔幻的是,为了排查一个请求跨了五个服务,我们被迫上了全链路追踪。链路图比蜘蛛网还密,每次看都得放大缩小好半天。运维同学开始抱怨,以前一台机器上跑个JVM,现在几十个容器要盯着,监控告警阈值调了无数遍,天天晚上被叫醒。

第二回合:微服务的隐藏账单比想象中更贵

到了2022年,团队扩张到20人,但我们每个迭代要花将近两周时间去处理环境问题、配置同步和接口兼容。我印象最深的一次:某个服务升级了HTTP客户端库,结果下游服务解析不了新加的请求头,线上故障一查就是三小时。这种事在单体时代根本不存在。

图片

其实微服务真正的成本不在服务本身,而在认知负担。你脑子里要装着一张调用拓扑图,还得时刻记住每个服务的超时时间、重试策略、熔断阈值。有时候为了调一个参数,要连着改三个服务的配置文件,再走一遍CI/CD流水线。我亲眼看到团队里最资深的工程师因为一个网络抖动,花了半天时间定位是哪个服务超时导致的级联失败。

我开始怀疑:我们是不是为了架构上的"政治正确"而放弃了工程上的常识?二十个人的团队,业务边界本来就模糊不清,强行拆成六个服务,结果每个服务都只有两三万行代码,却要维护独立的发布流程、数据库、监控面板——这不就是给七个矮人各配一辆房车吗?

图片

第三回合:回到单体,但不是原来的配方

今年年初,我做了一个谁也没想到的决定:把核心链路重新合并成一个模块化单体。当然,不是退回那个揉成一坨的老代码,而是用Maven模块和package隔离把业务边界画清楚,内部还是分层的,但部署单元只有一个。

图片

效果立竿见影。事务回滚变简单了,一个方法调用就搞定,不用再等消息队列最终一致。本地调试也爽了,不用开六七个服务,IDEA里直接跑起整个应用。以前跨服务调用变成普通方法调用,性能损耗直接降为0.1毫秒。新同事入职两天就能看懂全链路,而不是对着序列图发懵。

我知道说"微服务不好"很容易被扣上思想落后的帽子。但现实是,微服务解决的是组织规模问题和弹性伸缩需求,不是所有项目的药方。我们公司日活不到十万,部署在云上偶发毛刺,个别服务峰值也就几百QPS,单体加个负载均衡完全够用。为了这些不存在的瓶颈付出分布式地雷的代价,这几年我越想越亏。

最后的感悟:架构选择是团队认知史的外化

图片

这三年折腾下来,我最深的体会是:架构不是技术选型,而是对团队错误史的妥协。你犯过并发粒度的错,就会倾向拆服务;你被分布式事务坑过,就会想回到本地事务。可悲的是,很少有团队愿意记录这些错误背后的真实场景,以至于"从微服务回单体"这条路,我们走得比预想中更孤独。

如果你问我该选哪种,我只会说:先数一下你的团队人数,再看一下你的监控系统是否已经成熟到能诊断跨进程问题,最后摸着自己的良心问一句——这些服务拆开之后,你真的敢保证不会出现循环调用吗?不要被技术浪潮裹挟,也不要被"业界最佳实践"绑架。你的项目,只有你和你队友知道哪里在疼。