"你们这个机器人租赁系统,为什么非要拆微服务?单体加个缓存不行吗?"这是评审会上被客户技术负责人问得最多的一句话。这篇不讲概念,只讲我们在设备租赁场景里被单体架构实际卡住脖子的三个瓶颈,以及最后是怎么拆的——机器人租赁系统和微服务架构这个组合,不是追时髦,是被业务逼出来的。


一、先说结论:单体没有错,错的是"单体扛所有负载"

我们第一版就是一个标准的 Spring Boot 单体:商品、档期、订单、支付、IoT 五个模块一个工程、一个库。上线前四个月跑得很顺,直到三件事几乎在同一季度发生:一场大型展会带来档期抢租热点、设备接入量突破两千台、第三家大客户提出深度定制需求。

事后复盘,单体的问题从来不是"代码多跑不动",而是三种完全不同的负载特征被强行塞进同一个进程、同一个库,互相拖累。下面逐个展开。
在这里插入图片描述

二、瓶颈一:档期热点并发,一个模块拖垮整个平台

档期查询是租赁平台天然的读热点:一台热门人形机器人挂在首页,每次曝光都要算"未来 90 天哪些天可租"。这还不算狠的,狠的是抢租——某展会客户开标当天,几十个竞标方同时抢同一批设备的同一段档期,写并发瞬间堆起来。

单体架构下的连锁反应是这样的:

档期接口变慢 → Tomcat 线程池被占满
→ 排在后面的订单查询、支付回调请求全部排队
→ 支付回调超时 → 支付网关重试 → 雪崩

支付回调被档期查询拖死,这是单体最典型的"连坐"事故。我们当时的临时手段是给档期接口单独限流,但限流阈值没法动态贴合业务波动——展会季和非展会季差着一个数量级。

拆分后的解法很直接:档期域独立部署,独立配置线程池、连接池和扩容策略。展会季前对档期服务单独扩容到 8 个实例,订单服务纹丝不动。资源按需分配,这才是可伸缩的本意。

三、瓶颈二:IoT 高频写入,把交易库写成了"慢库"

第二个瓶颈更隐蔽。两千台设备按每台 30 秒一次心跳 + 定位上报算,QPS 大约 70,看起来不高?错。设备网络抖动会触发客户端重传,充电桩状态变化会批量上报,实际峰值写 QPS 能冲到 2000+,而且全是 INSERT,落的就是那个共享的 MySQL

后果是:

  1. binlog 和磁盘 IO 被遥测写入占满,交易事务的提交延迟从 2ms 涨到 40ms;
  2. 慢查询日志里全是设备状态表的写入等待锁超时;
  3. 每天几十 GB 的遥测数据让备份窗口越拖越长,DBA 第一个提刀来见。

设备遥测是"写多读少、允许容忍丢失、按时间查询",交易数据是"写少读多、一条都不能丢"。这两种数据的存储引擎、备份策略、容量规划本该完全不同。拆出 IoT 服务并接入时序数据库后,遥测流量进 TDengine,交易库的写入延迟回到正常水位,备份时间缩短了三分之二。

四、瓶颈三:多商家个性化扩展,主干代码变成"补丁山"

前两个瓶颈是性能问题,第三个是工程问题,往往更致命。

平台化之后,每家租赁商都有自己的"特殊要求":某连锁酒店集团要求押金走自己的会员余额体系;某展会服务商要求订单审批加一层内部确认;还有客户要求按小时计费而不是按天。单体的做法通常是在订单模块里加 if (tenantType == XX) 分支——三个月后,订单核心流程里埋了 40 多个租户分支,每次改价格策略都要全量回归,发布周期从一周拖到半月。

这不是代码风格问题,是变更隔离问题:不同商家的需求变更频率和方向完全不同,却被编译进同一个部署单元。拆分后按业务能力划域,个性化诉求通过两种手段消化:

  • 扩展点机制:定价、押金、审批流程定义 SPI 扩展点,租户定制实现独立打包;
  • 配置驱动:能配置的不写代码,价格策略、工单流程做成租户级配置项。

五、拆分边界怎么划:按业务能力,不按技术分层

决定拆之后,第一件最容易做错的事就是按"controller/service/dao"或按前端/后端拆——那是分布式单体,除了多了网络开销什么都没得到。我们的拆法是按业务能力:

服务 职责 独立伸缩的理由
商品服务 机型、设备档案、定价 读多写少,缓存友好
档期服务 预占、冲突检测、日历 并发热点,独立扩容
订单服务 状态机、履约编排 交易核心,稳定性优先
支付服务 收付、押金、分账 安全合规要求独立
IoT 服务 设备接入、影子、围栏 高频写入,独立存储
工单服务 维修、纠纷 变更频繁,快速迭代

每个服务对应独立的数据库 Schema,禁止跨服务 JOIN,禁止直接读别人的表。服务间调用分两类:同步用 OpenFeign(查询类、强一致校验类),异步用 RocketMQ 事件(订单状态变更、设备事件广播)。

数据一致性放弃分布式事务的强一致幻想,采用最终一致 + 对账兜底:以订单服务的事件为准发广播,下游服务本地事务消费 + 幂等表去重;每小时跑一次跨服务对账任务,差异记录进告警群。上线至今对账发现过的最大一次不一致,是消息积压导致的 20 分钟状态滞后,业务上完全可接受。

六、什么时候才值得拆:给单体的辩护词

必须泼一盆冷水:过早微服务的成本,比单体瓶颈的代价更高。拆分意味着分布式事务、链路排查、运维复杂度、基础设施成本全面上升。我们的建议触发线:

  • 设备接入量超过 1000 台,或者遥测写入开始影响交易库 P99;
  • 出现过一次"热点模块拖垮全局"的真实事故;
  • 服务 5 家以上租赁商且定制需求开始污染主干;
  • 团队规模 8 人以上,单仓库协作开始互相阻塞。

三条以下,老老实实单体 + 模块化边界(包隔离 + 接口层收敛),把拆分的"预备动作"做扎实:领域边界清晰、服务间只走接口、事件模型提前定义。做到这三点,将来拆分就是"搬代码",而不是"重新设计"。

七、总结

  • 单体的三大瓶颈本质是负载特征冲突:抢租并发、IoT 高频写、租户差异化变更,三类流量互不相容;
  • 拆分按业务能力划边界,档期、IoT、订单是设备租赁平台最先需要独立伸缩的三个域;
  • 服务间通信:同步查询走 Feign,状态变更走 MQ,一致性靠事件 + 幂等 + 对账三件套;
  • 拆分有明确的触发条件,避免过早微服务;单体阶段的模块纪律是未来拆分的最大资本。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐