我经常看到的单体架构问题之一是组件之间的紧耦合,这导致系统不同部分之间存在依赖关系。模块化单体通过定义良好的模块边界和通信模式来强制执行更好的架构实践。
但一个你不能忽视的方面是模块之间的数据隔离,数据隔离确保模块相互独立且耦合度低。
今天,我将向你展示模块化单体的四种数据隔离方法:
- 分离表
- 分离模式
- 分离数据库
- 不同持久化
为什么数据隔离很重要?
首先让我们了解在模块化单体架构中为什么数据隔离很重要。
模块化单体对数据完整性有严格的规定:
- 每个模块只能访问自己的表
- 没有共享表或对象的情况
- 只允许在同一模块的表之间进行连接
模块化单体中的模块应该是自包含的。每个模块处理自己的数据。其他模块可以使用模块的公共 API 访问该数据。
这种设计有哪些好处呢?
保持模块相互隔离有助于促进模块化和松耦合。引入新的系统更改变得更容易。在组件松耦合时,副作用会减少。
如果你使用关系数据库,你仍然可以保持参照完整性。提取表时移除外键不是问题。
等级 1 — 分离表
最简单的解决方案是在数据库级别没有隔离。所有模块的表都存储在一个数据库中。很难确定哪些表属于哪个模块。
我只是出于完整性考虑提到这种方法。
然而,表越多,保持它们在模块之间的隔离就越困难。
你可以通过在表之间添加逻辑隔离来改进这一点。
等级 2 — 分离模式
在数据库中分组相关的表是引入逻辑隔离的一种方式。你可以使用数据库模式来实现这一点。每个模块都有一个包含该模块表的唯一模式。
现在,很容易区分哪个模块包含哪些表。
使用多个 EF Core 数据库上下文是实现此目的的一种简单方法。
你还可以引入规则来阻止从其他模块查询数据。例如,你可以使用架构测试来实现这一点。
在构建模块化单体时,我总是从逻辑数据隔离开始。
但如果这还不够呢?
等级 3 — 分离数据库
下一个数据隔离级别是将每个模块的数据移至单独的数据库。与使用模式进行数据隔离相比,这种方法有更多的约束。
如果你需要模块之间严格的数据隔离规则,这是正确的方法。但是,缺点是操作上更加复杂。你必须管理多个数据库的基础设施。
然而,这是提取模块的绝佳步骤。
首先,你将要提取的模块的表移动到单独的数据库中。这也迫使你解决模块之间的任何数据库耦合问题。一旦将表移动到单独的数据库,你就准备好提取该模块了。
我们能否进一步实现模块数据隔离?
等级 4 — 不同持久化
谁说你必须为所有模块使用相同的数据库类型?
我大多数时间都使用关系(SQL)数据库。关系数据库很棒,解决了各种问题。但有时,文档或图形数据库是更好的解决方案。
这里的思路类似:使用单独的数据库进行数据隔离。
但是,你可以引入不同的数据库类型来解决特定问题。例如,你可以为一个模块使用关系数据库,而为另一个模块使用图形或列存储数据库。你还必须在应用程序中维护不同的持久化模型。
对于你的使用案例来说,这可能是一种有价值的
权衡。但需要仔细规划。
总结
如果你暂时不需要微服务,模块化单体是一个很好的选择。你可以将应用程序作为单体进行开发,并在系统内部建立明确的边界。你仍然可以提取模块并转移到微服务。但是模块化单体可以更快地进行开发。
模块必须遵守一些规则。它们只能访问自己的表。它们不能与其他模块共享表。它们不能直接查询其他模块的表。这些规则有助于实现模块之间的数据隔离。
但是你仍然必须在数据库级别实现数据隔离。
有四种选项供你选择:
•分离表•分离模式•分离数据库•不同持久化
我总是选择使用模式进行逻辑隔离。这很容易实现,并帮助我更好地理解我的边界。根据要求,我可以随后引入单独的数据库。希望这有所帮助。