4、拆分方法论:DDD领域驱动设计在拆分中的应用、限界上下文的识别、子域的划分

好,咱们进入正题。微服务怎么拆?这是个大问题。很多团队一上来就按功能模块切,比如用户服务、订单服务、支付服务。结果呢?拆完发现服务之间耦合严重,改一个需求要联动五六个服务。我见过太多这样的案例了。

那有没有一套成熟的方法论?有。就是DDD,领域驱动设计。说白了,DDD就是帮你搞清楚“业务边界”在哪,然后按边界去拆。今天我就把我在几个大型项目中用DDD拆服务的经验,掰开了讲给你听。

4.1 为什么DDD适合微服务拆分?

先问个问题:微服务拆分的核心难点是什么?

不是技术,是边界。你想想看,两个服务之间如果职责不清,A服务改了数据库表结构,B服务就挂了。这就是边界没划好。

DDD正好解决这个问题。它从业务出发,把整个系统划分成若干个“领域”。每个领域有自己的业务逻辑、数据模型。领域之间通过明确的接口通信。这不就是微服务想要的吗?

我个人习惯把DDD和微服务的关系总结成一句话:DDD负责划地盘,微服务负责守地盘

核心观点:DDD中的“限界上下文”天然对应微服务。一个限界上下文,就是一个微服务的最佳粒度。

4.2 限界上下文的识别——这是最关键的一步

限界上下文是什么?我举个例子你就明白了。

同样是“用户”这个概念,在电商系统里,订单上下文中的“用户”关注的是收货地址、积分;而在客服上下文中,“用户”关注的是投诉记录、历史工单。虽然都叫用户,但含义完全不同。

这就是限界上下文——每个上下文里,模型有自己独特的含义和规则。边界一旦模糊,代码就乱套了。

4.2.1 识别限界上下文的三个步骤

我在项目中一般按这三步走:

  1. 梳理业务流程——把核心业务场景画出来,比如下单、支付、发货、退款。
  2. 找“语言差异”——同一个词在不同环节含义是否不同?如果有,就是边界。
  3. 确定上下文——每个有独立语言和规则的业务模块,就是一个限界上下文。

举个例子。我之前做一个电商平台,发现“商品”在“商品管理”和“订单”两个模块里,属性完全不同。商品管理里的商品有SKU、库存、价格;订单里的商品只有快照(下单时的价格、名称)。这就是两个限界上下文。

小技巧:你可以让业务人员用“统一语言”描述流程。如果他们描述同一个概念时用了不同说法,那大概率就是边界。

4.3 子域的划分——把大问题拆小

限界上下文是“横向”的边界。子域是“纵向”的层次划分。DDD把领域分成三类:

子域类型 说明 例子
核心域 公司最核心的竞争力,必须自己做 电商的订单、支付
支撑域 重要但不是核心,可以自研或外包 权限管理、通知
通用域 通用能力,直接买现成的 短信、邮件、日志

为什么要分这个?因为资源有限。你不可能每个服务都投入同样精力。核心域要精雕细琢,通用域能省则省。

我记得有一次,团队非要把“短信发送”做成一个高可用的微服务,花了两个月。我说,这玩意儿买个云服务不香吗?后来他们算了下成本,确实不值。

4.3.1 如何划分子域?

我的做法是:先画业务全景图,然后问三个问题:

  • 这个模块如果出问题,公司还能正常运转吗?——核心域
  • 这个模块有没有行业标准方案?——通用域
  • 剩下的,就是支撑域。

嗯,这里要注意:核心域不一定只有一个。比如电商的核心域可能是订单+支付+商品。但别超过三个,否则说明你还没想清楚。

避坑指南:我曾经见过一个团队,把“用户登录”也划为核心域,投入大量资源做单点登录。其实登录是通用域,用OAuth2.0或者第三方认证就够了。别把力气用错地方。

4.4 从DDD到微服务——落地实操

理论说完了,咱们看看怎么落地。我一般分四步:

  1. 事件风暴——拉上业务和技术,一起贴便签纸,把业务流程中的事件、命令、聚合都找出来。
  2. 画限界上下文——根据事件风暴的结果,圈出每个上下文的边界。
  3. 划分子域——给每个上下文打标签:核心、支撑、通用。
  4. 映射微服务——一个限界上下文,对应一个微服务。核心域的服务优先做,通用域的服务能复用就复用。

举个例子,我之前做的一个物流系统,通过事件风暴找出了“订单创建”、“分配快递员”、“取件”、“签收”等事件。然后圈出了“订单上下文”、“配送上下文”、“签收上下文”。最后,核心域是“配送”,支撑域是“订单”,通用域是“通知”。

最终拆成了三个微服务:配送服务、订单服务、通知服务。每个服务独立部署,独立数据库。边界清晰,互不干扰。

关键原则:微服务之间只通过API通信,绝不共享数据库。这是底线。破了这条线,你拆了也白拆。

4.5 总结一下

DDD不是银弹,但它确实给微服务拆分提供了清晰的思路。你想想看,如果没有DDD,你拆服务靠什么?靠拍脑袋?那迟早要重构。

我个人建议,每个准备做微服务拆分的团队,都先花两周时间做一次事件风暴。别急着写代码,先把边界搞清楚。磨刀不误砍柴工。

好,这一章就到这里。下一章咱们聊聊具体的代码落地——聚合、实体、值对象,这些东西在微服务里怎么用。