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