16 Comments

  1. 我觉得关键是一致性,领域事件本质是引入观察者设计模式进行解耦,如果强行让两个聚合根 分开在两个事务当中,我并没有看到优点,在小型系统中 引入两阶段提交 三阶段提交这些复杂的东西,反倒是让原本简单的东西 变复杂了

  2. Angus

    在保存Order聚合根的时候,如果有OrderCreated事件和多个OrderUpdated事件要发出,如何在事件消费端确保按顺序接受事件,即先收到OrderCreated事件再收到OrderUpdated?

    • 滕云

      这是使用消息机制的常见问题,与具体所使用的消息中间件相关,比如kafka需要保证相关消息落在同一个分区中并且消费组中只有一个consumer,其他的中间件由于架构不同所采用的对顺序消费的保证方式也不同,建议查阅中间件对应的技术文档。

    • sunxiansong

      我提供一个思路。我们采用了轻量化无状态的broker服务(NATS),即trigger and forget, 消息中间件不会持久化消息。

      有点类似tcp的丢包检查、重传。消息需要增长的序列号(或者链式的序列号),消费者通过序列号来检测消息顺序和消息丢失,并保存消费序列号的进度。如果发现消息丢失则要求重传(也是通过消息)。在非顺序抵达的情况下,消费者需要缓存新的消息直到老的消息抵达。发送端先在数据库存储消息,后发送消息,发送消息需要严格按照序列号推进。

      这样可以保证发送和消费都按照消息的产生顺序执行。但有个问题不太好解决,那就是分布式环境下的多消费者顺序消费问题。

  3. 话说领域事件的发布方式是不是得分两种?一种是通过文中所说的订阅-发布模式,另一种是通过观察者模式?订阅-发布模式与观察者模式还是有些区别的,订阅-发布模式是完全解耦的,通过broker(或是中间件)来调度。。而观察者模式是松耦合且存在一定依赖的,subject知道observer interface的存在。。

    所以我想了解一下,这两种模式是不是都能用在DDD中?最近在做到DDD中的领域事件发布,比较纠结用哪种模式。。好像可以结合一起用。。跨应用的时候订阅发布最适合了吧。。笔者有没有这方面的经验传授一下?

    • 观察者模式的话,【每个】事件发布者需要自己控制事件的消费顺序、丢失事件的重发布,还有事件是同步消费还是异步消费。这往往导致代码拷贝之类的。

      感觉这类动作还是放到infrastructure里比较好,高内聚。

    • 滕云

      根据我的经验,我们很少使用观察者模式,并且这两个东西其实是相对的,举个例子,guava库中eventbus,从使用者的角度,没有耦合,你得到的是发布订阅,但是在eventbus内部实现确是使用的观察者模式。

  4. Edward

    看您写的伪代码示例里,在资源库中发布领域事件是在订单事务保存之前的,如果订单保存失败了,这时候领域事件已经发送出去,会产生一致性的问题。是否应该在应用层得到领域层保存成功的结果后(确保订单持久化成功),再发送领域事件(比如扣除库存、增加积分),这样做有什么问题吗?

  5. orange

    看IDDD书里也说领域事件是放在domain object的方法里发布的。这样做是必须的吗?
    为了方便和agg事务存储,放在AppService里发布可以吗?这样做会有问题吗?
    例如(Vanilla JS)
    class MobileAppService {

    async register(registeringMobileCommand) {
    … // some register mobile domain logic
    const event = new MobileRegistered(…)
    const session = await mongoRepo.startSession();
    await mongoRepo.withTransaction(session, async () => {
    await this.mobileMongoRepository.save(mobile, { session: session });
    await this.eventStore.save(event, { session: session });
    });
    domainEventPublisher.publish(event); // no await

    }

    • 滕云

      放在AppService中的问题是我们需要保证保存数据库和发送事件之间的原子性,如果你的项目可以容忍事件发送成功但是数据库更新失败的场景,那么这是OK的。

      • orange

        项目里约定了publish在save之后,agg和event的事务存储如果失败了,异常会导致api 500, 不会走到publish。 如果事务成功而publish失败,会有event publish error的专门处理。

      • orange

        另外publish失败问题,按郑晔老师在‘10x程序员工作法’里提到的案例做法,是保证消息中间件不会publish失败。是否微服内eventbus、微服务外mq的publish错误可以纳入基础设施的灾备(类似OOM,disk failure,http connection error),而不做应用层的特殊处理呢?

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据