首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lagom PersistentEntityRef

Lagom PersistentEntityRef
EN

Stack Overflow用户
提问于 2018-05-20 22:16:07
回答 1查看 881关注 0票数 1

我正在学习Lagom,并试图了解持久性实体是如何工作的。

我读过以下描述:

每个PersistentEntity都有一个固定的标识符(主键),可以用来获取当前状态,并且在任何时候只有一个实例(作为“单例”)保存在内存中。

合乎道理。

下面是创建客户的示例:

代码语言:javascript
复制
@Override
public ServiceCall<CreateCustomerMessage, Done> createCustomer() {
   return request -> {
       log.info("===> Create or update customer {}", request.toString());
       PersistentEntityRef<CustomerCommand> ref = persistentEntityRegistry.refFor(CustomerEntity.class, request.userEmail);
       return ref.ask(new CustomerCommand.AddCustomer(request.firstName, request.lastName, request.birthDate, request.comment));
   };
}

这让我感到困惑:

  • 这是否意味着persistentEntityRegistry包含多个单例persistentEntities?persistentEntityRegistry到底是如何被填充的,其中包含了什么?假设我们创建了10k用户,注册中心是包含10k persistentEntities,还是仅包含1?
  • 在这种情况下,我们希望创建一个新客户。因此,当我们使用persistentEntity请求persistentEntityRegistry.refFor(CustomerEntity.class, request.userEmail);时,不应该从注册表中返回任何内容,因为客户还不存在(?)。

你能给我看看这是怎么回事吗?文档是好的,但是在我的理解中有一些我无法填补的漏洞。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-21 00:23:58

好问题。我不知道您与这里没有提到的持久性实体相关的概念有多远,所以我从一开始就开始。

一般情况下,对于给定的实体(例如,单个客户),在进行事件采购时,您需要一个单独的作者。这是因为通常不会在单个事务中完成对事件日志的读取和写入,因此您需要读取一些事件来加载您的状态,验证传入的命令,然后发出一个或多个要持久的新事件。如果两个操作同时出现在同一个实体中,那么它们都将使用相同的状态进行验证--而不是考虑到另一个操作在执行之前可能进行的状态更改。因此,事件来源需要一个单一的编写原则,一次只能处理一个操作,因此只有一个编写者。

在拉格姆,这是通过行动者来实现的。每个实体(即客户的每个实例)都由一个参与者加载和管理。参与者有一个邮箱(即队列),其中放置命令,并按顺序一次处理它们。对于每个实体,都有一个单独的参与者来管理它(因此,每个客户有一个参与者,许多客户有多个参与者)。由于单一作家的原则,这是非常重要的,这是正确的。

但是,这种规模的系统是如何实现的呢?如果您有多个节点,那么每个实体是否有多个实例呢?不是的。Lagom使用Akka集群,Akka集群对多个节点分割实体,确保在所有已部署的节点上,每个实体中只有一个。因此,当一个命令传入一个节点时,该实体可能存在于同一个节点上,在这种情况下,它直接被发送到本地参与者进行处理,或者它可能位于另一个节点上,在这种情况下,它被序列化,发送到它所在的节点,并在那里处理,响应被序列化并发送回。

这就是为什么它是一个PersistentEntityRef的原因之一,由于位置透明性(你不知道实体在哪里),你不能直接保存实体,你只能有一个引用。对于参与者也使用了相同的术语,您有执行该行为的实际Actor,并使用一个ActorRef与其通信。

现在,从逻辑上讲,当您得到一个客户的参考,根据您的系统的域模型还不存在(例如,他们还没有注册),他们不存在。但是,它们的持久实体可以而且必须存在。实际上,在拉格姆中没有一个不存在的持久实体的概念,你总是可以实例化任何id的持久实体,它会加载。只是该实体可能还没有事件,在这种情况下,当它加载时,它只会有它的initialState,而不应用任何事件。对于客户,客户的状态可能是Optional<Customer>。因此,当第一次在为客户发出任何事件之前创建实体时,状态将是Optional.empty()。为客户发出的第一个事件将是一个CustomerRegistered事件,这将导致状态更改为Optional.of(someCustomer)

要理解为什么逻辑上必须如此,您不希望同一个客户能够注册自己两次,对吗?您希望确保每个客户只有一个CustomerRegistered事件。要做到这一点,您需要为处于未注册状态的客户提供一个状态,以验证它们在注册之前是否已经注册。

因此,为了明确第一个问题的答案,如果您有10K用户,那么将有10K持久实体实例,每个用户一个。不过,这只是逻辑上的(数据库中有10K不同用户的事件)。在内存中,实际加载的实体将取决于哪些实体处于活动状态,默认情况下,当一个实体在没有接收到命令的情况下执行2分钟时,Lagom将钝化该实体,这意味着它将从内存中删除该实体,因此下一次必须通过从数据库加载该实体的事件来加载该实体的命令。如果不需要的话,这有助于通过将所有数据保存在内存中来确保内存不会耗尽。

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

https://stackoverflow.com/questions/50439895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档