首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >CQRS读取模型同步:查询微服务之间写入模型的正确方法

CQRS读取模型同步:查询微服务之间写入模型的正确方法
EN

Stack Overflow用户
提问于 2022-07-31 06:30:15
回答 1查看 72关注 0票数 0

我试图使用HTTP跟踪每个微服务pattner的每次读/写数据库。

遵循这个例子

资产微服务

写作模式:

  • AssetWriteDb (Mssql)
  • 资产类/表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Asset
{
 public Guid AssetId {get;set;}
 public Guid ContractId {get;set;} //reference to contract of other microservice
 ...
}

读模型

(mongodb)

  • AssetAggregate class/collection

  • AssetReadDb AssetReadDb

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AssetAggregate
{
 public Guid AssetId {get;set;}
 public Guid ContractId {get;get;}
 public string ContractNumber {get;set;} //this comes from Contract Microservice
 ...
}

合同小额服务

写模型

  • ContractWriteDb (mssql)
  • Contract类/表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Contract
{
 public Guid ContractId {get;set;}
 public string ContractNumber {get;set;}
 ...
}

读模型

  • ContractReadDb (mongodb)
  • ContractAggregate class/collection

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ContractAggregate
{
 public Guid ContractId {get;set;}
 public string ContractNumber {get;set;}
 public int AssetCount {get;set;} //this comes from Asset microservice
 ...
}

契约聚合同步eventHandler示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ContractAggregateHandler :
 IHandleMessage<ContractChangedEvent> // published from ContractWriteDb mssql repository
 IHandleMessage<AssetChangedEvent> // published from AssetWriteDb mssql repository 
{
 
 public async Task Handle(ContractChangedEvent message)
 {
   await _bus.Send(new RefreshContractAggregateCommand(message.ContractId));
 }

 public async Task Handle(AssetChangedEvent message)
 {
   //since the event contains only AssetId, I need to retrieve the data from the asset microservice. i have two options to obtain the contractId from asset microservice:

   //call the AssetApi microservice reading the AssetAggregate collection (mongodb)
   //var contractId = await _mediator.Send(new GetAssetContractIdQuery(message.AssetId);
   
   //call the AssetApi microservice reading the Asset table (sqlserver)
   //var contractId = await _mediator.Send(new GetAssetContractIdFromWriteDbQuery(message.AssetId);


   await _bus.Send(new RefreshContractAggregateCommand(contractId));
 }
}

按照查询应该始终查询Read的规则,命令应该始终读取和写写模型,实现这一目标的最佳实践是什么?

在第一种情况下(读取mongodb资产读取模型),我认为这是错误的: AssetChanged事件来自AssetWriteDb ( server),查询读取模型是不安全的。此外,如果我根据其他聚合生成聚合,我应该侦听AssetAggregateRefreshedEvent,但这将在聚合生成之间创建无限循环,因为AssetAggregates需要对这些操作永远不会结束的ContractAggregateRefreshedEvent进行分级。

在第二种情况下,(读取sql资产写入模型),我认为这是最安全的,但我需要管理许多“错误”的查询,因为它们不遵循“查询必须从读取模型获取数据”的规则。这就是为什么为了避免错误,我需要用一个不同的结尾词来区分它们,比如"FromWriteDbQuery“

显然,我不想评估第三个选项:直接从合同微服务查询AssetWriteDb

注意事项:有一个“公共”api网关“保护”所有内部微服务不受外部影响。api网关公开了以正确方式查询mongodb的客户端所需的总是正确的查询。这个问题只是关于聚合的内部处理,以及如何在微服务之间“查询”写入模型。

备注2:我没有编写“同步”业务逻辑( RefreshContractAggreagteHandler),因为它只是对投射"ContractAggregate“的ContractWriteDb的"sql查询”,然后要映射出相同问题的assetCount,我想从合同Microservice查询AssetWriteDb,所以主要问题完全相同)

EN

回答 1

Stack Overflow用户

发布于 2022-07-31 07:24:23

请记住,可以有任意多个读取模型,为特定的查询/查询进行优化。假设资产微服务中对合同ID的更改是在AssetChangedEvent中捕获的,那么您的合同服务可以维护自己的资产到契约ID的映射,作为其写入模型的一部分,然后当您需要解析给定资产的合同ID时,检查该映射。尽管映射是契约写入模型的具体部分(它可能是契约mssql中的表),但从概念上讲,它是资产的读模型(实际上,AssetChangedEvent的流是资产的读取模型,这意味着事件处理程序已经在资产读取模型池和契约写入模型池中至少有一个toe )。

然后,AssetChangedEvent处理程序首先检查事件是否接触到契约ID;如果是,它将更新映射。

顺便说一句,看起来这种微服务分解是基于从关系模式中获取表,并使每个表成为自己的微服务。这是解决许多额外复杂性的快速方法之一(特别是如果您想要同步)。这通常是一个更好的想法(尽管几乎每个实践者都必须学习“艰难的方法”)来根据命令进行分解。如果资产和合同如此紧密地联系在一起,其中一种的变化往往会波及到另一种(特别是如果需要更强的一致性保证时),那么让它们处于相同的微观服务中可能是最好的主意。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73184136

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文