Запросить демо
Триггерные сценарии

Outbox pattern вместо Kafka: событийная модель для CDP

Почему on-prem CDP не нуждается в Kafka на старте. Outbox pattern на PostgreSQL: архитектура, гарантия доставки, масштабирование. Для CTO и архитекторов.

Категория
Триггерные сценарии
Время чтения
7 минут
Опубликовано
Автор
stackfort

Ключевые выводы

  • Outbox pattern CDP — архитектурный приём, при котором событие записывается в таблицу PostgreSQL в той же транзакции, что и бизнес-операция. Гарантия: exactly-once семантика без внешнего брокера
  • PostgreSQL с outbox pattern обрабатывает 3-5 тысяч событий/секунду — пятикратный запас для CDP с базой до 700 тысяч клиентов
  • Отказ от Kafka на старте снижает инфраструктурные затраты на 40-60% и убирает 3-5 узлов из baseline
  • Архитектура спроектирована для эволюции: переход на NATS или Kafka при масштабировании не требует переписывания

«Вам нужна Kafka» — фраза, которую слышит каждый CTO на этапе выбора CDP-платформы. Вендоры включают её в архитектурные схемы как само собой разумеющееся. Между тем для 90% enterprise-внедрений с базой до 700 тысяч клиентов Kafka — это архитектурный overkill, который добавляет 3-5 узлов, ZooKeeper и выделенную команду для обслуживания.

Outbox pattern CDP на PostgreSQL решает ту же задачу — гарантированная доставка событий для триггерных сценариев — но без внешнего брокера. Разберём, как это работает и когда действительно нужна event bus.

Зачем CDP нужна событийная модель

Прежде чем говорить об outbox pattern, зафиксируем задачу. CDP — платформа, управляемая событиями. Каждое действие клиента — это событие:

  • Зашёл на сайт — page_view
  • Добавил товар в корзину — cart_add
  • Оплатил заказ — purchase
  • Позвонил в контакт-центр — call_inbound
  • Открыл email — email_open

Триггерные сценарии реагируют на эти события: «если cart_add и нет purchase в течение 2 часов — отправить напоминание». Для этого CDP должна надёжно фиксировать каждое событие и гарантировать его обработку.

Классический подход — Kafka или другой message broker. Событие публикуется в топик, потребители забирают и обрабатывают. Надёжно, масштабируемо, проверено. Однако для on-prem CDP с lean-архитектурой это означает +3-5 узлов в инфраструктуре с первого дня.

Outbox pattern: как это работает

Outbox pattern CDP — это способ гарантировать атомарность бизнес-операции и события без внешнего брокера. Вся магия — в одной транзакции PostgreSQL.

Схема

  1. Бизнес-операция. Клиент совершает действие — например, оформляет заказ. CDP обновляет профиль клиента и записывает заказ в основную таблицу
  2. Запись события. В той же транзакции CDP записывает событие purchase в таблицу outbox — специальную таблицу для исходящих событий
  3. Commit. PostgreSQL фиксирует обе записи атомарно: либо обе, либо ни одной. Если транзакция откатывается — события нет
  4. Worker. Отдельный процесс (polling worker) периодически забирает новые записи из outbox batch-запросом
  5. Обработка. Worker отправляет событие в rules engine (триггерные сценарии), обновляет сегменты, логирует
  6. Подтверждение. После успешной обработки запись помечается как обработанная (или удаляется)

Результат: exactly-once семантика. Событие не может потеряться (оно в PostgreSQL) и не может обработаться дважды (идемпотентность по уникальному ID).

Структура outbox-таблицы

ПолеТипНазначение
idUUIDУникальный идентификатор события
event_typeVARCHARТип: purchase, cart_add, page_view
profile_idUUIDСсылка на профиль клиента
payloadJSONBДанные события (сумма, товар, канал)
created_atTIMESTAMPВремя создания
processedBOOLEANФлаг обработки

Индекс по (processed, created_at) обеспечивает быструю выборку необработанных событий. Worker забирает batch по 100-500 записей, обрабатывает, помечает — и берёт следующий batch.

Производительность: цифры вместо обещаний

Главный вопрос CTO: хватит ли PostgreSQL? Ответ — да, с запасом. Вот реальные показатели:

МетрикаOutbox pattern (PostgreSQL)Kafka (3 брокера)
Пропускная способность3-5 тыс. событий/сек100+ тыс. событий/сек
Latency (p99)50-200 мс5-20 мс
Узлы инфраструктуры0 дополнительных3-5 (брокеры + ZooKeeper)
Команда поддержкиНе требуется отдельно1-2 инженера
Exactly-onceДа (в рамках транзакции)Да (с настройкой)

Для CDP с базой 150-700 тысяч клиентов и 50 триггерных сценариев реальная нагрузка — 200-800 событий/секунду. Outbox pattern даёт пятикратный запас. Kafka — стократный, но за это приходится платить инфраструктурой.

90% enterprise-внедрений CDP не превышают 1000 событий/секунду. Kafka на этом масштабе — всё равно что арендовать грузовик для перевозки одной коробки.

Экономия инфраструктуры: что значит «минус Kafka»

Убрать Kafka из baseline CDP — это не просто «убрать один компонент». Это каскадный эффект:

  • Минус 3-5 серверов. Kafka production-кластер — минимум 3 брокера + ZooKeeper. Для on-prem это физические серверы или VM
  • Минус выделенная экспертиза. Kafka требует специфических знаний: partitioning, consumer groups, retention policies, monitoring. Без выделенного инженера — риск
  • Минус 40-60% инфраструктурных затрат. Для конфигурации «Minimum» (1 узел) отсутствие Kafka и ZooKeeper сокращает требования к ресурсам почти вдвое
  • Минус 2-4 недели внедрения. Настройка Kafka, интеграция с CDP, тестирование failover — это время, которое добавляется к проекту

Подробнее о профилях мощностей и стоимости — на странице On-prem CDP платформа для enterprise.

Эволюция архитектуры: от outbox к event bus

Outbox pattern CDP — не тупик, а отправная точка. Архитектура спроектирована так, что переход на event bus (NATS или Kafka) происходит без переписывания бизнес-логики.

Три этапа масштабирования

ЭтапИнфраструктураСобытийная модельНагрузка
Minimum1 узелOutbox pattern (PostgreSQL)до 3-5 тыс. событий/сек
Recommended3 узлаOutbox + NATSдо 10-15 тыс. событий/сек
HA5 узловNATS / Kafka50+ тыс. событий/сек

На этапе Minimum worker забирает события из outbox-таблицы напрямую. На этапе Recommended между outbox и потребителями появляется NATS — лёгкая event bus, которая добавляет fan-out без тяжести Kafka. И только на этапе HA, при нагрузке 50+ тысяч событий/секунду, появляется Kafka с полным distributed-стеком.

Ключевой принцип: бизнес-логика CDP не знает, куда уходит событие — в outbox-таблицу или в NATS-топик. Абстракция event publisher скрывает реализацию. Переключение — вопрос конфигурации, а не рефакторинга.

Подводные камни outbox pattern

Outbox pattern — не серебряная пуля. Есть ограничения, которые нужно учитывать при проектировании:

Latency polling-а

Worker опрашивает outbox-таблицу с интервалом 100-500 мс. Это означает задержку между записью события и его обработкой. Для триггерных сценариев CDP (отправить email через 2 часа после брошенной корзины) — некритично. Для real-time персонализации на сайте — может быть недостаточно.

Решение: PostgreSQL LISTEN/NOTIFY — push-уведомление worker'у при новой записи в outbox. Снижает latency до 10-50 мс без внешнего брокера.

Рост таблицы

При 1000 событий/секунду outbox-таблица растёт на ~86 миллионов записей в сутки. Без очистки — это десятки гигабайт в неделю.

Решение: TTL-политика — обработанные события удаляются через 24-72 часа. Архивные события переносятся в отдельную таблицу или сжатое хранилище.

Один потребитель

В базовой реализации outbox pattern worker — один. Если нужно раздать событие нескольким потребителям (rules engine + analytics + audit log) — нужен либо fan-out внутри worker'а, либо event bus.

Решение: на этапе Minimum — fan-out внутри worker'а (последовательная обработка). На этапе Recommended — переход на NATS с fan-out по подпискам.

Итого

Outbox pattern CDP — это архитектурно честный выбор для 90% enterprise-внедрений. PostgreSQL с правильной индексацией обрабатывает 3-5 тысяч событий/секунду — пятикратный запас для базы до 700 тысяч клиентов. Kafka на этом масштабе избыточна и добавляет 3-5 узлов, выделенную экспертизу и недели внедрения.

Главное преимущество lean-архитектуры — эволюционность. Начинаете с outbox pattern на 1 узле, добавляете NATS при росте до 3 узлов, переходите на Kafka только при HA-конфигурации. Бизнес-логика при этом не меняется.

Хотите разобрать архитектуру событийной модели для вашего масштаба? Запишитесь на техническую консультацию — спроектируем контур под конкретную нагрузку и сценарии.

FAQ о outbox pattern CDP

Outbox pattern — это замена Kafka?

Не замена, а альтернатива для определённого масштаба. Outbox pattern покрывает задачи CDP с базой до 700 тысяч клиентов и нагрузкой до 3-5 тысяч событий/секунду. Когда нагрузка превышает этот порог или нужен fan-out на 5+ потребителей — добавляется event bus (NATS или Kafka). Архитектура спроектирована так, что переход не требует переписывания.

Как outbox pattern гарантирует доставку события?

Бизнес-операция и запись события происходят в одной транзакции PostgreSQL. Если транзакция откатывается — события нет. Если фиксируется — событие гарантированно в outbox-таблице. Worker забирает события batch-запросом и отправляет в обработку. Идемпотентность обеспечивается уникальным ID события.

Какую нагрузку выдерживает outbox pattern без event bus?

PostgreSQL с правильной индексацией и batch polling — 3-5 тысяч событий/секунду на одном узле. Для CDP с базой 150-700 тысяч клиентов и 50 триггерных сценариев реальная нагрузка — 200-800 событий/секунду. Запас — пятикратный.

Когда всё-таки нужна Kafka или NATS в CDP?

Два сигнала: нагрузка стабильно превышает 3 тысячи событий/секунду (база от 2+ миллионов активных профилей), или требуется fan-out на 5+ независимых потребителей одновременно. На практике это уровень HA-конфигурации — третий этап масштабирования, а не стартовый.