DDD学习随笔——聚合的技巧 1

聚合在领域驱动设计中是非常重要的概念,在划分聚合时,可能听说过以下几种原则:

  • 生命周期一致性原则

  • 问题域一致性原则

  • 场景一致性原则

  • 聚合应该尽可能的小

然而,这些原则有时候仍然太过抽象,在选择时令人举棋不定,例如这样一个DevOps系统。

DDD学习随笔——聚合的技巧 1_第1张图片

基于生命周期一致性原则,它们应该被划分成一个聚合;基于场景一致性,它们又不应该被划分成一个聚合。如果划分成一个聚合,虽然更容易保证一致性,但又不利于并发的实现。那么,我们应当如何抉择呢?

Eirc 在DDD书中提到:

“在具有复杂关联的模型中,要想保证对象更改的一致性是很困难的。不仅互不关联的对象需要遵守一些固定规则,而且紧密关联的各组对象也要遵守一些固定规则。然而,过于谨慎的锁定机制又会导致多个用户之间毫无意义地互相干扰,从而使系统不可用。”

从这段话中,我们看到关键的问题在于:如何保证一组具有复杂关联的对象在修改时的一致性。此时,我们不妨扣一扣字眼。这里的“一致性”到底指什么?

联想分布式系统下我们常常挂在嘴边的“强一致性”和“最终一致性”,我们发现,在一组相互关联的对象之间,也可以这样来归类。有些关联关系要求在任何时刻都必须满足,而有些关系,则只需要在特定的场景下满足就可以了。

那些必须时刻满足的关系,被称为“不变式” 或 “固定规则” (invariant),通常我们采用函数的形式来体现,以便时刻维持对象之间的关系,这样的关系具备明显的事务特征:原子性、一致性、隔离性和持久性(ACID)。

而那些不必时刻满足的关系,则可以通过事件或其他的机制来维持。这意味着这些关系可以容忍软状态,并能够通过一些机制来达到最终一致。

这样,我们再重新来思考上面的DevOps模型该如何划分聚合

DDD学习随笔——聚合的技巧 1_第2张图片

“流水线”和“资源池”虽然都明确的归属在“项目”之下,但“流水线”和“项目”间没有“固定规则”时,我们可以将它们划分成不同的聚合。此时,一个项目下的多个流水线就可以并发被操作。当“项目”被删除时,“流水线”也需要被一同删除,但我们可以考虑一下,这个删除的动作是否必须事务性的完成呢?由于“项目”本身关联着大量的资源,并依赖外部系统。删除并不是一个能够被即时完成的操作,而会是一个持续的状态,它可能是下面这样一个步骤:

  1. 设定“项目”为删除中,使用消息机制通知“运行资源”和“流水线”执行删除;

  2. “流水线”和“运行资源”经过多次重试,完成删除,通过消息机制通知“项目”完成删除;

  3. 删除“项目”。

我们划分聚合时,应该考虑的是聚合对外暴露的操作的事务范围。一个聚合通过聚合根对外暴露的操作应该具有相同的事务范围。从而能够使得通过聚合根提供合理的事务机制。对象间的关联关系本身就包含了“归属关系”,因此聚合的主要作用不是用来表达一组对象之间的归属关系,而是为了处理对象间复杂关系的一致性问题。

你可能感兴趣的:(学习,架构)