Я внедряю систему, которая должна хранить все события согласованным образом, но в то же время я хотел бы сохранить согласованность, используя своего рода смешанный подход.Хотя идея источника событий довольно ясна, все мутации попадают в журнал 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 как брокером сообщений, так и базой данных, и из-за этих ограничений я даже не смотрю в этом направлении.
Итак, яИнтересно, по вашему опыту, как лучше сохранить систему «старомодной» (синхронной), но при этом гарантировать надежный журнал событий?(Да, я хочу все вкусности от обоих миров :))
Отказ от ответственности : Я знаю, насколько раздутый вопрос, если вы думаете, что этот вопрос не принадлежит сообществуиз-за этого, дайте мне знать, я сниму его.