一张互相绕圈的调用图
拆完半年,架构图变成毛线球:订单服务调商品服务拿价格,商品服务反过来调订单服务查销量,库存服务两边都要问一句。改一个运费规则,评审发现要动四个服务;一次大促压测,得把整条链上的服务全部拉起来。这不是微服务,这是把单体拆开了部署。
问题不在拆,在刀口。按技术分层切(一个订单服务、一个商品服务、一个通知服务),或者按代码顺手切,业务概念的缝隙就会长成服务之间的缝隙。这一篇讲怎么让边界跟着业务走,而不是跟着代码走。
限界上下文:同一个词,几个意思
DDD 里实战价值最高的概念是限界上下文:同一个业务名词,在不同上下文里含义不同,就该是不同的模型。"商品"在目录上下文里是名称、图片、详情页;在库存上下文里只是可售数量与仓库位置;在营销上下文里是价格与促销规则。三个"商品",三套模型,各归各的服务——硬捏成一个商品中心大服务,每次改动都要给三方让路。
找上下文的实操办法:拉着业务方把核心流程的事件列出来——订单已创建、库存已扣减、优惠券已核销——事件归属清楚的地方就是上下文的墙,事件说不清归属的地方,多半是边界还没想清楚。
粒度:宁粗勿细
方向定了,粒度看三条:能力内聚——一个服务对外提供一个说得完整的能力,改一个常见需求的改动尽量落在一个仓库;团队规模——一个服务配一个吃得住它的团队;数据内聚——一个服务的数据尽量落在同一个事务边界里。先拆粗一点,跑半年按痛点再拆细,好过一上来拆出二十个微型服务。
| 维度 | 拆太细的信号 | 拆太粗的信号 |
|---|---|---|
| 发布粒度 | 改一行要发三个服务 | 任何需求都要回归全量 |
| 调用拓扑 | 同步调用绕环、层层深 | 服务之间几乎不调用 |
| 数据边界 | 一个事务穿两个库 | 十个业务挤一张大表 |
数据归属:谁的数据谁说了算
服务边界画完,数据边界跟着画:每个服务独占自己的库,别的服务要用,走接口或事件,禁止直连别人的表。共享表是分布式单体的头号元凶——表结构一动,四个服务同时哑火。跨服务读数据先分两类:强一致的走同步调用并备好降级,最终一致的走事件,让数据以副本形式流过去。
// 反例:跨服务直连库(共享表)
orderMapper.insert(order); // orders 表
inventoryMapper.deduct(skuId, n); // 直接写库存服务的表 —— 禁止
// 正例:各自写自己的库,跨域走 API 或事件
orderService.create(order); // 订单域写自己的库
eventBus.publish(new OrderCreatedEvent(order)); // 库存域订阅事件自行扣减验收边界的三个问题
边界草案出来,用三个问题验收:这个服务的能力能用一句话说清吗——说不清就是拆散了;改一个常见需求要动几个服务——超过两个就要警惕;它挂了影响谁——影响面要和业务重要性匹配。三问都过,边界才算立住。下一篇进入基础设施:实例天天变,调用方去哪找到彼此。
评论 (0)