代码之家  ›  专栏  ›  技术社区  ›  Trace

Lagom持久性试验

  •  1
  • Trace  · 技术社区  · 6 年前

    我正在学习lagom并试图理解持久实体是如何工作的。

    我已阅读以下描述:

    每个持久性都有一个固定的标识符(主键),可以 用于获取当前状态,并且在任何时候只有一个实例 (作为一个单身汉)被保存在记忆中。

    有道理。

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

    @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));
       };
    }
    

    这让我困惑:

    • 这是否意味着持久性策略包含多个单例持久性?持久性策略到底是如何被填满的?它包含什么?假设我们创建了10000个用户,注册表是否包含10000个持久性,或者只包含1个?
    • 在这种情况下,我们希望创建一个新客户。所以当我们请求使用 persistentEntityRegistry.refFor(CustomerEntity.class, request.userEmail); ,这不应该从注册表返回任何内容,因为客户尚不存在(?).

    你能把这件事讲清楚吗? 文件是好的,但在我的理解中有一些漏洞,我还没有能够填补。

    1 回复  |  直到 6 年前
        1
  •  4
  •   James Roper    6 年前

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

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

    在lagom中,这是使用actors实现的。每个实体(即客户的每个实例)都由参与者加载和管理。参与者有一个邮箱(即队列),其中放置了命令,并按顺序一次处理一个命令。对于每个实体,都有一个单独的参与者管理它(因此,每个客户有一个参与者,许多客户有多个参与者)。由于单作者原则,这是非常重要的,这是真的。

    但是,一个像这样规模的系统是怎么做到的呢?如果您有多个节点,那么每个实体都有多个实例会发生什么?不。Lagom使用Akka集群和Akka集群分片来跨多个节点分片您的实体,确保跨所有部署的节点,您只有一个实体。因此,当一个命令进入一个节点时,实体可能生活在同一个节点上,在这种情况下,它直接被发送到本地参与者以进行处理,或者它可能生活在另一个节点上,在这种情况下,它会被串行化,发送到它生活的节点,并在那里进行处理,然后得到响应被连载并送回。

    这就是为什么它是 PersistentEntityRef ,由于位置透明(您不知道实体所在的位置),您不能直接保留实体,只能引用它。同样的术语也用于演员,你有 Actor 这样做的行为,以及 ActorRef 用于与之通信。

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

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

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

    推荐文章