微服务边界为什么要结合限界上下文来划分?
简化版
微服务边界不能只按表、接口或技术模块划分,更应该结合业务能力和限界上下文。
限界上下文强调:同一个词在不同业务域里可能含义不同,每个上下文拥有自己的模型、规则和数据边界。
如果边界划得好,服务可以独立开发、独立发布、独立扩容,数据所有权清晰。
如果边界划错,就会出现跨服务事务多、接口互相套娃、共享数据库、频繁联调和分布式单体。
详细版
面试中可以从三个层次回答。
第一,业务边界。服务应该围绕稳定的业务能力拆分,例如订单、支付、库存、会员、营销,而不是简单按 Controller、Service、DAO 分层拆。
第二,数据边界。一个服务应该拥有自己的核心数据,其他服务通过 API 或事件获取数据,而不是直接读写它的表。
第三,变更边界。经常一起变化的能力可以先放在一个服务里,经常独立变化的能力才适合拆开。
业务能力
|
v
限界上下文 -> 数据所有权 -> 服务边界
|
v
API / Event 协作
可以这样比较:
| 拆分方式 | 问题 | 更好的做法 |
|---|---|---|
| 按表拆 | 业务流程跨很多服务 | 按业务能力聚合数据 |
| 按技术层拆 | 远程调用替代本地方法 | 保持服务内高内聚 |
| 按团队随意拆 | 边界随组织摇摆 | 结合业务域和变更频率 |
| 共享数据库 | 数据所有权不清晰 | 每个服务负责自己的数据 |
伪代码表达服务边界时,可以强调只能通过契约访问:
class OrderService:
def create_order(self, command):
order = Order.create(command)
self.order_repository.save(order)
self.event_bus.publish("OrderCreated", order.to_event())
return order.id
这里订单服务发布领域事件,库存服务订阅事件处理库存,而不是订单服务直接修改库存表。
完整版教学
一、先看这个问题为什么高频
微服务拆分是架构面试里最容易追问的题。
很多候选人会说按业务拆,但面试官继续问“业务边界怎么判断”时,就需要限界上下文、数据所有权、变更频率这些更具体的标准。
这道题真正考的是你有没有经历过服务拆细之后的协作成本。
二、限界上下文是什么
限界上下文来自领域驱动设计。
它强调模型只在特定上下文内成立。
例如“用户”在账号系统里关注登录名、手机号、密码和安全策略;在营销系统里关注会员等级、标签和优惠资格;在客服系统里关注工单、投诉和服务记录。
这些模型不一定应该放在同一个服务里。
三、为什么不能只按数据库表拆
按表拆看起来清晰,实际很容易造成跨服务事务。
例如下单同时涉及订单表、库存表、优惠券表、支付流水表,如果每张表都拆成一个服务,一次下单就会变成一长串远程调用。
远程调用越多,超时、重试、部分成功和排障成本越高。
微服务拆分的目标不是让服务数量变多,而是让业务边界更清楚、变化更独立。
四、服务边界要看数据所有权
一个服务应该拥有自己的核心数据。
其他服务如果需要这部分数据,应该通过接口查询、事件订阅、数据同步或读模型获取。
直接跨库读写会破坏边界,因为任何表结构变化都会影响多个服务。
如果多个服务都能改同一张表,就很难判断规则应该放在哪里。
五、服务边界要看变更频率
经常一起改的功能拆开,发布会变复杂。
经常独立改的功能放在一起,又会互相拖累。
所以拆分时要看需求历史和团队协作方式。
如果订单状态和支付状态总是一起变更,可以先保持较近的边界;如果营销规则经常独立迭代,就适合单独服务化。
六、拆分后的协作方式
服务之间通常有两类协作。
同步协作适合需要立即返回结果的场景,例如查询价格、校验库存。
异步协作适合不要求立即完成的场景,例如发送通知、更新积分、同步搜索索引。
同步调用要关注超时、重试、熔断和降级。
异步事件要关注幂等、顺序、重复消费和最终一致。
七、拆错边界的信号
如果出现这些信号,说明边界可能有问题:
- 一个需求每次都要改很多服务。
- 服务之间频繁同步调用。
- 多个服务共享同一个数据库。
- 大量字段只是透传,没有业务判断。
- 测试必须启动一整套系统。
- 发布必须多个服务同时上线。
这些都是分布式单体的典型表现。
八、常见误区与追问
- 误区:服务越小越好。 服务过小会增加网络、事务、测试和发布成本。
- 误区:限界上下文等于数据库表。 它描述的是业务模型边界,不是物理表边界。
- 误区:所有数据都实时查询源服务。 高频读场景可以通过事件同步构建读模型。
- 误区:共享数据库更方便。 短期方便,长期会让服务边界失效。
- 追问:拆分后跨服务查询怎么办? 可以用冗余字段、CQRS、搜索索引、数据同步或聚合服务。
- 追问:拆分后事务怎么办? 优先调整边界,其次考虑 Saga、可靠消息和补偿。
九、加强记忆
- 服务边界先看业务能力。
- 限界上下文定义模型含义。
- 数据所有权要清晰。
- 经常一起变的不要强拆。
- 跨服务事务多说明边界可能错了。
- 共享数据库会破坏自治。
- 拆分目标是高内聚、低耦合、可独立演进。