【问题标题】:DDD in a modular monolith. How Consistency is Maintained?模块化单体中的 DDD。如何保持一致性?
【发布时间】:2021-10-25 21:30:58
【问题描述】:

我有三个有界上下文:

  1. 商业
  2. 库存
  3. 财务部门

每个都有其适当的领域层、应用层、数据库等。 当商务部门销售或订购某物时,库存部门需要增加或减少库存中存在的产品数量的价值,财务部门需要从交易中支付或收款。

我读到,在 微服务 中,我应该使用像 kafka 这样的事件驱动。 但是在一个模块化的单体中我应该怎么做呢?

我的第一个想法是为每个部门发出一个 http 请求,但如果一个失败,数据库一致性将丢失。
如果我应该用代码来做,我应该把它放在哪里? (应该是工作单元之类的?)提前致谢。

【问题讨论】:

    标签: java spring domain-driven-design


    【解决方案1】:

    在模块化单体中我应该怎么做?

    通常的答案是“消息传递”。

    模块使用自己的本地信息副本自行做出决定。一个模块是它自己决定的权威(“现在答案是 7!”),但依赖于来自外部的信息副本(“我不知道现在的答案是什么,但我收到了一个说明 5 分钟以前的答案是 7")。

    当商务部门销售或订购某物时,库存部门需要增加或减少库存中存在的产品数量的价值,财务部门需要从交易中支付或接收资金。

    是的,但这些需求通常不是即时的。拥有(可能是隐含的)服务级别更为常见:对于五个 9,我们希望在 1 毫秒或其他任何时间内在模块之间复制信息。

    (如果您在处理具有实物库存的领域尤其如此,因为在尝试使仓库的数字模型与实物仓库保持一致时通常会有一些延迟)。

    推荐阅读:帕特·赫兰德


    如果模块之间有可靠的消息传输,那么通信相对容易。我做出决定,我将决定的副本发送给您,您做出决定。

    我的第一个想法是为每个部门发出一个 http 请求,但如果一个失败,数据库一致性将丢失。

    当模块之间没有可靠的消息传输时,生活会变得更加复杂。一种常见的方法是使用拉,而不是推。你问我从你收到的最后一条消息开始的一批消息,我填写这些细节;当您将这些消息复制到本地后,您可以请求另一批。

    加上一点额外的簿记,以确保在出现问题时不会两次处理重复的消息。

    【讨论】:

      【解决方案2】:

      在模块化单体中,您应该将模块(有界上下文)视为可独立部署的单元。理想情况下,模块之间没有依赖关系。如果需要,您应该可以随时轻松地将其拆分为微服务。 在事件方面,是的,依赖最终一致性是一个好主意,并且在您的情况下使用集成事件是有意义的。但是,使用 Kafka 在同一存储库中并在同一台机器上运行的两个模块之间交换消息是有点开销的。我的建议是创建一个两个模块都将实现的事件总线接口。该实现可以是内存中的事件总线。 如果在某一时刻您需要拆分单体并单独部署一个模块(例如:出于可伸缩性原因),您可以将实现从内存切换到 Kafka 之类的东西。 在这个 repo 中完成了模块化单体的类似实现:https://github.com/kgrzybek/modular-monolith-with-ddd

      【讨论】:

        【解决方案3】:

        一般来说,您在单体应用中的选择与在微服务中的选择相同:

        • 您可以选择更最终一致的方法并使用领域事件来触发其他有界上下文中的更改。

        • 您可以使用 saga,它也将最终保持一致(因为聚合定义了您的一致性边界并且不跨越边界上下文,所以会有可观察的时间窗口,其中一个边界上下文已更新以反映新信息,而另一个没有),但由于更新过程现在是模型中的可跟踪实体,因此您可以采取适当的措施。

        例如,“进行销售”传奇可能需要(假设商业部门已最终确定要出售的物品):

        • 使用库存服务保留要出售的商品,以防止商品被两次出售(请注意,最好向业务专家询问是否更愿意在没有库存时偶尔进行销售,或者只是如果库存可能不存在,则拒绝进行销售...取决于您所销售的产品,答案可能是任何一种方式)
        • 预留库存后,安排财务部门收款
        • 一旦收到付款(无论这意味着什么),请使用库存服务(注意:库存服务可能不是一个好名字......仓库或履行之类的东西可能更适合域语言)删除库存中的物品

        在每个步骤中,您可能偶尔会遇到失败,您需要决定是等待并重试还是将整个操作声明为失败并回滚前面的步骤(例如,如果库存服务无法完成订单(也许仓库里有人带着商品潜逃,而没有礼貌地调整库存),您必须让财务部门取消/退还账单并取消库存。 .. 或者您可能将其视为一种特殊情况,即您向人类发出信号以提出可行的解决方案),并且如果失败足够多,那么传奇就会向某人发出信号以手动解决问题。

        传奇本身将是您域中的实体/聚合,具有自己的持久状态。

        【讨论】:

          猜你喜欢
          • 2015-07-14
          • 2016-05-05
          • 1970-01-01
          • 1970-01-01
          • 2018-08-30
          • 2023-03-27
          • 1970-01-01
          • 1970-01-01
          • 2020-05-18
          相关资源
          最近更新 更多