Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Domain driven design 强制执行跨多个聚合的严格一致性_Domain Driven Design_Aggregate_Eventual Consistency - Fatal编程技术网

Domain driven design 强制执行跨多个聚合的严格一致性

Domain driven design 强制执行跨多个聚合的严格一致性,domain-driven-design,aggregate,eventual-consistency,Domain Driven Design,Aggregate,Eventual Consistency,考虑以下业务需求: 我们有可以玩游戏的玩家。一个玩家一次只能玩一场游戏。一场游戏需要两名玩家。 该系统将容纳数百万玩家,游戏大约需要两分钟。并发问题可能会出现 我们希望遵守以下规则:单个交易涉及单个聚合。此外,最终的一致性不得导致接受的游戏,这些游戏必须在之后(即使是很短的一段时间)由于并发问题而取消。因此,最终的一致性并不真正合适 我们需要如何定义聚合及其边界来实施这些业务规则 我设想了两种方法: 1。基于事件的握手 聚合玩家,聚合游戏 当游戏被请求时,它会推送一个GameRequested-

考虑以下业务需求:

我们有可以玩游戏的玩家。一个玩家一次只能玩一场游戏。一场游戏需要两名玩家。

该系统将容纳数百万玩家,游戏大约需要两分钟。并发问题可能会出现

我们希望遵守以下规则:单个交易涉及单个聚合。此外,最终的一致性不得导致接受的游戏,这些游戏必须在之后(即使是很短的一段时间)由于并发问题而取消。因此,最终的一致性并不真正合适

我们需要如何定义聚合及其边界来实施这些业务规则

我设想了两种方法:

1。基于事件的握手

聚合
玩家
,聚合
游戏

当游戏被请求时,它会推送一个
GameRequested
-事件。
Player
s订阅此事件并响应相应的事件,要么
GamePlayerAccepted
,要么
GamePlayerRejected
。只有当两个
玩家
都接受时,
游戏
才会开始(
GameStarted

优点:

  • 聚合
    Player
    负责管理其自身的可用性,该可用性对应于域模型
缺点:

  • 开始一场
    游戏的责任分散在多个集合中(看起来像是“假的”-最终的一致性)
  • 大量的通信开销
  • 需要一致性度量,例如,如果出现问题,释放
    播放器
    s
2。集合集合

聚合
Player
,聚合
GamesManager
(带有一组值对象
ActiveGamePlayers
),聚合
Game

GameManager
被请求用两个给定的
玩家启动一个新的
游戏。
GameManager
能够确保
Player
一次只玩一次,因为它是单个聚合

优点:

  • 没有一致性强制事件,例如
    GamePlayerAccepted
    GamePlayerRejected
缺点:

  • 领域模型似乎很模糊
  • 玩家管理可用性的责任转移了
  • 我们必须确保只创建一个
    GameManager
    实例,并引入域机制,让客户不必担心中间聚合
  • 独立的
    游戏
    -开始互相干扰,因为
    游戏管理器
    -聚合自身锁定
  • 需要进行性能优化,因为
    GameManager
    -聚合将收集数千万的所有活动游戏玩家

这些方法似乎都不适合解决这个问题。我不知道如何设置边界,以确保模型和性能的严格一致性和清晰性。

我将使用基于事件的握手,这就是我将如何实现的:

据我所知,您需要一个
游戏
流程,作为
传奇
实现。您还必须定义一个
Player
聚合、一个
RequestGame
命令、一个
GameRequested
事件、一个
GameAccepted
事件、一个
MarkGameAsAccepted
命令、一个
MarkGameAsRejected
命令,
GameStarted
事件和
GameFailed
事件

因此,当
玩家A
想要与
玩家B
玩游戏时,
玩家A
收到
请求游戏
命令。如果此玩家正在播放其他内容,则会引发
playerReadyPlaySagame
异常,否则会引发
GameRequested
事件,并将其内部状态更新为
playing

Game
saga捕获
GameRequested
事件,并将
RequestGame
命令发送给
Player B
聚合(这是
Player
聚合,ID
等于
a
)。然后:

  • 如果
    玩家B
    正在玩另一个游戏(它通过查询其内部
    状态知道这一点),则会引发
    GameRejected
    事件;
    Game
    saga捕获此事件并向
    Player a
    发送
    MarkGameAsRejected
    命令;然后
    Player A
    引发
    GameFailed
    事件,并将其内部状态更新为
    not_playing

  • 如果
    玩家B
    没有玩另一个游戏,则会引发
    GameAccessed
    事件;
    Game
    saga捕获此事件,并将
    MarkGameAsAccepted
    命令发送给
    Player A
    aggregate
    Player A
    然后发出
    GameStarted
    事件,并将其内部状态更新为
    playing

为了理解这一点,您应该尝试对用例进行建模,假设没有计算机存在,玩家将是通过打印邮件进行通信的人

这个解决方案是可扩展的,我知道这是必需的

另一种解决方案似乎对数百万玩家不可行


第三种解决方案是在SQL表或NoSQL集合中使用活动参与者的集合,而不使用聚合战术模式。对于concurency,当将一对播放器设置为活动时,您可以在支持的情况下使用optimistick锁定或事务(低可扩展性)或两阶段提交(有点难看)

我会使用基于事件的握手,这是我将如何实现的: