Перейти к содержимому

Kafka как хранилище

Kafka как хранилище — это использование распределённого журнала (log) для долгосрочного хранения событий, где сообщения не удаляются после прочтения, а сохраняются заданное время (retention) или до достижения лимита объёма. В отличие от традиционных брокеров (RabbitMQ), Kafka позволяет перечитывать историю, воспроизводить события с любого offset, использовать компактизацию (оставлять только последнее сообщение по ключу) и применять потоковую обработку (Kafka Streams, ksqlDB). Основные сценарии: event sourcing (источник истины — поток событий), CQRS, CDC (Change Data Capture), аудит, аналитика в реальном времени и восстановление состояния сервисов. Однако Kafka не заменяет базу данных: нет обновлений (только append), сложных запросов и JOIN без дополнительных инструментов, а retention ограничен — данные рано или поздно удаляются. Типичная архитектура: Kafka для истории изменений, база данных для текущего состояния.

Введение: Журнал, который никогда не выбрасывает черновики

Представьте, что вы ведёте дневник. Вы пишете каждый день. Вы можете перечитать записи за прошлый месяц, прошлый год, за всё время. Вы можете начать читать с любого места. Вы можете искать по датам. Дневник — это не просто “передача сообщений”. Это хранилище вашей истории.

Большинство брокеров сообщений (RabbitMQ, ActiveMQ) — как почтовый ящик. Вы отправили письмо, адресат прочитал — письмо исчезло. Они не хранят историю.

Kafka — другой подход. Это журнал (log). Сообщения не исчезают после прочтения. Они хранятся дни, недели, месяцы. Любой потребитель может прочитать любое сообщение в любое время. Kafka — это брокер, который одновременно является хранилищем данных.

Kafka как хранилище означает, что вы можете использовать её не только для передачи сообщений между сервисами, но и для долгосрочного хранения данных, для воспроизведения истории (replay), для анализа потоков данных. Вы можете перечитать события, которые произошли неделю назад. Вы можете подключить новый сервис и дать ему прочитать всю историю событий.

Для системного аналитика понимание Kafka как хранилища открывает новые возможности: event sourcing (источником истины становится поток событий), CQRS (разделение команд и запросов), аналитика на потоковых данных, замена классических баз данных в некоторых сценариях.

Kafka vs Традиционные брокеры

ХарактеристикаТрадиционный брокер (RabbitMQ)Kafka
После прочтенияСообщение удаляетсяСообщение остаётся
Повторное чтениеНевозможноМожно (по offset)
ХранениеВременно (пока не доставлено)Длительное (дни, месяцы)
ИсторияНетДа
Основное применениеОчереди задачПотоки событий, хранилище

Какие данные можно хранить в Kafka

События (Events)

Всё, что произошло в системе, и важно сохранить.

Примеры событий:
  - Пользователь создан
  - Заказ оформлен
  - Платёж прошёл
  - Товар отгружен

Журналы изменений (Change Log)

Последовательность изменений состояния.

Журнал изменений пользователя:
  offset 0: user_123, {name: "Иван", status: "active"}
  offset 1: user_123, {name: "Иван", status: "blocked"}
  offset 2: user_123, {name: "Иван", status: "deleted"}

CDC (Change Data Capture)

Лог изменений из базы данных.

CDC поток из PostgreSQL:
  - INSERT в таблицу users
  - UPDATE в таблицу orders
  - DELETE из таблицы sessions

Аудитные логи

Кто, когда, что сделал.

Аудит действий администратора:
  - admin: user_456 изменил роль
  - admin: user_789 удалил заказ

Особенности хранения в Kafka

Журнальная структура (Log)

Данные хранятся в виде последовательности сообщений. Каждое сообщение имеет смещение (offset) — порядковый номер внутри партиции.

Партиция 0:
  offset 0: {user_id: 123, action: "login"}
  offset 1: {user_id: 123, action: "search"}
  offset 2: {user_id: 456, action: "login"}
  offset 3: {user_id: 123, action: "logout"}

Свойства:

СвойствоЗначение
УпорядоченностьПорядок сообщений гарантирован внутри партиции
НеизменяемостьНельзя изменить или удалить сообщение (только по retention)
Детерминированный доступЧтение по offset (O(1))

Retention (Срок хранения)

Данные хранятся ограниченное время или до достижения лимита объёма.

retention.ms = 604800000 (7 дней)
retention.bytes = 1073741824 (1 ГБ на партицию)

Что это значит для хранилища: Kafka не подходит для хранения данных “навсегда”. Данные рано или поздно удаляются. Для долгосрочного хранения нужна выгрузка в другие системы (S3, HDFS).

Компактизация (Compaction)

Оставляет только последнее сообщение для каждого ключа.

Исходный лог:
  key: user_123 → {status: "active"}
  key: user_123 → {status: "blocked"}
  key: user_123 → {status: "deleted"}

После компактизации:
  key: user_123 → {status: "deleted"}  # только последнее

Когда это полезно: Хранение текущего состояния. Таблицы в Kafka (KTable).

Сценарии использования Kafka как хранилища

1. Event Sourcing (Хранилище событий)

Все изменения состояния системы хранятся как последовательность событий. Текущее состояние вычисляется путём воспроизведения событий.

События пользователя:
  - Событие: UserCreated (id=123, name="Иван")
  - Событие: UserRenamed (id=123, new_name="Иван Петров")
  - Событие: UserBlocked (id=123)

Текущее состояние (вычисленное):
  - id=123, name="Иван Петров", status="blocked"

Почему Kafka: Хранит события в порядке, можно воспроизвести с любого момента.

2. CQRS (Command Query Responsibility Segregation)

Команды (запись) идут в Kafka. Отдельные сервисы читают события и строят оптимизированные модели для чтения.

Команда: CreateOrder
  → Kafka (событие OrderCreated)
    → Сервис записи (обновляет источник истины)
    → Сервис чтения (обновляет денормализованную view)

3. Замена базы данных для некоторых сценариев

Kafka может заменить базу данных, если:

  • Вам нужна только последовательная запись (нет обновлений)
  • Вам нужен доступ по первичному ключу (key-value)
  • Вам не нужны сложные запросы (JOIN, агрегации)

Что нельзя делать с Kafka:

ОперацияПоддержка в Kafka
Обновление записиНет (только новая запись)
Удаление записиНет (только через компактизацию)
SELECT с условиямиНет (только по ключу или по offset)
JOINНет (только через Streams)

4. Окно истории для новых сервисов

Новый сервис может прочитать всю историю событий и построить своё состояние.

Новый сервис аналитики:
  1. Подключается к Kafka
  2. Читает все события за последние 30 дней
  3. Строит аналитические отчёты
  4. Продолжает читать новые события

5. Аналитика на потоковых данных

Обработка и анализ данных в реальном времени.

Kafka Streams:
  - Подсчёт событий по окнам
  - Агрегации
  - Обогащение потоков
  - Join потоков

6. Резервное копирование и восстановление

Kafka хранит события. Если система обработки потеряла состояние, она может перечитать события и восстановиться.

Сервис упал:
  1. Восстановился
  2. Читает события с последнего сохранённого offset
  3. Восстанавливает состояние

Ограничения Kafka как хранилища

1. Нет случайного доступа по значению

Можно читать только по offset или по ключу (в компактифицированных топиках). Нельзя SELECT * FROM topic WHERE field = value.

Обход: Отдельный индекс в другой системе (Elasticsearch, Redis).

2. Нет обновлений

Нельзя изменить уже записанное сообщение. Только написать новое.

Обход: Компактизация для key-value сценариев.

3. Retention ограничен

Данные не хранятся вечно. Рано или поздно удаляются.

Обход: Выгрузка в долгосрочные хранилища (S3, HDFS).

4. Нет транзакций между топиками

Транзакции в Kafka работают в пределах одного топика. Нельзя атомарно обновить два топика.

5. Запросы сложнее, чем SQL

Нет SQL. Нужно писать код (Kafka Streams, ksqlDB, или свой потребитель).

Kafka vs Базы данных

ХарактеристикаPostgreSQLKafka
Модель данныхТаблицы, строки, колонкиЖурнал, ключ-значение
ОбновлениеUPDATE, DELETEТолько INSERT
ЧтениеSELECT с условиями, JOINПо offset, по ключу
ИсторияТолько текущее состояние (без аудита)Полная история
ПорядокНе гарантированГарантирован внутри партиции
Производительность записиТысячи TPSМиллионы TPS
Производительность чтенияБыстро (с индексами)Последовательно (быстро)
RetentionВечноОграничен

Практические примеры

Пример 1: Event Sourcing для корзины покупок

Топик: cart_events

События:
  - ItemAdded (user=123, product=456, quantity=1)
  - ItemAdded (user=123, product=789, quantity=2)
  - ItemRemoved (user=123, product=456)
  - CartCheckedOut (user=123)

Потребитель:
  - Читает события для user=123
  - Восстанавливает состояние корзины
  - Применяет команды

Пример 2: CDC из PostgreSQL в Kafka

Исходная таблица: orders

Debezium (CDC):
  - Ловит изменения в PostgreSQL
  - Публикует в Kafka

Потребители:
  - Сервис аналитики: считает метрики
  - Сервис поиска: обновляет Elasticsearch
  - Хранилище данных: загружает в ClickHouse

Пример 3: Хранилище последних состояний (KTable)

Топик: user_events (компактифицированный)

Kafka Streams:
  - Строит KTable (последнее состояние по ключу)
  - user_123: {status: "active", last_login: "2024-01-15"}
  - user_456: {status: "blocked", last_login: "2024-01-10"}

Интерактивные запросы:
  - Получить статус user_123 (через IQ)

ksqlDB: SQL для Kafka

ksqlDB — это движок потоковой обработки с SQL-интерфейсом.

-- Создать поток из топика
CREATE STREAM user_events (
  user_id INT,
  action VARCHAR
) WITH (KAFKA_TOPIC='user_events', VALUE_FORMAT='JSON');

-- Подсчёт действий по пользователям
SELECT user_id, COUNT(*) FROM user_events
GROUP BY user_id
EMIT CHANGES;

-- Соединить два потока
SELECT * FROM user_events u
JOIN user_profiles p ON u.user_id = p.id;

Когда использовать Kafka как хранилище

Подходит

СценарийПочему
Событийная архитектураНужна история событий
Event SourcingПоток событий как источник истины
CDCЛог изменений базы данных
Аналитика на потоковых данныхОбработка в реальном времени
Воспроизводимые вычисленияМожно пересчитать результат с начала
АудитНужно знать, кто что делал

Не подходит

СценарийПочему
Традиционное CRUD-приложениеНужны обновления, удаления, сложные запросы
Данные, которые нельзя потерятьRetention удаляет старые данные
Маленькие объёмыИзбыточно
Требуются JOIN с большим количеством таблицKafka не оптимизирована для этого

Распространённые ошибки

Ошибка 1: Kafka как единственное хранилище

Думают, что Kafka заменит PostgreSQL. Но в Kafka нет обновлений, нет сложных запросов, нет индексов.

Решение: Kafka для событий, PostgreSQL для текущего состояния.

Ошибка 2: Бесконечное хранение

Устанавливают бесконечный retention. Место кончается.

Решение: retention = 7-30 дней. Выгружать старые данные в S3/HDFS.

Ошибка 3: Использование Kafka для маленьких объёмов

Несколько событий в день. Kafka избыточна.

Решение: PostgreSQL с аудитом.

Ошибка 4: Попытка обновить сообщение

Пытаются изменить уже записанное сообщение.

Решение: Записать новое сообщение с тем же ключом, использовать компактизацию.

Ошибка 5: Игнорирование компактизации

Хранят историю изменений, но никогда не компактизируют. Место растёт.

Решение: Включить компактизацию для key-value сценариев.

Резюме

  1. Kafka как хранилище — это использование журнальной структуры для хранения событий. Данные не удаляются после прочтения, хранятся определённое время.

  2. Ключевые сценарии: event sourcing, CQRS, CDC, аналитика, аудит, восстановление состояния.

  3. Ограничения: нет обновлений, нет сложных запросов, retention ограничен, нет SQL (без ksqlDB).

  4. Компактизация позволяет хранить только последнее состояние (key-value хранилище).

  5. Kafka не заменяет базы данных. Она дополняет их. База данных для текущего состояния, Kafka для истории изменений.

  6. ksqlDB добавляет SQL-интерфейс для потоковой обработки.

Проверка знаний

Вопрос 1 из 4
Почему Kafka иногда рассматривается как хранилище, а не только как брокер?
Какой сценарий особенно подходит под 'Kafka как хранилище'?
Какое ограничение важно помнить, даже если Kafka используется как хранилище?
Что делает возможным повторное чтение истории в Kafka?

Вопросы, где были ошибки