Переход от CRUD к CQRS/ES
Переход от CRUD к CQRS/ES
Доброго времени суток!
Хочу обсудить такой момент. Как переходить от старых CRUD-приложений к CQRS/ES? Вернее, как это сделать плавно и постепенно.
Например, имеется интернет-аукцион. Его долго пилили предыдущие разрабы. Хранятся все данные в MySQL в реляционной модели с денормализацией (чтоб она сдохла) для ускорения чтения.
Требуется сделать быстрый и качественный поиск по каталогу лотов. Поиск полнотекстовый да еще с фильтрами и фасетами. Для него решено использовать Elasticsearch. Также планируется устранить денормализацию в реляционной базе.
Также необходимо вести тщательный аудит действий с каждым лотом. Сейчас при некоторых операциях просто добавляется запись в отдельную таблицу-журнал, лог не полный.
Основная трудность здесь - обеспечить консистентность реляционной базы и эластика.
Писать сразу и туда и туда - я думаю не вариант. Будет очень хрупко.
Индекстировать по крону - не подходит. Клиенты и руководство хотят чтоб было сразу или незаметно быстро.
Приходит на ум такое решение - писать в отдельную таблицу реляционной БД события изменений агрегата в одной транзакции с запросами на изменения самого агрегата. Другим потоком запрашивать необработанные события, отсортированные по autoincrement и применять их в Elasticsearch, затем ставить флаг, что событие было обработано. Такой вот Business Log в дополнение к состоянию.
Порядок следования событий в рамках одного агрегата планирую обеспечить следующим образом. В таблице событий будет автоинкрементная колонка и колонка с идентификатором агрегата. Так как запись эту таблицу будет производиться после выполнения запроса к таблице агрегата - блокировка InnoDB не даст сгенерировать следующий идентификатор для события, пока предыдущая транзакция на агрегат не завершится.
Все это может показаться довольно костыльным, но другого тут придумать пока не смог.
Я понимаю, что чистый ES как раз и призван избавить от необходимости хранить текущее состояние, но если сразу отказаться от этого не получается? Куча кода написана, который худо-бедно работает?
Кто-нибудь делал что-то подобное? Что можете подсказать? Правильным путем иду?
Хочу обсудить такой момент. Как переходить от старых CRUD-приложений к CQRS/ES? Вернее, как это сделать плавно и постепенно.
Например, имеется интернет-аукцион. Его долго пилили предыдущие разрабы. Хранятся все данные в MySQL в реляционной модели с денормализацией (чтоб она сдохла) для ускорения чтения.
Требуется сделать быстрый и качественный поиск по каталогу лотов. Поиск полнотекстовый да еще с фильтрами и фасетами. Для него решено использовать Elasticsearch. Также планируется устранить денормализацию в реляционной базе.
Также необходимо вести тщательный аудит действий с каждым лотом. Сейчас при некоторых операциях просто добавляется запись в отдельную таблицу-журнал, лог не полный.
Основная трудность здесь - обеспечить консистентность реляционной базы и эластика.
Писать сразу и туда и туда - я думаю не вариант. Будет очень хрупко.
Индекстировать по крону - не подходит. Клиенты и руководство хотят чтоб было сразу или незаметно быстро.
Приходит на ум такое решение - писать в отдельную таблицу реляционной БД события изменений агрегата в одной транзакции с запросами на изменения самого агрегата. Другим потоком запрашивать необработанные события, отсортированные по autoincrement и применять их в Elasticsearch, затем ставить флаг, что событие было обработано. Такой вот Business Log в дополнение к состоянию.
Порядок следования событий в рамках одного агрегата планирую обеспечить следующим образом. В таблице событий будет автоинкрементная колонка и колонка с идентификатором агрегата. Так как запись эту таблицу будет производиться после выполнения запроса к таблице агрегата - блокировка InnoDB не даст сгенерировать следующий идентификатор для события, пока предыдущая транзакция на агрегат не завершится.
Все это может показаться довольно костыльным, но другого тут придумать пока не смог.
Я понимаю, что чистый ES как раз и призван избавить от необходимости хранить текущее состояние, но если сразу отказаться от этого не получается? Куча кода написана, который худо-бедно работает?
Кто-нибудь делал что-то подобное? Что можете подсказать? Правильным путем иду?
Re: Переход от CRUD к CQRS/ES
все выглядит логичным, но это не ES, а соответственно, если состояние не зависит от событий, то некоторые события будете терять (забывать тригеррить в коде).anton_z писал(а): ↑2017.01.24, 05:23 Доброго времени суток!
Хочу обсудить такой момент. Как переходить от старых CRUD-приложений к CQRS/ES? Вернее, как это сделать плавно и постепенно.
Например, имеется интернет-аукцион. Его долго пилили предыдущие разрабы. Хранятся все данные в MySQL в реляционной модели с денормализацией (чтоб она сдохла) для ускорения чтения.
Требуется сделать быстрый и качественный поиск по каталогу лотов. Поиск полнотекстовый да еще с фильтрами и фасетами. Для него решено использовать Elasticsearch. Также планируется устранить денормализацию в реляционной базе.
Также необходимо вести тщательный аудит действий с каждым лотом. Сейчас при некоторых операциях просто добавляется запись в отдельную таблицу-журнал, лог не полный.
Основная трудность здесь - обеспечить консистентность реляционной базы и эластика.
Писать сразу и туда и туда - я думаю не вариант. Будет очень хрупко.
Индекстировать по крону - не подходит. Клиенты и руководство хотят чтоб было сразу или незаметно быстро.
Приходит на ум такое решение - писать в отдельную таблицу реляционной БД события изменений агрегата в одной транзакции с запросами на изменения самого агрегата. Другим потоком запрашивать необработанные события, отсортированные по autoincrement и применять их в Elasticsearch, затем ставить флаг, что событие было обработано. Такой вот Business Log в дополнение к состоянию.
смутно понял о чем речь. подкину лишь пару тезисов: а) id события можно генерить на клиенте в виде uuid, б) событиям можно сделать поле version, которое будет увеличиваться на клиенте, обеспечивать порядок событий и избавит от конкурентности.anton_z писал(а): ↑2017.01.24, 05:23Порядок следования событий в рамках одного агрегата планирую обеспечить следующим образом. В таблице событий будет автоинкрементная колонка и колонка с идентификатором агрегата. Так как запись эту таблицу будет производиться после выполнения запроса к таблице агрегата - блокировка InnoDB не даст сгенерировать следующий идентификатор для события, пока предыдущая транзакция на агрегат не завершится.
около того
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Переход от CRUD к CQRS/ES
А потом денормализовать ещё раз. Дело обычное. Схема устаревает так же, как и код.Также планируется устранить денормализацию в реляционной базе.
Звучит как обычная очередь. Смотрите сразу на какой-нибудь RabbitMQ.Приходит на ум такое решение - писать в отдельную таблицу реляционной БД события изменений агрегата в одной транзакции с запросами на изменения самого агрегата. Другим потоком запрашивать необработанные события, отсортированные по autoincrement и применять их в Elasticsearch, затем ставить флаг, что событие было обработано. Такой вот Business Log в дополнение к состоянию.
Нравится Yii? Давайте сделаем его лучше!.
Re: Переход от CRUD к CQRS/ES
Большое спасибо за ответы.
Еще AMQP не гарантирует порядок событий. А в этой задаче он важен.
version последовательна и уникальна для всех событий или в рамках агрегата?
Хочется консистентности между состоянием (сущностями) и событиями. Поэтому и очередь в таблице в той же БД на том же сервере под транзакциями. А так если кролик окажется недоступен в момент записи? Консистентность пострадает.
Еще AMQP не гарантирует порядок событий. А в этой задаче он важен.
Re: Переход от CRUD к CQRS/ES
А, тянем последнее событие для агрегата с блокировкой, к его version + 1, получаем version для нового события.
Re: Переход от CRUD к CQRS/ES
просто ставим уникальный индекс на [entity_type, entity_id, version]. Блокировка - не самое лучшее решение.
Re: Переход от CRUD к CQRS/ES
Тут получается выбор Optimistic lock vs Pessimistic lock.
А при проигрывании событий я выбираю необработанные с сортировкой по entity_id, version, верно?
А при проигрывании событий я выбираю необработанные с сортировкой по entity_id, version, верно?
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Переход от CRUD к CQRS/ES
Section 4.7 of the AMQP 0-9-1 core specification explains the conditions under which ordering is guaranteed: messages published in one channel, passing through one exchange and one queue and one outgoing channel will be received in the same order that they were sent. RabbitMQ offers stronger guarantees since release 2.7.0.
Нравится Yii? Давайте сделаем его лучше!.
Re: Переход от CRUD к CQRS/ES
ну дело в том, что на одну очередь может быть открыто несколько каналов, и так и делается при хорошей загрузке. И если в пять каналов одновременно ушло пять задач с id от 1 до 5, то нет гарантии, что они выполнятся по порядку. Скорее есть гарантия, что наоборот.
- samdark
- Администратор
- Сообщения: 9489
- Зарегистрирован: 2009.04.02, 13:46
- Откуда: Воронеж
- Контактная информация:
Re: Переход от CRUD к CQRS/ES
А с базой разве будет больше одного канала?
Нравится Yii? Давайте сделаем его лучше!.
Re: Переход от CRUD к CQRS/ES
Признаю ошибку c AMQP.
Один черт не могу сторонние очереди использовать - не будет консистентности между очередью и базой. Это если сначала в очередь. потом подписчиком в базу, тогда да.
Про производительность - параллеллить можно на стороне обработчика событий по entity_id.
Один черт не могу сторонние очереди использовать - не будет консистентности между очередью и базой. Это если сначала в очередь. потом подписчиком в базу, тогда да.
Про производительность - параллеллить можно на стороне обработчика событий по entity_id.