DDD多租户设计

时间:2019-04-15 21:33:15

标签: architecture domain-driven-design

我正在设计一个通用的多租户身份系统(身份验证/授权),但是我是否对它的设计方式有所怀疑。

当前,设计是这样的:

AR 用户参考租户以及用户所属的特定组织单位。 AR 租户具有实体组织单位

的列表

在这种情况下,组织单位是描述组织的树形结构,例如Aphabet-> Google-> Development

我的问题是

组织单位应该是用户所引用的根实体吗?

我将其建模为 Tenant 的实体,因为如果没有 Tenant 组织单位将不存在,所以在我看来,< strong>组织单位不应该是AR。

任何指导表示赞赏

1 个答案:

答案 0 :(得分:2)

从您的问题来看,我不清楚您的应用程序应该是什么样子,它的目的是什么。你在建模什么?您可以提供更多详细信息吗?

据我了解,您的实体为:租户 OrganizationalUnit 用户

租户 OrganizationalUnit 之间有什么关系?看来 Tenant 应该包含许多 OrganizationalUnit ,但是 OrganizationalUnit 的目的是什么?是要对用户进行分组和组织(例如,在特定团队中工作还是在公司特定部门(开发,销售,设计等)的一部分时?

人们开始使用DDD时遇到的第一件事是集合。它们是最容易被误解的概念,很难理解。我认为,当一个人开始为应用程序建模时,他/她不应从尝试定义聚合开始。首先定义实体并阐明它们之间的关系。完成此操作后,请分析您的应用程序及其将遇到的技术问题,并考虑如何将您的实体组织为聚合来解决这些问题。

您阅读过DDD book by Eric Evans吗?如果您还没有,我强烈建议您。

作为一种模式,聚合用于解决几个问题(这不是完整的列表):

  • 为您的实体定义变更的事务边界。哪些实体应该整体上一起改变,哪些实体可以彼此独立地改变?当今大多数应用程序都是多用户的,因此您可能会进行并发操作(例如同时从不同的管理员 OrganizationalUnit 添加多个用户

  • 限制一个实体对其他实体的引用数量,因此当您从数据库中加载它们时,您不会加载一个包含1 000 0000个其他实体的集合的实体,这可能会导致服务器耗尽内存和崩溃。那不是很实际,不会起作用。

  • 阐明遍历方向。双向关联很难维护。例如,您可能有一个用户属于组织单位,而 OgranizationalUnit 包含许多用户,因此您拥有多对多的关系。加载一个具有所有 OrganizationalUnits User 并加载属于这些 OrganizationalUnits 的所有其他 Users 只是为了更改其名称用户不是很实用。

存储库可以为您提供帮助。如果要获取特定用户 OrganizationalUnits ,您将具有 OrganizationUnitRepository getOrganizationalUnitsForUser(userID)方法。如果要为 OrganizationalUnit 查找 Users ,您将具有 UserRepository getUsersForOrganizationalUnit(unitID)方法。这样,您将使用存储库遍历组织到聚合中的实体之间的关系。

首先从定义实体的关系开始,分析应用程序的问题,然后根据遇到的问题将它们组织在聚合中(如果不正确,请稍后重构)。

就您而言,您可以:

  • 让所有实体成为单独聚合的一部分,并使每个实体成为其聚合的根。有所有的存储库。在服务中,如果需要特定操作的实体,则将使用存储库检索多个实体。

  • 如果您不认为 Tenant 具有数千个 OgranizationalUnits ,则可以将其作为 Tenant 汇总的一部分并将它们加载在一起。在这种情况下,由于 OgranizationalUnits 是分层的,因此您必须将父级和子级一起加载。如果您不希望使用 ReferenceByID ,并且仅对每个 OgranizationalUnit 拥有一个具有parentID的属性,而不是加载子代和父代的集合。

将实体分配到不同集合的一个问题是一致性边界。这样,您必须在不同的聚合之间引入最终的一致性,并且难以实施某些规则。

例如,假设您限制了租户中可以包含的用户个用户。如果 Tenant 实体和 OrganizationalUnit 实体属于同一聚合,则它们位于同一一致性边界中。这样,您将加载聚合,进行检查,如果违反检查,则会引发错误,如果不添加 User 并保存聚合。在多用户情况下,如果两个管理员加载相同的聚合,并且每个人向 OrganizationalUnit 添加一个 User ,则在保存期间可以使用Optimistic Concurrency解决冲突,这样您的用户计数就不会超过限制。

如果将聚合细分为两部分,则它们将处于不同的一致性边界中,因此执行此规则将变得更加困难。这称为基于集合的验证。您可以搜索有关此主题的信息,但是很难找到任何信息,因此我无法指向任何地方。

如果您在设置验证方面遇到此类问题,并且可以使用群集实体而不会在加载它们时出现性能问题,则可以这样做,并且不要执行基于集合的验证

有关更多详细信息,您可以检查Effective Aggregate Design。它详细讨论了这些问题和解决方案。实际上,它也是模型的 Tenant 部分:)