OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

CDC в PostgreSQL с Debezium: logical decoding, Kafka/Redpanda и outbox

Разбираем, как включить logical decoding, настроить replication slots, выбрать pgoutput или wal2json и подключить Debezium к Kafka/Redpanda. Покажу конфигурации, снапшоты, outbox, мониторинг лага и типичные ошибки в продакшене.
CDC в PostgreSQL с Debezium: logical decoding, Kafka/Redpanda и outbox

CDC (Change Data Capture) в связке PostgreSQL → Debezium → Kafka/Redpanda — это надёжный способ проталкивать изменения из OLTP-базы в стриминговую шину для аналитики, событийной интеграции и реактивных микросервисов. Но за простым обещанием «включить логическое декодирование и поставить коннектор» скрывается масса нюансов: настройки logical decoding, контроль replication slots, выбор плагина (pgoutput или wal2json), компоновка топиков, snapshot-стратегия, безопасность и мониторинг отставания.

Зачем CDC в PostgreSQL и когда он уместен

CDC позволяет получать поток событий о вставках, обновлениях и удалениях почти в реальном времени, не трогая приложение и не создавая тяжёлые триггеры. Это снижает связность систем: исходная база не знает о потребителях событий, а downstream‑компоненты (аналитика, кэширование, индексы поиска, интеграции) получают свежие данные из единого логического потока.

Основные сценарии:

  • Актуализация витрин/ODS/ELT: кластеры ClickHouse/Spark/OLAP берут изменения из Kafka/Redpanda.
  • Событийная интеграция микросервисов: публикуем доменные события и реагируем на них асинхронно.
  • Кеширование и денормализация: оперативная синхронизация материалов для поиска, рекомендаций, API-слоёв.

CDC — это не SQL‑репликация и не бэкапы. Это поток изменений на уровне журналов WAL, представленный в удобном формате для consumers.

Основы logical decoding в PostgreSQL

Логическое декодирование разбирает WAL‑записи в понятные для клиента события. Для этого включается wal_level=logical, а потребители подключаются как реплика и читают изменения через слот (replication slot). Слот фиксирует прогресс чтения: пока потребитель не подтвердит, что обработал LSN, сервер не удаляет соответствующие WAL‑сегменты. Это и благо (надёжность), и риск (рост диска при лаге).

Ключевые элементы:

  • wal_level=logical — разрешает формирование логического потока.
  • Replication slots — удерживают WAL до подтверждённой позиции (confirmed_flush_lsn для логических слотов).
  • Output plugin — преобразует события: pgoutput (встроенный, используется логической репликацией и Debezium по умолчанию) или wal2json (формат JSON).

pgoutput vs wal2json

pgoutput — стандартный, поддерживает DDL‑события и хорошо интегрирован с публикациями/подписками. Debezium 2.x использует pgoutput по умолчанию и умеет автоматически создавать PUBLICATION под заданные таблицы (или создавайте публикации вручную под нужные права).

wal2json даёт чистый JSON и популярен там, где он уже принят как стандарт. Его нужно установить и следить за совместимостью версий. В новых инсталляциях чаще берут pgoutput ради поддержки DDL и отсутствия внешних зависимостей.

Подготовка PostgreSQL к CDC

Минимальные настройки в postgresql.conf (значения подбирайте по своему трафику и SLA):

# postgresql.conf
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
wal_keep_size = 2048MB
max_worker_processes = 16
max_logical_replication_workers = 8
max_sync_workers_per_subscription = 4
logical_decoding_work_mem = 128MB
shared_buffers = 25% # ориентир, зависит от памяти

Создаём роль для Debezium с минимально необходимыми правами:

CREATE ROLE debezium WITH LOGIN REPLICATION PASSWORD 'strong-password';
GRANT CONNECT ON DATABASE appdb TO debezium;
GRANT USAGE ON SCHEMA public TO debezium;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO debezium;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO debezium;

Для pgoutput расширение не нужно. Для wal2json потребуется установить плагин и, при необходимости, расширение:

-- Если плагин установлен на уровне сервера, расширение может не требоваться
CREATE EXTENSION IF NOT EXISTS wal2json;

Планирование ресурсов: учитывайте дополнительную нагрузку на WAL, сетевой трафик и возможный рост задержек при всплесках. Продумайте мониторинг свободного места под WAL: если consumer отстаёт, слот удержит файлы, и диск начнёт расти. Пороговые алерты по отставанию слотов обязательны. Для соединений репликации не используйте PgBouncer в режиме transaction — только прямое подключение или пулер в режиме session (подробнее см. гайд по PgBouncer и режимам пуллинга).

Debezium: варианты развертывания

Debezium — это набор коннекторов для Kafka Connect, а также самостоятельный Debezium Server. Для Kafka/Redpanda наиболее распространён вариант с Kafka Connect: запускается кластер Connect, туда через REST создаются коннекторы. Redpanda совместим с Kafka API и имеет собственные инструменты управления, но логика та же.

Когда выбирать какой режим:

  • Kafka Connect — если у вас классическая Kafka‑инфраструктура, много коннекторов и важно централизованное управление.
  • Redpanda + Connect — удобен для компактных установок без ZooKeeper, быстрый старт, те же API.
  • Debezium Server — если Kafka Connect избыточен и нужно отправлять в разные целевые системы без отдельного Connect‑кластера. Для Kafka/Redpanda чаще остаются на Connect.

Практический совет: под коннекторы, брокеры и ZooKeeper/контроллеры удобно выделять изолированные инстансы. Для гибкого масштабирования подойдёт облачный VDS для брокеров и Connect, чтобы независимо наращивать CPU/SSD и сеть.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Минимальная конфигурация коннектора Debezium PostgreSQL

Пример конфигурации для Kafka Connect, использующей pgoutput и автосоздание публикации только для выбранных таблиц:

{
  "name": "pg-app-01",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "db.internal",
    "database.port": "5432",
    "database.user": "debezium",
    "database.password": "******",
    "database.dbname": "appdb",
    "topic.prefix": "app",
    "plugin.name": "pgoutput",
    "slot.name": "debezium_app",
    "slot.drop.on.stop": "false",
    "publication.name": "app_pub",
    "publication.autocreate.mode": "filtered",
    "schema.include.list": "public",
    "table.include.list": "public.orders,public.order_items",
    "column.exclude.list": "public.users.password_hash",
    "snapshot.mode": "initial",
    "snapshot.fetch.size": "2048",
    "include.schema.changes": "true",
    "provide.transaction.metadata": "true",
    "tombstones.on.delete": "false",
    "heartbeat.interval.ms": "5000",
    "max.batch.size": "2048",
    "max.queue.size": "8192",
    "decimal.handling.mode": "string",
    "time.precision.mode": "connect",
    "database.sslmode": "require"
  }
}

Комментарии к параметрам:

  • topic.prefix формирует имена топиков: по умолчанию app.public.orders и т.п.
  • publication.autocreate.mode=filtered — Debezium создаст PUBLICATION только для выбранных таблиц (либо создайте публикацию вручную и выдайте права на неё).
  • slot.drop.on.stop=false — слот сохраняется между рестартами, что безопаснее для RPO, но требует мониторинга лага.
  • snapshot.mode: initial — единоразовый снимок и затем поток; initial_only — только снимок; never — сразу WAL без начального дампа (нужна синхронизация запуска).
  • include.schema.changes=true — в отдельный топик пойдут DDL‑события, полезно для эволюции схемы.

Выбор и настройка формата сообщений

Debezium может публиковать в Avro, JSON, Protobuf. На практике JSON — быстрый старт, Avro — строгая схема и лучшая компрессия. Для JSON-потока часто отключают схемы (value.converter.schemas.enable=false) и получают компактные полезные нагрузки.

Ключ сообщений строится на основе первичного ключа таблицы. Это важно для партиционирования и компакции. Если в таблице нет PK, укажите REPLICA IDENTITY FULL или добавьте суррогатный ключ, иначе UPDATE/DELETE не будут однозначно сопоставимы.

ALTER TABLE public.orders REPLICA IDENTITY FULL;

Диаграмма: Debezium в Kafka Connect читает PostgreSQL и публикует в топики

Паттерн Outbox: доменные события без «шторма» DDL

Outbox — способ формировать стабильный, обратно совместимый поток доменных событий, не раскрывая всю схему БД. Приложение пишет бизнес‑события в таблицу outbox, CDC считывает только её и маршрутизирует в топики по типу события. Это уменьшает связанность и облегчает эволюцию схем.

Пример таблицы:

CREATE TABLE public.outbox_events (
  id uuid primary key,
  aggregate_id uuid not null,
  aggregate_type text not null,
  event_type text not null,
  payload jsonb not null,
  headers jsonb,
  created_at timestamptz not null default now()
);

И фрагмент конфигурации коннектора с SMT Debezium Outbox:

{
  "config": {
    "table.include.list": "public.outbox_events",
    "transforms": "outbox",
    "transforms.outbox.type": "io.debezium.transforms.outbox.EventRouter",
    "transforms.outbox.table.expand.json.payload": "true",
    "transforms.outbox.route.by.field": "aggregate_type",
    "transforms.outbox.route.topic.replacement": "app.outbox.${routedByValue}",
    "key.converter": "org.apache.kafka.connect.storage.StringConverter",
    "value.converter": "org.apache.kafka.connect.json.JsonConverter",
    "value.converter.schemas.enable": "false"
  }
}

В результате события типа, например, order пойдут в топик app.outbox.order, а полезная нагрузка будет «распакована» из поля payload.

Kafka или Redpanda: что учесть

Обе системы совместимы по API. Redpanda проще в развёртывании и не требует ZooKeeper, что удобно для компактных установок и тестовых контуров. Kafka проверена в больших кластерах и богата экосистемой. Ключевые моменты для CDC:

  • Топики: для таблиц с большим числом ключей и интенсивными изменениями настройте достаточное число партиций.
  • cleanup.policy: для changelog‑потоков часто ставят compact (оставляет последние версии по ключу). Для событийного outbox — delete с нужной retention.ms.
  • acks и durability: выбирайте уровень подтверждения продюсера в зависимости от SLA и синхронности хранилища.

Поток по паттерну Outbox: приложение → PostgreSQL → Debezium → Kafka

Производительность и надёжность

На стороне PostgreSQL обратите внимание на параметры, влияющие на поток изменений:

  • logical_decoding_work_mem — объём памяти на пакет декодирования. Если видите частые spill’ы, увеличьте.
  • wal_compression — может помочь снизить I/O при активных UPDATE, но увеличит CPU.
  • full_page_writes — безопасность прежде всего; отключайте только осознанно и обычно не в проде.
  • Размер wal_keep_size как страховка от мгновенного удаления WAL при кратковременных лагах.

На стороне Debezium/Kafka Connect:

  • max.batch.size и max.queue.size — увеличивайте для throughput, следите за задержками.
  • poll.interval.ms — частота опроса БД; слишком малая — лишняя нагрузка, слишком большая — рост задержек.
  • Используйте мониторинг метрик Connect/коннектора и алерты на рост очереди, ошибки конвертации, переработки снапшота.

Семантика доставки: Debezium обеспечивает «по крайней мере один раз» на уровне коннектора. Для строгой дедупликации проектируйте идемпотентных консьюмеров и используйте ключи сообщений, позволяющие безопасно переигрывать поток. Для планирования WAL‑ретенции и аварийного восстановления пригодится подробный разбор PITR и архивирования WAL.

Мониторинг и алертинг

Главный риск — отставание слотов и рост диска под WAL. Наблюдайте pg_replication_slots и LSN‑лаг:

SELECT slot_name,
       active,
       plugin,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag
FROM pg_replication_slots
WHERE database = current_database();

Также полезно контролировать публикации и покрытие таблиц:

SELECT pubname, puballtables, pubinsert, pubupdate, pubdelete FROM pg_publication;
SELECT * FROM pg_publication_tables WHERE pubname = 'app_pub';

Повесьте алерты на:

  • Лаг слота по байтам и по времени (оценочно по скорости поступления WAL).
  • Свободное место в разделе с WAL и каталоге данных.
  • Ошибки конвертеров в Connect (например, несериализуемые типы, большие строки).

Безопасность

Подключение Debezium к PostgreSQL шифруйте и ограничивайте:

  • Включайте SCRAM‑аутентификацию и TLS для клиентских подключений.
  • Минимальные привилегии: доступ только к нужной БД/схемам/таблицам, роль REPLICATION, запрет на DDL.
  • Сетевые ACL/фаервол: брокеры и Connect не должны быть доступны из внешних сетей без необходимости.

Пример фрагмента конфигурации коннектора для TLS в БД (значения и пути условны):

{
  "config": {
    "database.sslmode": "verify-full",
    "database.sslrootcert": "/etc/ssl/ca.pem",
    "database.sslcert": "/etc/ssl/client.crt",
    "database.sslkey": "/etc/ssl/client.key"
  }
}

Если у вас внешний доступ к брокерам/Connect, для публичных эндпоинтов используйте проверенные SSL-сертификаты, чтобы избежать проблем с клиентами и ротацией самоподписанных цепочек.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Частые ошибки и как их избежать

  • Таблица без PK: UPDATE/DELETE неидемпотентны. Решение — добавить PK или REPLICA IDENTITY FULL (понимая рост нагрузки).
  • Отставание слота и переполнение диска: включить алерты, ограничить batch‑размеры, масштабировать консьюмеров, временно повысить wal_keep_size, при кризисе — остановить write‑нагрузку или временно остановить неважные коннекторы.
  • Снапшот «долго и больно»: используйте snapshot.fetch.size, исключайте лишние таблицы, запускайте в тихое окно. При больших БД — staged‑подход: сначала ключевые таблицы, затем остальные.
  • DDL‑шторм: при активной эволюции схемы используйте Outbox, отделяйте доменные события от структуры OLTP.
  • Сброс слота: не удаляйте слот без осознания последствий — потеряете непрочитанные изменения. Если нужно пересоздать — зафиксируйте LSN и пересоберите поток.

Схема и типы данных

Debezium транслирует типы PostgreSQL в типы Kafka Connect. Обратите внимание на numeric и временные типы: decimal.handling.mode и time.precision.mode влияют на сериализацию. Для геометрии и пользовательских типов предусмотрите сериализацию в строки/JSON. Если у вас жёсткие схемы downstream (Avro), заранее планируйте совместимость и миграции.

Redpanda на практике

Redpanda удобна для небольших команд: один бинарник, низкая латентность, совместимость с экосистемой Kafka. Проверьте настройки топиков под CDC: для changelog‑потоков — cleanup.policy=compact, для событий — delete и адекватная retention.ms. Следите за размером сегментов и компрессией. Для быстрой диагностики используйте утилиты управления кластерами и экспорт метрик, чтобы видеть задержки продюсера/консьюмера.

Порядок развертывания: проверенный чек‑лист

  1. Оцените сценарии: нужен ли outbox, требования к ретенции и ключам топиков.
  2. Подготовьте PostgreSQL: wal_level=logical, слоты/сендеры, права для роли CDC.
  3. Определите таблицы для публикации, проверьте PK и REPLICA IDENTITY.
  4. Разверните Kafka/Redpanda и Kafka Connect, спроектируйте топики и политику хранения.
  5. Создайте коннектор Debezium: pgoutput (или wal2json, если это ваш стандарт).
  6. Запустите snapshot.initial на тестовом контуре, измерьте лаги и пропускную способность.
  7. Включите мониторинг: лаг слотов, место на диске, метрики коннектора и брокеров.
  8. Протестируйте ошибки: рестарты коннектора, временно недоступное хранилище, повторы сообщений.
  9. Подготовьте план инцидентов: действия при росте лага, расширении партиций, смене схемы.

Кстати, если вы активно оптимизируете базу под поток изменений, пригодится и гайд по настройке Autovacuum и индексам.

Итоги

Связка PostgreSQL + Debezium + Kafka/Redpanda — зрелый способ внедрить CDC без боли и с хорошей масштабируемостью. Успех определяется дисциплиной: чёткой зоной ответственности таблиц, продуманной стратегией снапшота, мониторингом replication slots и вниманием к форматам данных. В большинстве новых проектов стоит начинать с pgoutput и Outbox‑паттерна, чтобы получить стабильный событийный поток и спокойно эволюционировать схему, не ломая потребителей.

Поделиться статьей

Вам будет интересно

cert-manager в Kubernetes: Issuer, ClusterIssuer и DNS-01 на практике OpenAI Статья написана AI (GPT 5)

cert-manager в Kubernetes: Issuer, ClusterIssuer и DNS-01 на практике

Подробный разбор автоматизации TLS в Kubernetes с cert-manager: когда выбирать Issuer или ClusterIssuer, как настроить ACME DNS-01 ...
Redis replication практикум: PSYNC2, diskless, failover и измеримый RPO OpenAI Статья написана AI (GPT 5)

Redis replication практикум: PSYNC2, diskless, failover и измеримый RPO

Разбираем практический план настройки и измерений: как работает PSYNC2 и репликационный backlog, чем полезна бездисковая репликаци ...
ModSecurity 3 + OWASP CRS в Nginx: установка, динамический модуль, настройка и борьба с false positives OpenAI Статья написана AI (GPT 5)

ModSecurity 3 + OWASP CRS в Nginx: установка, динамический модуль, настройка и борьба с false positives

Пошаговая интеграция ModSecurity 3 (libmodsecurity) и OWASP CRS с Nginx. Разберём установку как динамического модуля, безопасное в ...