Надежный журнал событий (не совсем Event Sourcing) - PullRequest
0 голосов
/ 24 декабря 2018

Я внедряю систему, которая должна хранить все события согласованным образом, но в то же время я хотел бы сохранить согласованность, используя своего рода смешанный подход.Хотя идея источника событий довольно ясна, все мутации попадают в журнал ES, а потребители затем создают материализованные представления, что меня беспокоит, так это ровно возможная согласованность, поскольку теперь система является асинхронной во всей системе.

CQRS +Подход ES предполагает, что это должно быть решено на уровне пользовательского интерфейса, и клиент должен ждать.Предположим, у меня есть что-то близкое к тому, что такое stackoverflow.Когда я закончу этот вопрос, я нажму кнопку «Опубликовать вопрос», и веб-сайт сразу же ответит на мой вопрос.При использовании подхода ES нажатие кнопки «Опубликовать свой вопрос» будет означать, что мой вопрос будет помещен в хранилище ES для последующей обработки, и я буду видеть «Мы публикуем ваш вопрос, подождите некоторое время», верно?Вот чего я хочу избежать.Я придумал следующую схему:

CreateQuestionCommand command
    = new CreateQuestionCommand(uint userId, string questionBody, string[] tags)
QuestionSavedEvent result
    = command.execute() // save to DB as usual, return events
saveToES(result) // ugghhhhh...

Если я когда-нибудь забуду saveToES, журнал ES станет непоследовательным и практически бесполезным.Если кто-то из разработчиков моей команды забудет об этом, то же самое - весь журнал ES - это просто отброс.

Может ли такой подход быть жизнеспособным?Это устранит недостаток ES, который заключается в возможной согласованности и при этом сохранит яркую сторону, которая всегда является надежным журналом событий.

Я сталкивался с некоторыми решениями.

1.

  • Некоторые базы данных предоставляют доступ к журналу фиксации, который может быть источником событий, но этот подход немного скучен, поскольку чтение журнала фиксации ничего не говорит о бизнес-логике приложения, которая может потребоватьсято есть вы просто читаете UPDATE users SET loggedIn = "2018-12-30 10:00:00" WHERE id = 1 из журнала фиксации, событие в этом случае просто UserUpdated, но на уровне приложения это может быть намного лучше UserLoggedIn.

Другоеподход, используемый ebay (якобы, я читал его в одной книге по ES, не буду вспоминать название, хотя)

2.

  • Начать транзакцию 1
  • UPDATE domain.users SET loggedIn = "2018-12-30 10:00:00" WHERE id = 1
  • Начать транзакцию 2 (внутренняя передача)
  • INSERT INTO events.log SET event = "{name: UserLoggedIn, userId: 1}", timestamp = "2018-12-30 10:00:00"
  • Подтвердить транзакцию 2
  • Подтвердитьтранзакция 1

Тогда другой процесс может опросить этот events.log для публикацииданные в ES store.По замыслу каждый мутатор данных должен быть вынужден возвращать event и указатель на transaction 1, и таким образом система никогда не "забудет" зафиксировать событие в базе данных.

Третий подходиспользовать 2PC (двухфазное принятие), для которого требуется диспетчер распределенных транзакций, и поддержку 2PC как брокером сообщений, так и базой данных, и из-за этих ограничений я даже не смотрю в этом направлении.

Итак, яИнтересно, по вашему опыту, как лучше сохранить систему «старомодной» (синхронной), но при этом гарантировать надежный журнал событий?(Да, я хочу все вкусности от обоих миров :))

Отказ от ответственности : Я знаю, насколько раздутый вопрос, если вы думаете, что этот вопрос не принадлежит сообществуиз-за этого, дайте мне знать, я сниму его.

1 Ответ

0 голосов
/ 24 декабря 2018

Может ли такой подход быть жизнеспособным?Это устранит недостаток ES, который заключается в возможной последовательности и при этом сохранит яркую сторону, которая всегда является надежным журналом событий.

В этом нет ничего плохого, все сделано осторожно - важно убедиться, что вашсобытия и ваше состояние хранятся в одной транзакции и, следовательно, в одной и той же базе данных.

Идея хранения событий вдоль стороны состояния давно существует.Вы часто будете встречать такие обсуждения, сосредоточенные на идее «доменных событий» и использовании события, вызванного одним агрегатом, для запуска поведения где-то еще.См., Например, доклад Уди Даана о надежном обмене сообщениями без распределенных транзакций .

При этом мы отбросили CQRS - вместо этого у нас есть единая логическая модель данных, которая хранит текущее состояниеи история событий вместе.

Что отлично ;если CQRS не решает проблему, с которой вы столкнулись, вам не следует ее использовать.

Отделение модели чтения от модели записи эквивалентно кешированию;чтобы получить преимущества, вы должны решить проблему аннулирования кэша, что является одной из двух трудных проблем .

...