3、服务拆分实战:按业务能力拆分、按子域拆分、拆分粒度控制、拆分后的数据一致性挑战

好,咱们直接进入正题。服务拆分这件事,说起来好像就是「把一个大系统切成几块」,但真动手的时候,你会发现处处是坑。我这些年拆过的服务,少说也有几十个了,有的拆完系统跑得飞起,有的拆完反而比原来还慢。今天我就把那些实战中摸出来的经验,掰开了跟你聊聊。

3.1 按业务能力拆分:最直观的切法

什么叫按业务能力拆分?说白了,就是看你的系统能提供哪些核心功能。比如一个电商系统,能下单、能支付、能发货、能管库存,那这些就是它的业务能力。

我个人习惯,先画一张业务能力地图。把系统里所有的功能点列出来,然后归类。举个例子:

  • 用户相关的:注册、登录、权限管理
  • 商品相关的:商品发布、商品搜索、商品详情
  • 订单相关的:创建订单、订单状态流转、退款
  • 支付相关的:发起支付、回调处理、对账

每一类就是一个候选的服务。我在项目中遇到过,有人把「商品搜索」和「商品管理」拆成了两个服务。结果呢?搜索服务每次都要调商品管理服务的接口拿数据,延迟高得离谱。后来我们合并了,反而更清爽。

核心原则:一个业务能力,应该是一个完整的闭环。它内部的数据和逻辑,尽量不依赖其他服务。

3.2 按子域拆分:DDD 的落地玩法

按业务能力拆分,适合初期快速上手。但系统复杂了,你会发现有些能力边界是模糊的。这时候,我建议你引入领域驱动设计(DDD)里的子域概念。

DDD 把业务分成三类子域:

子域类型 说明 例子
核心子域 公司最赚钱、最核心的业务 电商的订单、支付
支撑子域 为核心业务服务的,但非核心 商品管理、库存管理
通用子域 所有系统都可能用到的 用户认证、通知、日志

你想想看,核心子域的服务,应该得到最好的资源、最严格的治理。通用子域的服务,可以直接买现成的,比如用第三方登录服务。我在一个项目中,把「通知服务」自己从头写了一遍,结果维护成本比核心业务还高。后来换成云服务,省心多了。

我的经验:先识别出核心子域,把它拆得足够细。其他子域,能合并就合并,别为了拆分而拆分。

3.3 拆分粒度控制:拆多细才算好?

这是最让人头疼的问题。拆得太粗,跟没拆一样;拆得太细,服务之间互相调来调去,延迟和复杂度都上去了。

我一般用三个维度来判断:

  1. 数据维度:两个功能如果频繁操作同一张表,就别拆。我见过有人把「订单创建」和「订单查询」拆成两个服务,结果每次创建完订单,要等数据同步到查询服务,用户刷新页面看不到新订单。这就是典型的拆错了。
  2. 变更维度:两个功能如果经常一起改,就别拆。比如「下单」和「扣库存」,它们几乎每次迭代都是一起改的。拆开之后,每次改完要同时发布两个服务,协调成本翻倍。
  3. 团队维度:一个服务最好由一个团队维护。如果团队只有5个人,你拆出10个服务,每个人要维护2个,那光是部署和排查问题就够受的。

避坑指南:我曾经把一个「用户服务」拆成了「用户基础信息服务」和「用户行为服务」。结果发现,每次展示用户页面,要调两个服务。后来我学乖了——服务拆分的粒度,应该以「一次业务请求,最多跨2-3个服务」为准

3.4 拆分后的数据一致性挑战

好,服务拆完了,问题来了。以前在一个数据库里,事务可以保证数据一致。现在数据分散到各个服务,怎么保证?

举个例子:用户下单,要扣库存、减余额、创建订单。这三个操作分别在三个服务里。如果扣库存成功了,但减余额失败了,怎么办?

这里有几个常见的方案:

方案 原理 适用场景 缺点
最终一致性(消息队列) 先发消息,异步处理 对实时性要求不高的场景 可能出现消息丢失或重复
TCC(Try-Confirm-Cancel) 预留资源,确认或回滚 对一致性要求高的场景 实现复杂,需要业务支持
Saga 模式 每个操作都有补偿操作 长事务场景 补偿逻辑容易遗漏
本地消息表 在本地数据库记录消息状态 中小型系统 需要轮询,性能一般

我个人最常用的是「最终一致性 + 消息队列」。为什么?因为大部分业务场景,用户能接受几秒钟的延迟。比如下单后,库存不是立刻扣减,而是等消息处理完再扣,用户感知不到的。

但要注意,消息队列本身也有坑。我记得有一次,消息队列挂了,结果订单创建成功了,库存没扣,导致超卖。后来我们加了个「对账系统」,每天跑一次,把不一致的数据找出来人工处理。

核心观点:拆分后的数据一致性,没有银弹。你要做的,是接受「最终一致性」,然后通过补偿、对账、监控来兜底。

3.5 实战中的几个小建议

  • 先别急着拆:我建议你先在单体架构里跑通业务,等确实遇到性能瓶颈或团队协作问题了,再动手拆。
  • 拆一个,稳一个:别一次性拆完。每次只拆一个服务,观察一段时间,没问题了再拆下一个。
  • 做好监控:拆分后,服务之间的调用链变长了。没有链路追踪,出了问题你根本不知道是哪个服务慢了。
  • 数据同步别用强一致:能用最终一致,就别用分布式事务。分布式事务的性能开销,比你想象的大得多。

最后说一句:服务拆分不是目的,目的是让系统更稳定、更易维护。如果拆完反而更复杂了,那还不如不拆。嗯,这个道理,我也是踩了好几个坑才明白的。