Skip to content
PПромтбук
RUEN
07Пайплайны

Стратегия бекфилла: chunking, throttling, rollback

Когда нужен бекфилл, требования к идемпотентности, чанкование по дням/часам, не положить прод БД, мониторинг прогресса.

Действуй как инженер, который проводил много бекфиллов. Спланируй бекфилл: {{scenario}}. Объём: {{data_volume}}.

Когда нужен бекфилл

| Триггер | Почему | | Исправлен баг в трансформации | Историчные mart'ы содержат битые цифры — пересчитать | | Добавили новую колонку из источника | Нужны исторические значения, не только новые | | Изменилась бизнес-логика | "Теперь refunds учитываем по-другому", аналитика просит ретро | | Восстановление после инцидента | Период с пропусками или дублями | | Новый mart/модель | Историчные данные нужны для тренда |

Перед бекфиллом — спроси: "А зачем? Может, новая логика только с момента релиза?" Часто это самый дешёвый ответ.

Idempotency — это нулевое требование

Бекфилл, который не идемпотентен, нельзя запустить. Точка. Проверь:

  • MERGE/INSERT OVERWRITE PARTITION вместо INSERT
  • Уникальный ключ на каждой строке (composite ok)
  • Partition by date — переналив одного дня атомарен и не трогает остальные
  • Если используешь external API — храни response, чтобы при повторе не платить за тот же запрос

Тест: запусти один день бекфилла дважды. Результат должен быть бит в бит одинаков.

Chunking — обязательно

Никогда не "одним SQL за полгода". Чанкуй:

| Гранулярность | Когда | | По дню | Дефолт для большинства pipeline'ов | | По часу | Высокообъёмные события (>100M/день), хочется параллелизма | | По tenant/customer | Multi-tenant, изоляция сбоев | | По диапазону id | Реляционные таблицы без даты |

# Пример: ежедневная итерация
for date in $(generate_dates 2025-11-01 2026-05-01); do
  dbt run --select fct_orders --vars "{run_date: $date}"
  sleep 30  # throttling
done

Throttling — чтобы не положить прод

Бекфилл = N × обычная нагрузка. Без throttling:

  • Source DB: replicas лагают, OLTP запросы тормозят, пользователи замечают
  • Warehouse: compute упирается, дорогие интерактивные запросы аналитиков встают
  • API: rate limit, бан

Правила:

  • Между chunk'ами: sleep N секунд (начинай с 30, тюнингуй по метрикам)
  • Параллелизм: максимум 2-3 chunk'а одновременно
  • Окно: только off-peak (для прод DB — ночь по основной таймзоне)
  • Circuit breaker: если replica lag > порога — останови и подожди
  • Resource budget: отдельный warehouse/cluster для бекфилла, чтобы не конкурировать с прод-pipeline'ами
# Псевдо
for chunk in chunks:
    if replica_lag_seconds() > 60:
        sleep(300)  # ждём, пока догонит
        continue
    process(chunk)
    sleep(30)

Monitoring прогресса

Без него бекфилл превращается в "запустил и забыл" → утром обнаружишь, что упало 8 часов назад.

Дашборд должен показывать:

  • Прогресс: processed_chunks / total_chunks
  • ETA: chunks_left × avg_chunk_duration
  • Throughput: rows/min, чтобы видеть деградацию
  • Replica lag, warehouse load — пороги для throttling
  • Алерт на 2 подряд failed chunk'а

Храни состояние в backfill_state(scenario, chunk_key, status, started_at, finished_at, rows_processed, error). Тогда перезапуск понимает, что уже сделано, а что нет.

Rollback при ошибке

План rollback'а ОБЯЗАТЕЛЕН, продумай ДО запуска:

| Стратегия | Когда | | Partition swap | Бекфиллишь в shadow-партицию, при ошибке остаётся старая. Идеал для warehouse'а | | Versioned tables | Пишешь в fct_orders_v2, перенаправляешь BI после валидации | | Soft delete | Все строки с пометкой backfill_run_id; при ошибке — DELETE WHERE backfill_run_id = X | | Point-in-time restore | Снапшот warehouse до бекфилла; самый дорогой, для крайних случаев |

После бекфилла — reconciliation: сравни ключевые метрики (sum(revenue), count(distinct user) по дням) до/после. Расхождение > 5% по необъяснимым причинам = откат.

Вывод

## Scope
Период: ... → ...
Таблицы: ...
Объём: ~X rows

## Idempotency
- unique_key: ...
- merge column: ...
- partition: ...

## Chunking
- Гранулярность: day / hour / tenant
- Total chunks: N
- Concurrency: K

## Throttling
- Sleep между chunk'ами: ...
- Pause condition: replica_lag > ...

## State tracking
backfill_state(...)

## Rollback plan
Стратегия: ...
Команда отката: ...

## Reconciliation
| Метрика | Pre | Post | Diff % | Acceptable? |

## Run book
1. Заморозить downstream consumers
2. Backup / snapshot
3. Запустить с --dry-run на 1 chunk
4. Полный прогон
5. Reconciliation
6. Разморозить consumers

Anti-patterns

  • ❌ Одна команда UPDATE за полгода — WAL bloats, replica лагает, может убить прод
  • ❌ Запуск без backfill_state — после рестарта не знаешь, что уже сделано
  • ❌ Параллелизм без throttling по lag — replica отстаёт, app начинает читать stale data
  • ❌ Никакой reconciliation — спустя месяц аналитик найдёт расхождение и придётся бекфиллить заново
  • ❌ Бекфилл в тот же warehouse, что и прод-pipeline'ы, без resource isolation — встанет всё разом
К подразделу «Пайплайны»
Похожие промты