Skip to content
Learning Platform
Intermediate
25 minutes
snapshot-strategies incremental-snapshot chunk-tuning

Prerequisites:

  • module-2/05-aurora-failover-handling

Стратегии снэпшотов в Debezium

При первом запуске CDC-коннектора возникает фундаментальный вопрос: как получить текущее состояние таблицы? Debezium должен знать, что уже есть в базе данных, прежде чем начать отслеживать изменения. Этот процесс называется снэпшотом (snapshot).

Зачем нужен снэпшот?

CDC захватывает только изменения — INSERT, UPDATE, DELETE. Но что насчет миллиона записей, которые уже существуют в таблице? Без снэпшота consumer увидит только новые изменения, а существующие данные останутся невидимыми.

Без snapshot: Потеря существующих данных
Существующие данные
ПОТЕРЯНЫ
Новые изменения
Kafka
Consumer видит только новые изменения, не зная о миллионах существующих записей

Режимы snapshot в Debezium

Debezium предлагает несколько режимов снэпшота, каждый для своего сценария:

РежимПоведениеТипичный сценарий
initialСнэпшот при первом запуске, затем только streamingСтандартный — новое развертывание
initial_onlyТолько снэпшот, без streamingОдноразовая миграция данных
neverНикогда не делать снэпшотКоннектор пересоздается с сохраненным offset
when_neededСнэпшот если offset потерянОтказоустойчивая конфигурация
alwaysСнэпшот при каждом запускеАНТИ-ПАТТЕРН в production!

Конфигурация режима

{
  "name": "inventory-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "postgres",
    "database.port": "5432",
    "database.user": "postgres",
    "database.password": "postgres",
    "database.dbname": "inventory",
    "topic.prefix": "inventory",
    "table.include.list": "public.orders",
    "snapshot.mode": "initial",
    "plugin.name": "pgoutput"
  }
}

Проблемы традиционного снэпшота

Традиционный снэпшот (initial, always) имеет серьезные ограничения для больших таблиц:

1. Блокировка streaming

Во время снэпшота коннектор не обрабатывает новые изменения из WAL. Все CDC-события накапливаются в replication slot, увеличивая WAL retention.

Connector
PostgreSQL
Kafka
SELECT * FROM large_table10M rows...op="r" eventsRead WALAccumulated changesop="c/u/d" events
Период блокировки streaming
ПРОБЛЕМА:Streaming заблокирован на время snapshot.
Для таблицы 100GB это могут быть часы. WAL retention растет, replication slot lag увеличивается.
При crash во время snapshot — приходится начинать сначала.

2. Нет возобновляемости

Если коннектор падает во время снэпшота большой таблицы, приходится начинать сначала. Для таблицы в 100GB это может означать часы потерянной работы.

3. Блокировки таблиц

В зависимости от режима изоляции, снэпшот может требовать блокировок, влияющих на production workload.

Проверка знаний
Почему традиционный snapshot проблематичен для 100 ГБ таблицы в production?
Ответ
Традиционный snapshot блокирует streaming CDC на всё время выполнения. Для 100 ГБ это могут быть часы, в течение которых новые изменения накапливаются в слоте репликации. Если snapshot прерывается, придётся начинать сначала. Incremental snapshot решает обе проблемы — работает параллельно со streaming и возобновляем.

Incremental Snapshots (Debezium 1.6+)

Incremental snapshots — современный подход, решающий все вышеперечисленные проблемы:

ХарактеристикаTraditionalIncremental
Streaming во время снэпшотаЗаблокированПродолжается параллельно
ВозобновляемостьНетДа, с позиции последнего chunk
Блокировки таблицВозможныМинимальные
УправлениеАвтоматически при стартеПо запросу через signaling table
Signal Table
Connector
PostgreSQL
Kafka
execute-snapshotSELECT WHERE id 1-512op="r" chunk 1WAL changesop="c/u/d"SELECT WHERE id 513-1024op="r" chunk N
Параллельная обработка
ПРЕИМУЩЕСТВО:Snapshot и streaming работают параллельно.
Минимальный downtime, возобновляемость при crash, collision detection.
Consumer различает события по полю source.snapshot

Как работает incremental snapshot

  1. Chunk-based чтение: Вместо SELECT всей таблицы, коннектор читает порциями (chunks) по primary key
  2. Watermark tracking: Каждый chunk имеет watermark позицию, позволяющую возобновить с места остановки
  3. Collision detection: Если запись изменилась во время снэпшота, приоритет отдается streaming событию

Формат событий

Incremental snapshot события имеют op: 'r' (read) и метаданные в source:

{
  "payload": {
    "op": "r",
    "source": {
      "snapshot": "true",
      "db": "inventory",
      "table": "orders"
    },
    "after": {
      "id": 1,
      "customer_id": 100,
      "total": 150.00
    }
  }
}

Streaming события отличаются отсутствием snapshot: true:

{
  "payload": {
    "op": "c",
    "source": {
      "snapshot": "false",
      "db": "inventory",
      "table": "orders"
    },
    "after": {
      "id": 1001,
      "customer_id": 200,
      "total": 75.50
    }
  }
}

Выбор стратегии: Decision Framework

Нужен snapshot?
Нет
snapshot.mode=never
Да
Размер таблицы?
< 1M строк
Downtime OK?
Да
initial
Нет
incremental
>= 1M строк
Incremental Snapshot
Рекомендации
snapshot.mode=initial
Новое развертывание, таблицы < 1M строк
snapshot.mode=never + incremental
Большие таблицы, zero downtime требование
Анти-паттерны
snapshot.mode=always
Полный snapshot при каждом рестарте — только для dev
initial для > 10M строк
Часы блокировки streaming, WAL backlog

Рекомендации по сценариям

Новое развертывание, маленькие таблицы (< 1M строк):

"snapshot.mode": "initial"

Простой вариант. Снэпшот пройдет за минуты.

Новое развертывание, большие таблицы (> 1M строк):

"snapshot.mode": "never",
"signal.data.collection": "public.debezium_signal"

Используйте incremental snapshot через signaling table.

Пересоздание коннектора (offset сохранен):

"snapshot.mode": "never"

Коннектор продолжит с сохраненной позиции.

Восстановление после сбоя:

"snapshot.mode": "when_needed"

Автоматический снэпшот только если offset потерян.

Настройка chunk size

Размер chunk критически влияет на производительность incremental snapshot:

Формула расчета

chunk_size = (target_chunk_memory_mb * 1024) / average_row_size_kb

Пример: Целевая память 50MB, средний размер строки 5KB:

chunk_size = (50 * 1024) / 5 = 10240 строк

Рекомендации по типам таблиц

Тип таблицыРазмер строкиchunk_size
Wide JSONB (много JSON колонок)50-100KB500-1000
Standard OLTP (обычная структура)2-10KB2048-4096
Narrow logs (узкие записи)0.5-2KB8192-16384

Конфигурация

{
  "name": "orders-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "snapshot.mode": "never",
    "incremental.snapshot.chunk.size": "2048",
    "signal.data.collection": "public.debezium_signal",
    "signal.enabled.channels": "source"
  }
}

Измерение размера строки

-- Средний размер строки в таблице
SELECT
    pg_size_pretty(pg_total_relation_size('public.orders') / COUNT(*)) AS avg_row_size
FROM public.orders;

-- Более точный расчет по pg_stats
SELECT
    SUM(avg_width) AS estimated_row_bytes
FROM pg_stats
WHERE tablename = 'orders' AND schemaname = 'public';

Критические предупреждения

АНТИ-ПАТТЕРН: snapshot.mode=always

// НЕ ДЕЛАЙТЕ ТАК В PRODUCTION!
{
  "snapshot.mode": "always"
}

Проблемы:

  • При каждом рестарте коннектора полный снэпшот
  • Блокировка streaming на время снэпшота
  • Дублирование всех данных в Kafka
  • Взрывной рост WAL retention

Когда допустимо: Только для разработки и тестирования.

Проверка знаний
Почему snapshot.mode=always — анти-паттерн в production?
Ответ
Каждый рестарт коннектора вызывает полный snapshot, повторно отправляя все данные в Kafka. Это создаёт дублирование событий, блокирует streaming на время snapshot и вызывает рост WAL retention. В production используйте initial (первый запуск) или never с incremental snapshot.

Schema changes во время incremental snapshot

Debezium не поддерживает изменения схемы во время incremental snapshot:

-- Это вызовет ошибку во время snapshot!
ALTER TABLE orders ADD COLUMN new_field TEXT;

Решение: Координируйте maintenance windows:

  1. Остановите snapshot через signaling table
  2. Примените schema changes
  3. Перезапустите snapshot

Что мы узнали

  1. Снэпшот необходим для захвата существующих данных при первом запуске
  2. Traditional snapshot блокирует streaming и не возобновляем
  3. Incremental snapshots работают параллельно со streaming и возобновляемы
  4. Режим выбирается по размеру таблицы и требованиям к downtime
  5. Chunk size рассчитывается по формуле на основе размера строки
  6. snapshot.mode=always — анти-паттерн для production

Что дальше?

В следующем уроке мы выполним практическую работу: создадим signaling table, запустим incremental snapshot для большой таблицы и напишем Python consumer для мониторинга процесса снэпшота.

Check Your Understanding

Score: 0 of 0
Conceptual
Question 1 of 6. Зачем при первом запуске нового Debezium-коннектора необходим initial snapshot?

Finished the lesson?

Mark it as complete to track your progress