You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD跨限界上下文聚合存在性校验:异步方案与HTTP通信疑问

问题背景

我在开发航空公司应用,划分了预订和用户两个限界上下文(Bounded Context):

  • 预订限界上下文的聚合结构:
export class Plane {
  id: UUID
  reservations: Array<Reservation>
  seats: Array<Seats>
  
  // 其他无关代码
}

export class Reservation {
    id: UUID 
    personId: UUID
    seatId: UUID
}

Plane是聚合根,Reservation是子实体。

  • 用户限界上下文的User实体:
export class User {
    id: UUID
    // 其他无关代码
}

创建预订的初始逻辑未校验用户存在性,后来改为同步HTTP调用用户服务校验,但存在两个问题:

  1. 微服务间同步通信增加耦合度;
  2. 校验后用户被删除,虽可通过DeletedUser事件后续移除预订,但处理方式不够直观,略显“取巧”。

核心疑问

  1. 如何将同步通信转为异步通信,同时避免数据竞争导致应用处于无效状态?比如担忧以下场景:
    1. 用户通过Plane聚合发起预订,未校验用户是否存在;
    2. 触发校验用户是否存在的事件;
    3. 用户服务返回“用户存在”事件;
    4. 用户被删除,用户服务触发“用户已删除”事件;
    5. 处理用户删除事件,移除Plane中的预订;
    6. 处理用户存在事件,为已删除用户创建预订。
  2. 微服务间通过HTTP通信是否属于不良实践?

解答

1. 异步通信下避免数据竞争的方案

要解决事件顺序错乱导致的无效状态问题,核心是通过状态管控、版本追踪或顺序保障来处理,以下是几个落地性强的方案:

方案一:先创建待确认预订,基于版本做冲突校验

  • 用户发起预订请求时,预订服务先创建一条待确认状态的预订记录,生成唯一requestId,并向用户服务发送CheckUserExists事件(携带requestId和userId)。
  • 用户服务返回UserExists事件时,附加用户当前的版本号userVersion;返回UserNotFound则直接标记预订无效。
  • 预订服务处理UserExists事件时,先核对待确认预订是否存在,再检查用户的最新状态:
    • 如果用户未被删除,且当前版本≥事件中的userVersion,则将待确认预订转为有效状态;
    • 如果已存在UserDeleted事件(且删除操作的版本大于UserExists中的版本),则直接取消该待确认预订。
  • 收到UserDeleted事件时,标记该用户所有待确认预订为无效,同时触发已生效预订的取消流程(释放座位、通知用户)。

方案二:用状态字段+定期巡检保障最终一致

  • 在预订表中新增user_valid字段,默认值为pending;
  • 发起预订时直接创建记录,同时发送CheckUserExists事件;
  • 收到UserExists则将user_valid设为valid,收到UserDeleted则设为invalid并触发取消流程;
  • 预订服务定期巡检user_valid=pending的记录,主动调用用户服务校验状态,避免因消息丢失导致的长期待确认。

方案三:基于消息顺序的因果处理

使用支持消息顺序的中间件(比如Kafka按userId分区+时间戳排序),给每个事件添加correlationId(关联同一业务流程):

  • 同一userId的事件会被分配到同一个消息分区,确保按生成顺序处理;
  • 预订服务处理事件时,先判断当前业务流程的最新状态,比如如果已经处理过UserDeleted,再收到UserExists就直接忽略。

2. 微服务间HTTP通信是否是不良实践?

不是绝对的不良实践,要结合业务场景判断:

  • 适合用HTTP的场景:

    • 必须同步获取结果才能继续的业务(比如你最初的用户存在校验,如果业务要求必须确保用户存在才能创建预订,同步HTTP是最直接的方式);
    • 低并发、对延迟不敏感的内部查询操作(比如获取用户基本信息);
    • 简单的跨服务调用,不需要复杂的事件驱动逻辑。
  • 不适合用HTTP的场景:

    • 高并发的通知类操作(比如订单创建后通知库存),同步HTTP会导致服务阻塞、吞吐量下降;
    • 依赖最终一致性的业务流程,同步调用会增加耦合,一旦依赖服务故障,当前服务也会受影响;
    • 事件驱动的复杂业务场景,异步消息队列更适合解耦和保障消息可靠性。

总结:HTTP通信本身没问题,关键是不要用同步HTTP实现跨服务的强依赖业务流程。如果可以用异步事件解耦,优先选择异步;但如果业务要求强一致性,同步HTTP调用是合理选择,此时可通过超时、重试、熔断等机制降低耦合风险。

内容的提问来源于stack exchange,提问作者JackG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:33:19