если я хочу получить профиль пользователя по определенному адресу электронной почты, должен ли я запросить на стороне чтения идентификатор пользователя, а затем запросить хранилище событий, используя этот идентификатор для данных профиля? или на стороне чтения уже должна храниться вся информация профиля?
Вы должны использовать специально разработанную модель чтения для поиска профилей по адресу электронной почты. Вам следует запрашивать хранилище событий только для повторного увлажнения агрегатов, а для повторного объединения агрегатов отправлять только команды, а не запросы. В CQRS агрегат не может быть запрошен.
Если на стороне чтения есть вся информация, в чем причина хранилища событий? Если это действительно только для записи, это не очень полезно, не так ли?
Event-store является источником правды для стороны записи (Aggregates). Он используется для регидратации агрегатов (они перестраивают свое внутреннее и частное состояние на основе предыдущих отправленных событий) перед командами процесса и для сохранения новых событий. Таким образом, хранилище событий доступно только для добавления, но также используется для чтения потока событий (событий, генерируемых экземпляром Aggregate). Хранилище событий гарантирует, что экземпляр Aggregate (то есть идентифицируемый типом и идентификатором) обрабатывает только команду за раз.
если изменяется пользовательская модель (например, профиль теперь включает описание профиля), и я использую сторону чтения, которая содержит все данные профиля, как мне обновить эту сторону чтения в lagom, чтобы теперь она также содержала это описание
Я не использую никакой другой фреймворк, кроме своей, но я думаю, что вы переписываете (чтобы использовать новое добавленное поле в событиях) и перестраиваете ReadModel.
После этого вопроса я должен хранить разные таблицы на стороне чтения для разных полей профиля вместо одной таблицы, содержащей весь профиль
У вас должна быть отдельная модель чтения (со своими таблицами) для каждого варианта использования. ReadModel должен работать быстро, это означает, что он должен быть как можно меньше, только с полями, необходимыми для этого конкретного варианта использования. Это очень важно, это одно из главных преимуществ использования CQRS.
если другой сервис нуждается в доступе к данным, должен ли он всегда запрашивать сервис пользователя или он должен сохранять свою собственную сторону чтения по мере необходимости? В случае последнего, не нарушает ли это принцип CQRS, что служба, которой принадлежат данные, должна быть единственной, кто читает и записывает эти данные?
Здесь зависит от вас, архитектор. Желательно, чтобы каждый ReadModel владел своими данными, то есть он должен подписываться на нужные события, он не должен зависеть от других ReadModel. Но это приводит к большому дублированию кода. По своему опыту я видел желание иметь некоторые канонические модели чтения, которые владеют некоторыми данными, но также могут делиться ими по требованию. Для этого в CQRS есть также термин query
. Как и команды и события, запросы могут перемещаться в вашей системе, но только из ReadModel в ReadModel.
Запросы не следует отправлять во время запроса клиента. Они должны отправляться только в фоновом режиме, как механизм асинхронной синхронизации. Это важный аспект, который влияет на устойчивость и отзывчивость вашей системы.
Я также использую оперативные запросы, которые передаются из официальных ReadModels в подписанные ReadModels в режиме реального времени, когда меняется ответ.
В случае последнего, не нарушает ли это принцип CQRS, согласно которому служба, которой принадлежат данные, должна быть единственной, кто читает и записывает эти данные?
Нет, это не так. CQRS не определяет , как обновляется R
(сторона чтения), только то, что R
не должен обрабатывать команды и C
не должен запрашиваться.