首页 文章

Lagom PersistentEntityRef

提问于
浏览
1

我正在研究Lagom,并尝试了解持久化实体的工作原理 .

我已经阅读了以下描述:

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

说得通 .

然后是以下示例来创建客户:

@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包含多个singleton persistentEntities? persistentEntityRegistry究竟是如何填充的以及它中包含的内容?假设我们创建了10k个用户,注册表是否包含10k persistentEntities,还是仅包含1个?

  • 在这种情况下,我们想要创建一个新客户 . 因此,当我们使用 persistentEntityRegistry.refFor(CustomerEntity.class, request.userEmail); 请求persistentEntity时,这还不应该存在(?) .

你能说清楚它是如何工作的吗?文档很好但是我的理解中有一些漏洞,我无法填写 .

1 回答

  • 3

    好问题 . 我不确定你与这里没有提到的持久性实体相关的概念有多远,所以我将从头开始 .

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

    在Lagom中,这是使用actor实现的 . 每个实体(即客户的每个实例)由演员加载和管理 . 一个actor有一个邮箱(即一个队列),在那里放置命令,并按顺序一次处理一个 . 对于每个实体,都有一个单独的角色管理它(因此,每个客户一个角色,许多客户有很多角色) . 由于单一作家原则,这是非常重要的 .

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

    这是为什么它是 PersistentEntityRef 的原因之一,由于位置透明(你不直接 grab 实体,你只能引用它 . 相同的术语用于演员,你有实际的 Actor 那个行为,并使用 ActorRef 与它进行通信 .

    现在,从逻辑上讲,当您根据系统的域模型获得客户的参考资料时,他们只是认为该实体可能还没有事件,在这种情况下,当它加载时,它将只有 initialState ,没有应用任何事件 . 对于客户,客户的状态可能是 Optional<Customer> . 因此,在为客户发出任何事件之前首次创建实体时,状态将为 Optional.empty() . 为客户发出的第一个事件将是 CustomerRegistered 事件,这将导致状态更改为 Optional.of(someCustomer) .

    要理解为什么必须这样,你不希望同一个客户能够自己注册两次,对吧?您希望确保每个客户只有一个 CustomerRegistered 事件 . 要做到这一点,您需要让客户处于未注册状态,以确认他们在注册之前尚未注册 .

    因此,为了明确你的第一个问题的答案,如果你有10K用户,那么将有10K持久性实体实例,每个用户一个 . 虽然,这只是逻辑上的(数据库中有10K个不同用户的物理事件) . 在内存中,实际加载的实体将取决于哪些实体是活动的,当实体进入时,默认情况下,2分钟而不接收命令,Lagom将钝化该实体,这意味着它将其从内存中删除,因此下一次一个命令进来因为它必须通过从数据库加载它的事件来加载 . 这有助于确保在不需要时将所有数据保存在内存中,从而使内存不足 .

相关问题