加强跨多个集合的严格一致性 [英] Enforce strict consistency spanning multiple aggregates

查看:118
本文介绍了加强跨多个集合的严格一致性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下业务要求:

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

We have players which can play games. A player can play only one game at a time. A game needs two players.

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

The system will contain millions of players, and games take about two minutes. Concurrency issues are likely to emerge.

我们要遵守单笔交易涉及单个汇总的规则。此外,最终的一致性不能导致接受的游戏,该游戏必须由于并发问题而在之后(即使是很短的时间)取消。因此,最终的一致性并不是真正合适的。

We want to comply to the rule that a single transaction involves a single aggregate. Further, eventual consistency must not lead to accepted games which must be cancelled afterwards (even if a short period of time) due to concurrency issues. Thus, eventual consistency is not really appropriate.

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

How do we need to define the aggregates and their boundaries to enforce these business rules?

我构思了两种方法:

1。基于事件的握手

总计 Player ,总计 Game

请求游戏时,它会推送 GameRequested 事件。 Player 订阅此事件并响应相应的事件,即 GamePlayerAccepted GamePlayerRejected 。仅当两个 Player 都接受时, Game 才会启动( GameStarted )。

When a game is requested, it pushed a GameRequested-event. The Players subscribe this event and respond with a corresponding event, either GamePlayerAccepted or GamePlayerRejected. Only if both Players have accepted, the Game starts (GameStarted).

优点:


  • 玩家负责管理自己的与域模型相对应的可用性

  • The aggregate Player is responsible for managing his own availability which corresponds to the domain model

缺点:


  • 启动游戏的责任分散在多个聚合中(似乎是伪造-最终一致性)

  • 很多通信开销

  • 需要采取一致性措施,例如如果出现问题,请释放 Player s

  • The responsibility of starting a Game is scattered throughout multiple aggregates (it seems like "fake"-eventual-consistency)
  • Much communication overhead
  • Consistency measures needed, e.g. freeing up the Players if something went wrong

2。集合汇总

汇总玩家,汇总 GamesManager (带有值对象 ActiveGamePlayers 的集合),总计 Game

Aggregate Player, aggregate GamesManager (with a collection of value-objects ActiveGamePlayers), aggregate Game.

要求 GameManager 启动一个新的 Game ,其中两个给定的播放器 s。 GameManager 能够确保 Player 一次只能播放一次,因为它是单个集合。

The GameManager is requested to start a new Game with two given Players. The GameManager is able to ensure that a Player only plays once at a time since it's a single aggregate.

优点:


  • 没有诸如 GamePlayerAccepted GamePlayerRejected

  • No consistency-enforcing events such as GamePlayerAccepted, GamePlayerRejected and so forth

缺点:


  • 域模型似乎模糊了

  • 播放器的可用性管理职责转移

  • 我们必须确保只有一个实例GameManager 的创建并引入了域机制,该机制使客户不必担心中介集合

  • 独立 Game -start彼此干扰,因为 GameManager -聚合自身锁定

  • 由于 GameManager -聚合收集所有活跃的游戏玩家,这些玩家将达到数千万

  • The domain model seems obscured
  • The responsibility of the Player to manage availability shifted
  • We have to ensure that only one instance of GameManager is created and introduce domain-mechanisms which let the client not worry about the intermediary-aggregate
  • Independent Game-starts disrupt each other because the GameManager-aggregate locks itself
  • Need for performance optimization since the GameManager-aggregate collects all active game players which will be tens of millions

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

It seems like none of these approaches are appropriate to solve the problem. I don't know how to set the boundaries to ensure both strict consistency and clarity of the model, and performance.

推荐答案

我将使用基于事件的握手,这就是我要实现的方式:

据我了解,您将需要 Game 流程作为 Saga 实施。您还必须定义一个 Player 聚合,一个 RequestGame 命令,一个 GameRequested 事件, GameAccepted 事件, GameRejected 事件, MarkGameAsAccepted 命令, MarkGameAsRejected 命令, GameStarted 事件和 GameFailed 事件。

From what I understand you would need a Game process implemented as a Saga. You will also have to define a Player aggregate, a RequestGame command, a GameRequested event, a GameAccepted event, a GameRejected event, a MarkGameAsAccepted command, a MarkGameAsRejected command, a GameStarted event and a GameFailed event.

因此,当玩家A 想要与玩家B 玩家A 收到 RequestGame 命令。如果此玩家正在玩其他游戏,则会抛出 PlayerAlreadyPlaysAGame 异常,否则将引发 GameRequested 事件并更新其内部状态为

So, when the Player A want's to play a game with Player B, Player A receives the RequestGame command. If this player is playing something else then a PlayerAlreadyPlaysAGame exception is thrown, otherwise it raises the GameRequested event and update it's internal state as playing.

游戏传奇抓住了 GameRequested 事件,并将 RequestGame 命令发送到 B玩家聚合(这是 Player 聚合,其 ID 等于 A )。然后:

The Game saga catches the GameRequested event and send the RequestGame command to the Player B aggregate (this is a Player aggregate with ID equal to A). Then:


  • 如果玩家B 正在玩其他游戏(它通过查询其内部播放状态知道这一点),然后引发 GameRejected 事件; Game 传奇抓住了这个事件,并向玩家A MarkGameAsRejected 命令$ c>;然后玩家A 引发 GameFailed 事件,并将其内部状态更新为 not_playing

  • If the Player B is playing another game (it knows this by querying its internal playing state) then it raises the GameRejected event; the Game saga catches this event and send a MarkGameAsRejected command to Player A; then Player A raises the GameFailed event and updates its internal state as not_playing.

如果玩家B 没有玩其他游戏,则加注 GameAccepted 事件; Game 传奇抓住了这个事件,并将 MarkGameAsAccepted 命令发送给玩家A 总计; 玩家A 然后发出 GameStarted 事件,并将其内部状态更新为正在播放

If the Player B is not playing another game then it raises the GameAccepted event; the Game saga catches this event and send the MarkGameAsAccepted command to Player A aggregate; Player A then emits the GameStarted event and update its internal state as playing.

为了理解这一点,您应该尝试对用例进行建模,就好像没有计算机会

In order to understand this you should try to model the use-case as if no computers would exist and players would be humans that communicate over printed mail.

此解决方案具有可扩展性,我知道这是必需的。

This solution is scalable and I understand that this is required.

另一种解决方案似乎无法吸引数百万玩家

第三种解决方案是在SQL表中使用活动参与者的集合或在NoSQL中使用集合,而不使用聚合战术模式。为了确保一致性,将一对播放器设置为活动状态时,可以在支持(低可伸缩性)或两阶段提交(有点丑陋)的地方使用光学标记锁定或事务。

A third solution would be to use a colection of active players in a SQL table or a NoSQL colection, without using the Aggregate tactical pattern. For concurency, when setting a pair of players as active, you could use optimistick locking or transactions where supported (low scalable) or two-phase commits (kind of ugly).

这篇关于加强跨多个集合的严格一致性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆