Microservices 播种微服务数据库

Microservices 播种微服务数据库,microservices,event-sourcing,Microservices,Event Sourcing,给定控制模型(产品)的服务A(CMS),让我们假设它仅有的字段是id、标题、价格)和必须显示给定模型的服务B(发货)和C(电子邮件),在事件源方法中,在这些服务中同步给定模型信息的方法应该是什么?让我们假设产品目录很少更改(但确实更改),并且有管理员可以经常访问装运和电子邮件的数据(例如功能有:B:显示订单中包含的产品标题,C:显示将要发送的装运相关电子邮件的内容)。每个服务都有自己的数据库 解决方案1 在事件中发送有关产品的所有所需信息-这意味着所下订单的结构如下所示: { order

给定控制模型(产品)的服务A(CMS),让我们假设它仅有的字段是id、标题、价格)和必须显示给定模型的服务B(发货)和C(电子邮件),在事件源方法中,在这些服务中同步给定模型信息的方法应该是什么?让我们假设产品目录很少更改(但确实更改),并且有管理员可以经常访问装运和电子邮件的数据(例如功能有:B:
显示订单中包含的产品标题
,C:
显示将要发送的装运相关电子邮件的内容
)。每个服务都有自己的数据库

解决方案1

在事件中发送有关产品的所有所需信息-这意味着所下订单的结构如下所示:

{
    order_id: [guid],
    product: {
        id: [guid],
        title: 'Foo',
        price: 1000
    }
}
{
    order_id: [guid],
    product_id: [guid]
}
关于服务B和C,产品信息存储在
订单
表的
产品
JSON属性中

因此,仅使用从事件检索的数据来显示必要的信息

问题:根据B和C中需要显示的其他信息,事件中的数据量可能会增加。B和C可能不需要关于产品的相同信息,但事件必须同时包含这两个信息(除非我们将事件分为两个)。如果给定的数据在给定的事件中不存在,代码就不能使用它-如果我们将给给定的产品添加一个color选项,对于B和C中的现有订单,给定的产品将是无色的,除非我们更新事件,然后重新运行它们

解决方案2

仅在事件中发送产品的guid-这意味着所下订单的结构如下所示:

{
    order_id: [guid],
    product: {
        id: [guid],
        title: 'Foo',
        price: 1000
    }
}
{
    order_id: [guid],
    product_id: [guid]
}
关于服务B和C,产品信息存储在
订单
表的
产品id
属性中

当需要执行对
A/Product/[guid]
endpoint的API调用时,服务B和C将检索产品信息

问题:这使得B和C始终依赖于A。如果产品的模式在上更改,则必须对依赖于它们的所有服务进行更改(突然)

解决方案3

仅发送事件中产品的guid-这意味着下订单的结构如下:

{
    order_id: [guid],
    product_id: [guid]
}
关于服务B和C,产品信息存储在
产品
表中;在
订单
表上仍然有
产品id
,但是在A、B和C之间有
产品
数据的复制;B和C可能包含与A不同的产品信息

产品信息在创建服务B和C时进行种子设定,并在有关产品的信息发生变化时通过调用
A/Product
端点(显示所有产品的所需信息)或通过对A执行直接DB访问并复制给定服务所需的产品信息来更新

问题:这使得B和C依赖于A(播种时)。如果产品架构在上发生更改,则必须对依赖于它们的所有服务进行更改(种子设定时)



根据我的理解,正确的方法是使用解决方案1,或者按照特定逻辑更新事件历史记录(如果产品目录没有更改,并且我们希望添加要显示的颜色,我们可以安全地更新历史记录以获取产品的当前状态,并在事件中填充缺失的数据)或者迎合不存在的给定数据(如果产品目录已更改,并且我们希望添加要显示的颜色,我们无法确定在过去的某个时间点,给定的产品是否有颜色-我们可以假设以前目录中的所有产品都是黑色的,并通过更新事件或代码来迎合)

一般来说,我强烈建议不要选择选项2,因为这两个服务之间存在时间耦合(除非这些服务之间的通信是超级稳定的,并且不是非常频繁)。时间耦合就是您所描述的
,这使得B和C依赖于A(在任何时候)
,这意味着如果A关闭或无法从B或C访问,B和C无法实现其功能

我个人认为,选项1和选项3都存在有效选项的情况

如果A和B&C之间的通信非常频繁,或者进入事件所需的数据量大到足以引起关注,那么选项3是最佳选项,因为网络负担要低得多,并且操作延迟将随着消息大小的减小而减少。这里要考虑的其他问题是:

  • 契约的稳定性:如果留下一条消息的契约经常发生变化,那么在消息中放置大量属性将导致消费者的大量变化。然而,在这种情况下,我认为这不是一个大问题,因为:
  • 您提到系统A是CMS。这意味着您正在一个稳定的域上工作,因此我不相信您会看到频繁的更改
  • 由于B和C正在发货和发送电子邮件,并且您正在从A接收数据,我相信您将经历附加更改,而不是破坏更改,只要您发现这些更改,就可以安全地进行添加,而无需返工
  • 耦合:这里几乎没有耦合。首先,由于通信是通过消息进行的,因此在数据种子设定期间,除了短时间的服务之外,服务与该操作的契约之间没有耦合(这不是您可以或应该尝试避免的耦合)
  • 然而,选择1并不是我会忽略的。耦合的数量是相同的,但在开发方面应该很容易做到(不需要特殊操作),域的稳定性应该意味着这些不会经常改变(正如我已经提到的)

    我建议的另一个选择是对3进行轻微修改,即在启动期间不运行流程,而是