3、服务拆分策略:按业务能力拆分、按子域拆分、因子工厂的服务边界识别、拆分粒度控制
服务拆分,说白了就是「怎么把一个大家伙切成小块」。
这块我踩过不少坑。刚做微服务那会儿,我恨不得把每个类都拆成一个服务。结果呢?运维想哭,调用链乱成一锅粥。后来才明白——拆分不是目的,目的是让每个服务能独立演进、独立部署。
3.1 两种主流拆分方式
业界常见的拆分思路,其实就两条路:按业务能力拆,或者按子域拆。我个人的习惯是,两条路结合着用。
3.4.1 按业务能力拆分
什么叫业务能力?就是「这个服务能干啥」。比如用户服务能注册登录、订单服务能下单支付、库存服务能扣减库存。每个服务对应一个独立的业务能力单元。
这种拆分方式很直观。我在做电商平台时,第一版就是这么干的。用户、商品、订单、支付,各管各的。好处是团队分工明确,前端调用也清晰。
3.4.2 按子域拆分
这个来自领域驱动设计(DDD)。说白了,就是把业务领域拆成多个子域,每个子域对应一个服务。
举个例子,电商里有「商品管理」这个核心域,还有「物流追踪」这个支撑域,还有「用户积分」这个通用域。每个子域的边界清晰,变化原因也不同。
我记得有一次,我们按子域拆完后,发现「订单」和「支付」之间有个模糊地带——退款。到底归谁管?后来我们单独抽了一个「退款服务」,才把这事理清楚。
| 拆分方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 按业务能力 | 业务边界清晰、团队独立 | 简单直接、易于理解 | 容易忽略领域内聚性 |
| 按子域 | 复杂业务、需要领域建模 | 边界合理、变化隔离 | 建模成本高、学习曲线陡 |
3.2 因子工厂的服务边界识别
好,理论说完了。咱们来看看「因子工厂」这个具体案例。
因子工厂是干啥的?它负责生成各种风险因子、策略因子。比如信用评分里的收入因子、负债因子,风控里的欺诈因子。每个因子背后都有一堆计算逻辑和数据源。
我当初设计时,第一反应是「一个因子一个服务」。但仔细一想,不对。因子太多了,几百个因子就几百个服务?运维直接炸了。
后来我用了三步法来识别边界:
- 找聚合根:哪些因子经常一起变化?比如「收入因子」和「职业因子」都依赖用户收入数据,可以放一起。
- 找变化频率:有些因子每天更新,有些每月更新。变化频率不同的,拆开。
- 找数据依赖:如果两个因子依赖同一张数据表,那它们很可能属于同一个服务。
最终,我们把因子工厂拆成了这几个服务:
- 基础因子服务:收入、负债、资产等基础数据因子
- 衍生因子服务:基于基础因子计算出来的复合因子
- 策略因子服务:跟具体业务策略绑定的因子,比如「首单优惠因子」
- 因子配置服务:管理因子的元数据、版本、生效时间
嗯,这里要注意。边界不是一成不变的。随着业务发展,你可能需要合并或拆分。我见过一个团队,一开始把「因子配置」放在基础因子服务里,后来配置逻辑越来越复杂,不得不单独抽出来。
3.3 拆分粒度控制
这是最让人头疼的部分。拆太细,服务间通信成本高;拆太粗,又回到了单体应用。
我总结了一个「三问法」来控制粒度:
- 这个服务能独立部署吗? 如果不能,说明拆得不够。
- 这个服务需要跟多少个其他服务通信? 如果超过5个,说明拆得太细了。
- 这个服务的数据是独立的吗? 如果跟别人共享数据库,那边界有问题。
还有一个经验:先粗后细。刚开始可以拆得粗一点,运行一段时间后,根据监控数据再决定要不要进一步拆分。别一上来就追求完美。
你想想看,一个服务如果只有几十行代码,那它真的需要独立成一个服务吗?不一定。有时候一个模块就够了。
3.4 因子工厂的拆分实践
最后,我分享一下因子工厂的实际拆分案例。
最开始,我们只有一个「因子计算服务」,里面塞了所有逻辑。后来发现,每次改一个因子的计算逻辑,都要全量部署,风险太大。
于是我们按「因子类型」拆成了三个服务:
- 数值因子服务:处理数值型因子,比如金额、比例
- 枚举因子服务:处理枚举型因子,比如职业类型、学历
- 文本因子服务:处理文本型因子,比如地址、描述
每个服务内部,又按「因子组」分了模块。比如数值因子服务里,有「收入组」「负债组」「资产组」。
这样做的好处是:
- 修改收入因子,只影响数值因子服务
- 新增一个枚举因子,只改枚举因子服务
- 每个服务可以独立扩缩容
当然,也有代价。比如一个策略需要同时用到数值因子和枚举因子,那就得跨服务调用。不过这个代价是值得的——比起单体应用的一锅粥,这点通信成本不算什么。
好了,关于服务拆分,核心就是这些。记住一句话:拆分是为了更好的聚合,而不是为了拆分而拆分。