如何将领域模型设置为演员? [英] How to setup domain model as actor?

查看:63
本文介绍了如何将领域模型设置为演员?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Scala和Akka还是陌生的,我试图弄清楚如何创建合适的域模型,它也是一个Actor。

I'm fairly new to both Scala and Akka and I'm trying to figure out how you would create a proper domain model, which also is an Actor.

假设我们有一个简单的业务案例,您可以在其中开设一个新的银行帐户。假设其中一项规则是,您只能为每个姓氏创建一个银行帐户(不现实,只是为了简单起见)。我的第一种方法在不应用任何业务规则的情况下,将如下所示:

Let's imagine we have a simple business case where you can open a new Bank Account. Let's say that one of the rules is that you can only create one bank account per last name (not realistic, but just for the sake of simplicity). My first approach, without applying any business rules, would look something like this:

object Main {
  def main(args: Array[String]): Unit = {
    implicit val system = ActorSystem("accout")
    implicit val materializer = ActorMaterializer()
    implicit val executionContext = system.dispatcher
    val account = system.actorOf(Props[Account])
    account ! CreateAccount("Doe")
  }
}

case class CreateAccount(lastName: String)

class Account extends Actor {

  var lastName: String = null

  override def receive: Receive = {
    case createAccount: CreateAccount =>
      this.lastName = lastName
  }
}

最终会将这些数据保留在某个地方。但是,在添加每个姓氏只能有一个银行帐户的规则时,需要对某些数据存储进行查询。假设我们将逻辑放入存储库中,该存储库最终返回了 Account ,我们遇到了 Account 的问题不再是Actor,因为存储库将无法创建Actors。

Eventually you would persist this data somewhere. However, when adding the rule that there can only be one Bank Account per last name, a query to some data storage needs to be done. Let's say we put that logic inside a repository and the repository eventually returns an Account, we get to the problem where Account isn't an Actor anymore, since the repository won't be able to create Actors.

这肯定是错误的实现,而不是Actors的使用方式。我的问题是,有什么方法可以解决这类问题?我知道我对Akka的了解还不是很好,所以这可能是一个奇怪/愚蠢的提法问题。

This is definitely a wrong implementation and not how Actors should be used. My question is, what are ways to solve these kind of problems? I am aware that my knowledge of Akka is not on a decent level yet, so it might be a weird/stupid formulated question.

推荐答案

这可能是一个很长的答案,对不起,没有TLDR版本。 :)

This might be a long answer and I am sorry there isn't a TLDR version. :)

好,因此您想授权您的域模型吗?馊主意。领域模型不一定是参与者。有时是,但通常不是。在每个域模型中部署一个actor是一种反模式,因为如果这样做,您将把方法调用转移到消息调用上,而又失去了方法调用的所有单线程范式。您不能保证消息到达您的参与者的时间,并且基于ASK模式进行编程是引入无法扩展的系统的好方法,最终您会拥有太多的线程和太多的期货,并且无法继续进行下去,这会使系统陷入困境。那么这对您的特定问题意味着什么呢?

Ok, so you want to "Actorize" your domain model? Bad idea. Domain models are not necessarily actors. Sometimes they are but often they are not. It would be an anti-pattern to deploy one actor per domain model because if you do that you are simply offloading the method calling to message calling but losing all of the single threaded paradigm of the method calling. You cannot guarantee the timing of the messages hitting your actor and programming based upon ASK patterns is a good way to introduce a system that is not scalable, eventually you have too many threads and too many futures and cant proceed further, the system bogs and chokes. So what does that mean for your particular problem?

首先,您必须停止将域模型视为一件事情,并且一定要停止使用POJO实体。马丁·福勒(Martin Fowler)讨论贫血领域模型时,我完全同意。在构建良好的参与者系统中,通常会存在三个领域模型。一种是持久性模型,该模型具有对数据库进行建模的实体。第二个是不可变模型。参与者用来相互交流的模型。从下至上,所有实体都是不可变的,所有集合都是不可修改的,所有对象都只有吸气剂,所有构造函数都将集合复制到新的不可变集合中。不变的模型意味着您的参与者无需复制任何内容,他们只需传递对数据的引用即可。最后,您将拥有API模型,这通常是为客户端使用的JSON建模的实体集。 API模型可以使后端与客户端代码更改隔离,反之亦然,它是系统之间的契约。

First you have to stop thinking of the domain model as a single thing and definitely stop using POJO entities. I entirely agree with Martin Fowler when he discusses the anemic domain model. In a well built actor system there will often be three domain models. One is the persisted model which has entities that model your database. The second is the immutable model. This is the model that the actors use to communicate with each other. All the entities are immutable from the bottom up, all collections unmodifiable, all objects only have getters, all constructors copy the collections to new immutable collections. The immutable model means your actors never have to copy anything, they just pass around references to data. Lastly you will have the API model, this is usually the set of entities that model the JSON for the clients to consume. The API model is there to insulate the back end from client code changes and vice versa, its the contract between the systems.

要创建您的参与者,请停止考虑您的持久性模型以及您将如何使用它,而开始考虑用例。您的系统必须做什么?根据用例对参与者进行建模,这将改变参与者的实施及其部署策略。

To create your actors stop thinking about your persistent model and what you will do with it but instead start thinking of the use cases. What does your system have to do? Model your actors based on the use cases and that will change the implementation of the actors and their deployment strategies.

例如,考虑一台服务器,该服务器向用户传递库存信息,包括当前库存水平,用户的评论等,以了解单个供应商的产品。用户锤击此信息,并且随着库存水平的变化而迅速变化。此信息可能存储在六个不同的表中。我们不会为每个表建模一个参与者,而是为这个用例提供一个参与者。在这种情况下,大量人在重负载环境中会访问此信息。因此,我们最好创建一个actor来聚合所有这些数据,并将actor复制到每个节点,并且每当数据更改时,我们就会将所有更改通知所有节点上的所有复制者。这意味着获得概述的用户甚至不会触摸数据库。他们击中演员,获得不可变模型,将其转换为API模型,然后返回数据。

For example, consider a server that delivers inventory information to users including current stock levels, reviews by users and so on for products by a single vendor. The users hammer this information and it changes quickly as stock levels change. This information is likely stored in half a dozen different tables. We don't model an actor for each table but rather a single actor to serve this use case. In this case this information is accessed by a large group of people in heavy load environment. So we are best creating an actor to aggregate all of this data and replicating the actor to each node and whenever the data changes we inform all replicants on all nodes of the changes. This means the user getting the overview doesn't even touch the database. They hit the actors, get the immutable model, convert that to the API model and then return the data.

另一方面,如果用户想要更改库存水平,我们需要确保两个用户不要同时执行此操作,但是大型数据库事务会严重降低系统速度。因此,相反,我们选择一个节点来容纳该供应商的库存管理参与者,然后对参与者进行分片。任何请求都会路由到该参与者,并按顺序进行处理。公司用户登录并记录了20个新项目的交付收据。消息从他们命中的任何节点到持有该卖方的参与者的节点,然后卖方进行适当的数据库更改,并广播该更改,所有复制的清单视图参与者都选择了更改,以更改其数据。

On the other hand if a user wants to change the stock levels, we need to make sure that two users don't do it concurrently yet large DB transactions slows down the system massively. So instead we pick one node that will hold the stock management actor for that vendor and we cluster shard the actor. Any requests are routed to that actor and handled serially. The company user logs in and notes the receipt of a delivery of 20 new items. The message goes from whatever node they hit to the node holding the actor for that vendor, the vendor then makes the appropriate database changes and the broadcasts the change which is picked up by all the replicated inventory view actors to change their data.

现在这很简单,因为您必须处理丢失的消息(请阅读为什么不需要可靠消息传递的文章)。但是,一旦开始走这条路,您很快就会意识到,仅仅将您的域模型用作参与者系统是一种反模式,并且有更好的做事方法。

Now this is simplistic because you have to deal with lost messages (read the articles on why reliable messaging is not necessary). However once you start to go down that road you soon realize that simply making your domain model an actor system is an anti-pattern and there are better ways to do things.

反正就是我的2美分:)

Anyway that is my 2 cents :)

这篇关于如何将领域模型设置为演员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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