Использование Kafka как хранилища событий (CQRS). Отличная идея?

220

Хотя я раньше сталкивался с Кафкой , я только недавно понял, что Кафку, возможно, можно использовать как (основу) CQRS , хранилище событий .

Один из основных моментов, которые поддерживает Кафка:

  • Захват / хранение событий, все ГА, конечно.
  • Паб / суб архитектура
  • Возможность воспроизведения журнала событий, что позволяет новым подписчикам регистрироваться в системе после факта.

По общему признанию, я не на 100% разбираюсь в CQRS / Event Sourcing, но это кажется довольно близко к тому, каким должно быть хранилище событий. Забавная вещь: я действительно не могу найти так много о том, что Кафка используется в качестве хранилища событий, так что, возможно, я что-то упускаю.

Итак, чего не хватает в Кафке, чтобы он был хорошим хранилищем событий? Будет ли это работать? Используя это производство? Интересует понимание, ссылки и т. Д.

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

Герт-Ян
источник
Привет Гирт-Ян. В ретроспективе, как вы справились с этой проблемой? У меня есть связанный вопрос (выставлен здесь: stackoverflow.com/questions/58763727/… ). Большинство людей, предлагающих принятие Kafka, похоже, полагаются на точки неизменяемости append-log, высокую пропускную способность и гарантию порядка разделов. Я вижу проблемы, связанные с быстрым поиском по темам (для «реконструкции» сущности), отсутствие атомарности транзакций и упорядочение по разделам (100% -ная гарантия заказа подразумевает использование только одного раздела - одновременный убийства)
Тони _008
В конце концов, не продолжал, потому что закончил этот побочный проект. Так что нет четкого ответа, я боюсь
Герт-Янв

Ответы:

119

Kafka - это система обмена сообщениями, которая имеет много общего с хранилищем событий, однако процитирую их введение:

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

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

ОБНОВИТЬ

Кафка документация :

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

ОБНОВЛЕНИЕ 2

Одной из проблем, связанных с использованием Kafka для поиска источников, является количество необходимых тем. Обычно в источниках событий имеется поток (тема) событий для каждой сущности (такой как пользователь, продукт и т. Д.). Таким образом, текущее состояние объекта может быть восстановлено путем повторного применения всех событий в потоке. Каждый раздел Kafka состоит из одного или нескольких разделов, и каждый раздел хранится в виде каталога в файловой системе. Также будет давление со стороны ZooKeeper по мере увеличения количества znodes.

eulerfx
источник
16
Я смотрел на Кафку и имел другое беспокойство: я ничего не заметил в оптимистичном параллелизме. В идеале я мог бы сказать: «Добавьте это событие как элемент N + 1, только если самое последнее событие объекта по-прежнему равно N.»
Дариен
2
@Darien: Я, вероятно, собираюсь настроить, где Redis кормит Кафку (используя Redis Notifications ). Поскольку Redis допускает оптимистичный параллелизм (используя Watch / multi-exec), это должно сработать
Geert-Jan
2
@Darien Я не эксперт по поиску событий, но я понимаю, что, вообще говоря, вам не понадобится оптимистичный параллелизм, потому что события по определению являются записями событий, которые уже произошли исторически.
Джон
4
@ Джон Я думаю, что если у вас уже есть авторитетный порядок неконфликтующих событий, это означает, что где бы они ни находились, это ваша настоящая технология хранения событий, а Kafka просто используется как вторичная система для их распространения.
Дариен
1
Здесь также есть ценная информация: groups.google.com/forum/#!topic/dddcqrs/rm02iCfffUY
manuc66
283

Я один из оригинальных авторов Кафки. Кафка будет очень хорошо работать в качестве журнала для поиска событий. Он отказоустойчив, масштабируется до огромных объемов данных и имеет встроенную модель разделения.

Мы используем его для нескольких случаев использования этой формы в LinkedIn. Например, наша система обработки потоков с открытым исходным кодом, Apache Samza, поставляется со встроенной поддержкой источников событий.

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

Я написал немного об этом стиле использования Кафки здесь .

Джей Крепс
источник
2
Собирался опубликовать эту ссылку :) Потрясающий пост в блоге. Было бы хорошо иметь возможность комментировать это, потому что у меня много вопросов. @ Geert-Jan также взглянет на «Лямбда-архитектуру», это довольно похоже, и имя дано от автора Storm, в основном использующего некоторый журнал событий на основе hadoop во многих примерах
Себастьян Лорбер
6
@Jay: Поскольку я снова заинтересовался этой темой, не могли бы вы рассказать немного о том, что Kafka, похоже, рассчитан на истечение срока действия опубликованных сообщений по истечении заданного периода времени? При использовании Kafka в качестве источника событий сообщения должны храниться неограниченное время. Это, вероятно, настраивается, но не вызовет ли это проблемы?
Герт-Ян
2
Есть ли сравнения между кафкой и eventtore? В частности, мне нравится фокус на FRP в хранилище событий под названием Projection. Есть ли что-то подобное в Кафке / Самзе?
CMCDragonkai
4
Меня также интересует вопрос @ Geert-Jan к Джею. Kafka не подходит для транзакционной стороны фактического поиска событий из-за необходимости потока событий (темы) для каждой совокупности доменов (думаю, миллионов). Однако он идеально подходит для подачи в него событий, например, из GetEventStore. Но это будет работать только с бесконечно сохраненными событиями (в нашем случае), и, кроме нескольких кратких комментариев, это не похоже на поддерживаемый вариант использования Kafka? Я здесь ошибаюсь? Самза, например, предполагает, что есть только два сценария: задержка на основе времени или задержка на основе ключей. Есть другие ..
Стивен Дрю
3
@eulerfx Предполагая, что мы хотели бы использовать Kafka в качестве хранилища для системы источников событий, как следует реализовать оптимистическую блокировку / параллелизм?
Кшиштоф Браницкий
51

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

TL; DR. Да или Нет, в зависимости от вашего использования источника событий.

Я знаю о двух основных видах систем, основанных на событиях.

Процессоры нижестоящих событий = Да

В такой системе события происходят в реальном мире и записываются как факты. Например, складская система для отслеживания поддонов с продуктами. Там в основном нет конфликтующих событий. Все уже произошло, даже если это было не так. (Т.е. поддон 123456 поставлен на грузовик А, но был запланирован на грузовик Б.) Затем позже факты проверяются на наличие исключений с помощью механизмов отчетности. Кафка, кажется, хорошо подходит для такого рода нисходящего потока приложений для обработки событий.

В этом контексте понятно, почему люди Kafka отстаивают его как решение для поиска событий. Потому что это очень похоже на то, как оно уже используется, например, в потоках кликов. Однако люди, использующие термин Event Sourcing (в отличие от Stream Processing), скорее всего, ссылаются на второе использование ...

Контролируемый приложением источник правды = Нет

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

Отсутствие изоляции объекта

В этом сценарии требуется возможность загрузки потока событий для конкретной сущности. Распространенной причиной этого является построение модели переходной записи для бизнес-логики, используемой для обработки запроса. Делать это нецелесообразно в Кафке. Использование темы для каждой сущности может позволить это, за исключением того, что это не начало, когда могут быть тысячи или миллионы сущностей. Это связано с техническими ограничениями в Kafka / Zookeeper.

Одна из основных причин использования модели переходной записи таким образом - сделать изменения в бизнес-логике дешевыми и легкими в развертывании.

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

Отсутствие обнаружения конфликта

Во-вторых, пользователи могут создавать условия гонки из-за одновременных запросов к одному и тому же объекту. Может быть весьма нежелательно сохранять конфликтующие события и разрешать их по факту. Поэтому важно уметь предотвращать конфликтующие события. Чтобы масштабировать загрузку запроса, обычно используют службы без сохранения состояния, предотвращая конфликты записи с использованием условных записей (запись только, если последним событием объекта был #x). Ака Оптимистичный Параллелизм. Кафка не поддерживает оптимистичный параллелизм. Даже если бы он поддерживал это на уровне темы, он должен был бы быть полностью вплоть до уровня сущности, чтобы быть эффективным. Чтобы использовать Kafka и предотвращать конфликтующие события, вам нужно использовать сериализованный писатель с сохранением состояния на уровне приложения. Это существенное архитектурное требование / ограничение.

Дальнейшая информация


Обновление за комментарий

Комментарий был удален, но вопрос был что-то вроде: что люди тогда используют для хранения событий?

Кажется, что большинство людей катят свою собственную реализацию хранилища событий поверх существующей базы данных. Для нераспределенных сценариев, таких как внутренние серверные или автономные продукты, хорошо документировано, как создать хранилище событий на основе SQL. И есть библиотеки, доступные поверх различных видов баз данных. Существует также EventStore , который построен для этой цели.

В распределенных сценариях я видел несколько разных реализаций. Проект Jet Panther использует Azure CosmosDB с функцией Change Feed для уведомления слушателей. Еще одна похожая реализация, о которой я слышал в AWS, - это использование DynamoDB с функцией Streams для уведомления слушателей. Ключ раздела, вероятно, должен быть идентификатором потока для лучшего распределения данных (чтобы уменьшить объем избыточного выделения ресурсов). Тем не менее, полное воспроизведение через потоки в Динамо является дорогостоящим (чтение и стоимость). Так что это подразумевалось также для Dynamo Streams для выгрузки событий на S3. Когда новый слушатель подключается к сети или существующий слушатель хочет полного воспроизведения, он будет читать S3, чтобы наверстать упущенное.

Мой текущий проект - мультитенантный сценарий, и я перевернул свой собственный поверх Postgres. Что-то вроде Citus кажется подходящим для масштабируемости, разделения по tentant + stream.

Кафка все еще очень полезна в распределенных сценариях. Нетривиальная проблема - выставлять события каждого сервиса другим сервисам. Хранилище событий, как правило, не создается для этого, но это именно то, что делает Кафка хорошо. Каждый сервис имеет свой собственный внутренний источник правды (может быть хранилище событий или другое), но слушает Кафку, чтобы узнать, что происходит «снаружи». Служба также может публиковать события в Кафке, чтобы информировать «извне» об интересных вещах, которые сделал служба.

Кейси Спикман
источник
1
@Dominik Я упомянул EventStore в разделе «Обновление» (2-й абзац). Я вернусь и свяжу это. Я попробовал это, и у него есть впечатляющий результат. Для нашей небольшой команды на данный момент считалось более важным не вводить другую базу данных, поэтому Postgres (которая также используется для представлений). Возможно, что мы перейдем в EventStore в будущем или в будущих продуктах.
Кейси
2
@KaseySpeakman Темы не совпадают с разделами. В теме есть один или несколько разделов. У разделов гарантированно будет только один потребитель на группу в любой данный момент. Разделите ваши сущности таким образом, чтобы воспользоваться этим. Вам не нужна тема для каждой сущности или даже раздел для каждой сущности. Вам просто нужно разделить их таким образом, чтобы гарантировать, что все команды, адресованные одному и тому же объекту, идут в один и тот же раздел.
Эндрю Ларссон
1
@KaseySpeakman Многие объекты могут совместно использовать один раздел. Кто сказал, что вы всегда должны загружать состояние объекта непосредственно из хранилища событий, воспроизводя события? Существуют и другие способы реализации той же концепции без строгого следования поэтапной реализации Грега Янга.
Эндрю Ларссон
1
@AndrewLarsson Если вы не разбиваете разделы на сущности, то как вы собираетесь предотвращать конфликтующие события на уровне сущностей? Поскольку мы прошли полный цикл назад к конфликтам параллелизма, возможно, вам следует опубликовать свою собственную статью на носителе или что-то вроде того, как вы использовали Kafka для получения событий (а не потоковой обработки) в производстве. Как это сделать с разделением по типу и без контроля параллелизма на уровне объекта. Я прочитал бы это, и я даже не буду троллить вас в комментариях, если я не согласен.
Кейси
2
@ KaseySpeakman Использование Кафки таким способом непросто. Но если вы находитесь в масштабе, где вы серьезно рассматриваете CQRS и Event Sourcing, то вы находитесь в масштабе, когда вы не можете позволить себе делать вещи простым способом. Ваша модель параллелизма напрямую влияет на ваш масштаб - не выбирайте ее произвольно. Кроме того, HTTP не является надежным транспортным средством, и, опять же, если вы находитесь в таком масштабе, вы не можете позволить себе тратить время на решение проблем с потерянными и / или дублированными сообщениями. Все это можно решить с помощью Kafka между клиентом и командным процессором, но да, это достигается ценой сложности.
Эндрю Ларссон
20

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

  • Kafka гарантирует только один раз доставку, и в хранилище событий есть дубликаты, которые нельзя удалить. Обновление: здесь вы можете прочитать, почему это так сложно с Кафкой, и некоторые последние новости о том, как наконец добиться этого поведения: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how. -apache-Кафка-делает-то /
  • Из-за неизменности, нет никакого способа манипулировать хранилищем событий, когда приложение развивается, и события должны быть преобразованы (существуют, конечно, такие методы, как апкастинг, но ...). Однажды может быть сказано, что вам никогда не нужно преобразовывать события, но это неверное предположение, может быть ситуация, когда вы делаете резервную копию оригинала, но вы обновляете их до последних версий. Это действительное требование в управляемых событиями архитектурах.
  • Нет места для сохранения снимков сущностей / агрегатов, и воспроизведение будет становиться все медленнее и медленнее. Создание снимков должно быть характерно для хранилища событий в долгосрочной перспективе.
  • С учетом того, что разделы Кафки распределены и ими сложно управлять и их резервное копирование сравнивают с базами данных. Базы данных просто проще :-)

Итак, прежде чем сделать свой выбор, подумайте дважды. Хранилище событий как комбинация интерфейсов прикладного уровня (мониторинг и управление), хранилище SQL / NoSQL и Kafka в качестве брокера - лучший выбор, чем предоставление Kafka обеих функций для создания полноценного полнофункционального решения.

Хранилище событий - это сложный сервис, который требует большего, чем может предложить Kafka, если вы серьезно относитесь к использованию источников событий, CQRS, Sagas и других шаблонов в архитектуре, управляемой событиями, и сохраняете высокую производительность.

Не стесняйтесь оспаривать мой ответ! Возможно, вам не понравится то, что я скажу о вашем любимом брокере с множеством перекрывающихся возможностей, но, тем не менее, Kafka не был разработан как хранилище событий, а больше как высокопроизводительный брокер и буфер одновременно для обработки быстрых производителей по сравнению со сценариями для медленных потребителей, например.

Пожалуйста, посмотрите на фреймворк с открытым исходным кодом для микросервисов eventuate.io, чтобы узнать больше о потенциальных проблемах: http://eventuate.io/

Дополнение от 8.02 2018

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

  1. Не используйте Spring - это здорово (я сам часто его использую), но оно тяжелое и медленное одновременно. И это совсем не микросервисная платформа. Это «просто» фреймворк, чтобы помочь вам реализовать его (много работы за этим ..). Другие фреймворки - это "просто" облегченные REST или JPA или фреймворки с различной ориентацией. Я рекомендую, вероятно, лучшую в своем классе полную микросервисную платформу с открытым исходным кодом, которая возвращается к чистым корням Java: https://github.com/networknt

Если вас интересует производительность, вы можете сравнить себя с существующим набором тестов. https://github.com/networknt/microservices-framework-benchmark

  1. Ни в коем случае не используйте Кафку :-)) Это наполовину шутка. Я имею в виду, что, хотя Кафка великолепен, это еще одна система, ориентированная на брокеров. Я думаю, что будущее за системами обмена сообщениями без посредников. Вы можете быть удивлены, но есть более быстрые, чем системы Kafka :-), конечно, вы должны перейти на более низкий уровень. Посмотри Хронику.

  2. Для хранилища событий я рекомендую улучшенное расширение Postgresql под названием TimescaleDB, которое ориентировано на высокопроизводительную обработку данных временных рядов (события являются временными рядами) в большом объеме. Конечно, CQRS, Event Sourcing (функции воспроизведения и т. Д.) Встроены в фреймворк light4j из коробки, который использует Postgres в качестве места для хранения.

  3. Для обмена сообщениями попробуйте взглянуть на Chronicle Queue, Map, Engine, Network. Я имею в виду избавиться от этого старомодного решения, ориентированного на брокера, и использовать микросистему сообщений (встроенную). Хроника очереди на самом деле даже быстрее, чем Кафка. Но я согласен, что это не все в одном решении, и вам нужно заняться разработкой, иначе вы пойдете и купите версию Enterprise (платную). В конце концов, усилия по созданию из Chronicle собственного уровня обмена сообщениями будут оплачены за счет снятия бремени обслуживания кластера Kafka.

Kensai
источник
Интересная точка зрения. Хотите уточнить некоторые моменты? > Кафка гарантирует только один раз доставку, и в хранилище событий есть дубликаты, которые нельзя удалить. Вы, похоже, подразумеваете, что существует такая вещь, как ровно один раз доставки. afaik (и я почти уверен в этом) в распределенной системе такого нет. 2) Что касается вашего пункта 2: классическая школа (Event Sourcing / DDDD) считает, что события по своей природе неизменны. Т.е.: они случаются, нет возможности изменить прошлое. Каков реальный случай их изменения в ретроспективе? Спасибо!
Герт-Янв
1.) Hazelcast, чтобы гарантировать, что каждое сообщение будет обработано один и только один раз. 2.) Мне не нравится ничего похожего на _V2 в служебном коде, поэтому либо вы будете выполнять резервное копирование в архив и воссоздавать старые события в их новых версиях (у вас все еще есть исходная правда), либо вы можете скрыть / встроить эту функцию непосредственно в Event Сохраните функциональность снимка, так что есть единственная точка апскейтинга -> хранилище событий. Каковы ваши решения для этого?
Кенсай
1) хотя бы один раз + идемпотентность на потребителя. То есть: проверить, если событие уже видел. Если так, пропустите. Или, что еще лучше, совершайте идемпотентные действия. Конечно, это не всегда возможно. 2) Я никогда не сталкивался с необходимостью версий событий. Я всегда отношусь к самим событиям как к источнику правды и включаю в них всю необходимую мне информацию. Делая это, я никогда не сталкивался с ситуацией, когда мне требовалась другая структура события и / или данные о событии. Но, возможно, мммм. Заинтересованы в том, чтобы узнать, в каких ситуациях вам действительно нужно иметь обновленные события.
Герт-Янв
1.) может быть способом выбора .. 2.) тогда ваши структуры данных были идеальны с самого начала :-) удачи вам, ха-ха. Мне может не понадобиться это в моем текущем проекте, но я строю целую платформу на форках eventuate.io, объединенных с некоторыми высокопроизводительными JEE-подходами, взятыми из light eventuate 4j ... во всей этой дискуссии нет места для комментариев по stackoverflow , но если вы заинтересованы в более глубоком погружении, я рекомендую эту статью: leanpub.com/esversioning/read
kensai
1
Кстати, Kafka поддерживает доставку только один раз. Обновление пули 1
OneCricketeer
8

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

Что касается:

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

Это может быть сложно. Я подробно рассказал об этом здесь: https://stackoverflow.com/a/48482974/741970

Дмитрий Минковский
источник
0

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

Бриендра Верма
источник
0

Я думаю, что вы должны взглянуть на рамки аксонов вместе с их поддержкой Кафки

Даршу БК
источник