团队不到10人,我为何劝你放弃微服务?

凌晨三点,看着监控屏上因为网络抖动导致分布式事务回滚失败的报警红灯,我手里的速溶咖啡早已经凉透了。

那是2021年的一个春天,作为一家B轮创业公司的架构师,我带着5个后端兄弟,雄心勃勃地维护着一套包含12个微服务的庞大系统。日活用户刚破万,我们的服务器成本却比竞品高出三倍,开发一个新功能需要改动三个仓库,联调得喊上大半个组的人。

那一刻我突然意识到:我们引以为傲的“先进架构”,正在慢慢拖死整个团队。

如果你也正对着复杂的Service Mesh配置发愁,或者因为某些“高大上”的技术选型而焦虑,不妨停下来听听我的建议:在中小团队,“够用”才是最高级的架构哲学。

别让“简历驱动开发”毁了项目

很多时候,我们选择某个技术栈,不是因为业务需要,而是因为“大家都这么用”或者“我想把这个写进简历里”。

我曾接手过一个电商SaaS项目,前任架构师为了追求极致性能,在日单量不到5000的时候,引入了Kafka做全链路异步,上了ElasticSearch做搜索,还搭了一套复杂的Redis Cluster。

结果呢?

  • 维护成本极高:三个后端开发,有一半时间在排查中间件的不稳定问题,而不是写业务代码。
  • 招聘困难:新来的实习生光是搭本地开发环境就要花两天,看到复杂的调用链路直接被劝退。

后来我们在重构时,做了一个极其“倒退”的决定:砍掉Kafka,改用Redis List做简单队列;砍掉ES,直接用MySQL的全文索引(对于十万级数据完全够用)。

结果惊人:服务器成本下降了60%,系统稳定性从99%提升到了99.9%,因为组件越少,出错的概率越低。

“在中小规模下,单体架构+适当的模块化,往往比微服务更能打。”

模块化单体:被低估的“银弹”

提到单体架构(Monolith),很多人脑海里浮现的是那坨改一行崩三处的“意大利面条代码”。但其实,模块化单体(Modular Monolith) 才是中小团队的救星。

我不止一次在代码评审会上强调:物理上的拆分(微服务)并不等于逻辑上的解耦。 如果你的代码耦合度高,拆成微服务只会变成“分布式大泥球”,不仅没解决耦合,还引入了网络延迟。

我现在每做一个新项目,都会坚持使用模块化单体结构。我们把不同的业务域(如订单、用户、支付)放在同一个仓库的不同包(Package)下,通过定义清晰的接口进行交互,严禁跨包直接依赖数据库表。

看看这种简单的目录结构,它真的很香:

配图

src/
  ├── modules/
  │     ├── user/       // 用户模块:只负责用户相关逻辑
  │     ├── order/      // 订单模块:通过接口调用User,不查User表
  │     └── payment/    // 支付模块
  ├── shared/           // 共享基础设施
  └── Application.java  // 一个启动类,打一个包,部署只需一分钟

这种架构不仅保留了单体架构部署快、测试方便、无网络开销的优点,未来如果某个模块(比如订单量暴增)真的需要独立,直接把那个包拆出去微服务化也非常容易。

我有个习惯,每周五下午抽出两小时,专门检查各个模块之间的依赖关系。如果发现Order模块直接Import了User模块的DAO层,那就算是个严重的“架构事故”,必须当场修正。这种人为的“纪律约束”,比引入Docker和K8s要管用得多。

中间件选型:越无聊越好

在技术选型上,我现在的原则是:选择那些“无聊”且经过实战检验的技术,而不是Github上Star增长最快的技术。

去年有个做物联网的小伙伴问我,要不要上ClickHouse来处理设备日志?他们每天大概有500万条数据。

我问他:“你们现在的PostgreSQL遇到瓶颈了吗?” 他说:“还没,查询有点慢,但能接受。”

我给出的建议是:别换。 给PostgreSQL表做个分区,加好索引,或者定期归档冷数据。

引入ClickHouse意味着你需要维护一套新的运维体系,你的团队需要学习新的SQL语法,你需要处理数据同步的延迟。对于一个只有3个后端的小团队,这些隐形成本是致命的。

架构师的能力,不体现在你会用多少复杂的工具,而体现在你能否用最简单的工具解决复杂的问题。

如果MySQL能抗住,就别引Redis;如果单机Cron能解决,就别上分布式调度中心。在这个阶段,数据一致性和开发效率,远比那所谓的“高并发扩展性”重要。

够用就好,是放过自己

我也曾焦虑过,看着大厂的架构分享PPT,觉得自己做的东西太low。但随着年岁增长,看着一个个项目因为过度设计而烂尾,一个个团队因为技术债而分崩离析,我才明白:

架构没有高低之分,只有适合与否。

当你能用最简单的技术栈,快速支撑起业务的百倍增长;当你能让团队成员并在晚上8点前准时下班,而不是通宵修补复杂的分布式Bug时,你就是这个团队最好的架构师。

配图

最后,想邀请大家做个选择: 在项目初期,你更倾向于哪种方案? A. 直接上微服务,为未来可能的百万用户做准备,哪怕初期开发慢点。 B. 先做单体,跑通业务,遇到瓶颈再拆分,哪怕未来重构痛苦点。 (欢迎在评论区告诉我你的答案)

给架构师/资深开发的3个落地建议:

  1. 定期“做减法”:下周一上班,检查一遍你的依赖库,删掉那些三个月没用过的中间件和废弃代码。
  2. 设立“复杂度红线”:引入任何新组件前,要求提出者写一个文档,回答三个问题:为什么现有技术解决不了?引入后的运维成本谁来抗?回滚方案是什么?
  3. 关注业务数据:哪怕是纯技术人员,也要盯着DAU和QPS看。如果QPS只有50,请把那套复杂的缓存层代码删了吧,直接查库真的很快。