Lagom PersistentEntityRef - PullRequest
       5

Lagom PersistentEntityRef

0 голосов
/ 21 мая 2018

Я изучаю Лагом и пытаюсь понять, как работают постоянные сущности.

Я прочитал следующее описание:

Каждый 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 содержит несколько одноэтапных persistentEntities?Как именно заполняется persistentEntityRegistry и что в нем?Скажем, у нас создано 10 тысяч пользователей, реестр содержит 10 тысяч постоянных объектов или только 1?
  • В этом случае мы хотим создать нового клиента.Поэтому, когда мы запрашиваем persistentEntity, используя persistentEntityRegistry.refFor(CustomerEntity.class, request.userEmail);, это не должно ничего возвращать из реестра, так как клиент еще не существует (?).

Можете ли вы пролить свет на то, как это работает?Документация хорошая, но в моем понимании есть несколько пробелов, которые я не смог заполнить.

1 Ответ

0 голосов
/ 21 мая 2018

Отличные вопросы.Я не уверен, насколько далеко вы находитесь с концепциями, относящимися к постоянным сущностям, которые здесь не упомянуты, поэтому я начну с самого начала.

При выполнении поиска событий, как правило, для данной сущности (например, один клиент), вам нужен один писатель.Это связано с тем, что обычно чтение и последующая запись в журнал событий не выполняются в одной транзакции, поэтому вы читаете некоторые события для загрузки своего состояния, проверки входящей команды и затем отправляете одно или несколько новых событий для сохранения.Если для одной и той же сущности одновременно выполняются две операции, то обе они будут проверены с одним и тем же состоянием, не принимая во внимание изменение состояния, которое другая может получить до выполнения.Следовательно, для извлечения событий требуется принцип единственного писателя, одновременно может обрабатываться только одна операция, поэтому есть только один писатель.

В Lagom это реализовано с использованием актеров.Каждый объект (т. Е. Каждый экземпляр клиента) загружается и управляется субъектом.У актера есть почтовый ящик (т. Е. Очередь), в который помещаются команды, и он обрабатывает их по очереди, по порядку.Для каждого объекта существует отдельный субъект, управляющий им (так, один субъект на клиента, много участников для многих клиентов).Из-за принципа единственного автора очень важно, чтобы это было правдой.

Но как система масштабируется?Что произойдет, если у вас будет несколько узлов, у вас будет несколько экземпляров каждой сущности?Нет. Lagom использует кластеризацию Akka с сегрегацией кластеров Akka для разделения ваших сущностей на множество узлов, гарантируя, что на всех ваших развернутых узлах у вас будет только один объект.Таким образом, когда команда поступает на узел, сущность может жить на том же узле, и в этом случае она просто отправляется прямо на локальный субъект для обработки, или она может жить на другом узле, и в этом случае онасериализуется, отправляется на узел, на котором он живет, и обрабатывается там, с сериализацией и отправкой ответа.

Это одна из причин, по которой он равен PersistentEntityRef, из-за прозрачности местоположения (выне знаю, где живет эта сущность), вы не можете удерживать сущность напрямую, вы можете иметь только ссылку на нее.Та же самая терминология используется для актеров, у вас есть фактический Actor, который выполняет поведение, и ActorRef используется для связи с ним.

Теперь, логически, когда вы получаете ссылку для клиентачто в соответствии с моделью домена вашей системы еще не существует (например, они не зарегистрированы), они не существуют.Но постоянная сущность для них может и должна существовать.На самом деле в Lagom отсутствует концепция постоянной сущности, вы всегда можете создать постоянную сущность с любым идентификатором, она будет загружена.Просто для этого объекта еще не может быть никаких событий, и в этом случае, когда он загружается, у него просто будет initialState без примененных событий.Для клиента состояние клиента может быть Optional<Customer>.Таким образом, когда сущность сначала создается до того, как для клиента генерируются какие-либо события, состояние будет Optional.empty().Первым событием, отправляемым для клиента, будет событие CustomerRegistered, и это приведет к изменению состояния на Optional.of(someCustomer).

Чтобы понять, почему логически это должно быть так, вы не хотите, чтобыОдин и тот же клиент сможет дважды зарегистрироваться, верно?Вы хотите, чтобы для каждого клиента было только одно событие CustomerRegistered.Для этого вам нужно иметь состояние для клиента в его незарегистрированном состоянии, чтобы подтвердить, что они еще не зарегистрированы, прежде чем они зарегистрируются.

Итак, для ясности ответа на ваш первый вопрос, если у вас есть 10K пользователей, то будет 10K постоянных экземпляров сущностей, по одному для каждого пользователя.Впрочем, это только логично (в базе данных будут физические события для 10K разных пользователей).В памяти фактические загруженные объекты будут зависеть от того, какие объекты активны. Когда объект по умолчанию идет 2 минуты без получения команды, Lagom пассивирует этот объект, то есть он удаляет его из памяти, поэтому в следующий разприходит команда, которую нужно загрузить, загрузив для нее события из базы данных.Это помогает гарантировать, что вы не исчерпываете память, удерживая все свои данные в памяти, если вы не хотите.

...