- Удалён класс InMemoryBatchHistory и вся fallback-логика - Упрощён KafkaBatchHistory: убраны _initialized, get_stats(), обработка ошибок - Обновлена документация (generator/README.md, docs/OPERATIONS.md) - Упрощены тесты, удалены тесты для удалённого функционала - Код стал честнее: без Kafka генератор падает при старте Ревьюер: Prometheus даёт достаточно visibility, fallback избыточен
17 KiB
Operations Runbook
Операционный runbook для локального запуска и проверки пайплайна.
Локальный запуск
Базовые команды:
make up(илиdocker compose up -d)make down(остановить и удалить контейнеры/сети проекта)make clean(полная очистка:down -v --remove-orphans)make ddl(применяет SQL изsql/ddl/00_databases.sqlиsql/ddl/*/*.sqlв ClickHouse)make data(пересоздаёт топики и заливает данные в Kafka; по умолчанию полный объём, срез —LIMIT=50 make data)make transform(запускает batch-процесс ODS -> DDS -> DM)make superset-init(повторная инициализация Superset: подключение к ClickHouse, датасеты, дашборд)docker compose psdocker compose logs -f --tail=200 <service>docker compose down(сохраняет named volumes, включаяclickhouse-data)docker compose down -v(удаляет named volumes, использовать осознанно)
Порты
Порты задаются в docker-compose.yml:
- ClickHouse native:
localhost:8002(пользовательdefault, пароль123456) - ClickHouse HTTP / play-консоль:
http://localhost:9123/play(default/123456) - Kafka:
localhost:9092 - Kafka UI:
http://localhost:8082 - Airflow:
http://localhost:8080(admin/admin) - Superset:
http://localhost:8088(admin/admin) - Prometheus:
http://localhost:9090 - Grafana:
http://localhost:3000(admin/admin)
Airflow DAGs
ddl_init
- Запуск: ручной (
Trigger DAG) - Параметр:
verify_only(bool, defaultfalse) - Назначение: создаёт БД и таблицы в ClickHouse от
00_databasesдо40_dm
kafka_load
- Запуск: ручной (
Trigger DAG with config) - Параметры:
limit(int, default0) — количество строк (0= все)reset_topics(bool, defaulttrue) — пересоздать топики
- Примеры:
{}
{"limit": 100}
etl_pipeline
- Запуск: ручной (
Trigger DAG with config) - Параметры:
full_refresh(bool, defaulttrue) — очистить DDS перед загрузкойwait_stg_timeout_sec(int, default600, minimum30) — сколько секунд задачаwait_for_stg_dataждёт появления данных в STG, прежде чем упасть по таймауту
- Зависимость: требует наличия данных в STG (от
kafka_loadилиmake data) - Гейт целостности DDS:
check_dds_integrityсчитает события без клика, аassert_dds_integrityроняет DAG приorphan_events > 0. Проверка идёт послеload_ddsи доload_dm_summary, чтобы DM не собирался поверх нарушенной связиdds.event -> dds.click. Дляassert_dds_integrityзаданоretries=0: повтор не чинит уже собранную сироту и только задерживает явный failed-статус.
Генератор событий (автономный стриминг)
Автономный сервис для непрерывной генерации событий в Kafka. Работает независимо от Airflow DAGs.
Управление
# Запустить генератор
make generator-up
# Остановить генератор
make generator-down
# Перезапуск с пересборкой
make generator-restart
# Логи
make generator-logs
Конфигурация (env)
| Переменная | Описание | По умолчанию |
|---|---|---|
GEN_TICK_SECONDS |
Интервал между тиками | 5 |
GEN_LAMBDA_BASE_PER_MIN |
Базовая интенсивность (событий/мин) | 200 |
GEN_JITTER_PCT |
Процент вариативности | 20 |
GEN_MIN_EVENTS_PER_TICK |
Минимум событий за тик | 5 |
GEN_MAX_EVENTS_PER_TICK |
Максимум событий за тик | 50 |
Топик истории
Генератор пишет историю батчей в топик generator_batch_history (JSON, ключ batch_id).
Важно: генератор требует работающей Kafka. Без Kafka генератор упадёт при старте или потеряет события.
# Чтение истории из Kafka
docker compose exec kafka /opt/kafka/bin/kafka-console-consumer.sh \
--bootstrap-server kafka:29092 \
--topic generator_batch_history \
--from-beginning
Метрики
Prometheus метрики доступны на http://localhost:9109/metrics:
generator_events_total— счётчик отправленных событийgenerator_publish_errors_total— ошибки публикацииgenerator_tick_duration_seconds— длительность тика
Рекомендуемый сценарий (фаза 2)
# 1. Запуск инфраструктуры
make up
# 2. Инициализация схемы (один раз)
# Airflow UI -> DAGs -> ddl_init -> Trigger DAG
# 3. Загрузка данных через Airflow
# Airflow UI -> DAGs -> kafka_load -> Trigger DAG with config
# Параметры по умолчанию: limit=0, reset_topics=true
# 4. Запуск ETL
# Airflow UI -> DAGs -> etl_pipeline -> Trigger DAG with config
# {"full_refresh": true}
# 5. Проверка результатов
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT count() FROM ods.browser_event"
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT count() FROM dds.event"
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "SELECT * FROM dm.dq_summary"
Быстрые проверки
- Kafka ingest: наличие данных в
stg.*и типизированных строк вods.*. - Airflow UI:
http://localhost:8080показывает DAGddl_init,kafka_load,etl_pipeline. - BI: витрина
dm.v_events_enrichedотвечает за разумное время при фильтре по дате.
Мониторинг
TL;DR после git pull
# Быстрый вариант (make)
make reload-monitoring
# Если мониторинг "залип" (No data/out of bounds) — жесткое восстановление:
make recover-monitoring
# Или вручную:
docker compose up -d prometheus grafana kafka-exporter statsd-exporter
docker compose restart prometheus statsd-exporter
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/datasources/reload
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/dashboards/reload
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/alerting/reload
Если менялся configs/prometheus_ch.xml: docker compose restart clickhouse.
Prometheus + Grafana для ClickHouse, Kafka и Airflow
Стек мониторинга поднимается вместе с остальной инфраструктурой:
# Проверить статус сервисов мониторинга
docker compose ps prometheus grafana
# Проверить скрейп ClickHouse в Prometheus
curl -s http://localhost:9090/api/v1/targets | grep -o '"health":"[^"]*"'
Конфигурация
- ClickHouse: встроенный Prometheus endpoint (
/metricsна порту9126) - Kafka: через
kafka-exporter(порт9308) - Airflow: через
statsd-exporter(StatsD → Prometheus, порт9102)- Airflow отправляет метрики в StatsD-формате на
statsd-exporter:8125 - Mapping конфигурация:
configs/statsd_mapping.yml
- Airflow отправляет метрики в StatsD-формате на
- Grafana provisioning (
configs/grafana/provisioning/):- Дашборды: ClickHouse Overview, Kafka Overview, Airflow Overview
- Алерты: ClickHouse, Kafka, Airflow
После git pull: быстрый апдейт мониторинга
Если прилетели изменения в configs/grafana/provisioning/* или configs/prometheus.yml, примените их так:
# Рекомендуемый способ (через make)
make reload-monitoring
# Если метрики пропали/залипли:
make recover-monitoring
# Или вручную:
docker compose rm -sf prometheus statsd-exporter
docker compose up -d prometheus grafana kafka-exporter statsd-exporter
docker compose restart airflow-scheduler airflow-webserver
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/datasources/reload
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/dashboards/reload
curl -s -u admin:admin -X POST http://localhost:3000/api/admin/provisioning/alerting/reload
Проверка результата:
# Дашборды и алерты
curl -s -u admin:admin http://localhost:3000/api/v1/provisioning/alert-rules | grep -o '"title":"[^"]*"'
# Kafka метрики
curl -s http://localhost:9090/api/v1/targets | grep kafka
curl -s http://localhost:9308/metrics | grep "^kafka_brokers"
Если в пулле изменился configs/prometheus_ch.xml, дополнительно перезапустите ClickHouse:
docker compose restart clickhouse
Если дашборд Kafka не загрузился (ошибка "Dashboard title cannot be empty" в логах), пересоздайте контейнер Grafana:
docker compose stop grafana && docker compose rm -f grafana && docker compose up -d grafana
Дашборд ClickHouse Overview
URL: http://localhost:3000/d/clickhouse-overview/clickhouse-overview
| Раздел | Метрики |
|---|---|
| System Health | CPU Usage, Memory Resident, Memory Code |
| Query Performance | Queries per Second, Active Queries, Failed Queries (total), Total Queries, Inserted Rows/sec |
| MergeTree Storage | Total Parts, Parts by State, Total Merges, Merges per Second |
Принятое решение по метрикам: сверили naming через Context7 (/clickhouse/clickhouse-docs, раздел Prometheus interface) и заменили недоступные в 25.1 серии на фактически экспортируемые (ClickHouseProfileEvents_InsertedRows, ClickHouseAsyncMetrics_TotalPartsOfMergeTreeTables, ClickHouseMetrics_Parts*).
Дашборд Kafka Overview
URL: http://localhost:3000/d/kafka-overview/kafka-overview
| Раздел | Метрики |
|---|---|
| Cluster Health | Brokers Up, Topics, Total Partitions, Consumer Groups |
| Throughput | Messages In / sec by Topic |
| Consumers | Consumer Lag by Group |
| Partitions | Partition Offsets (Current) |
Источник метрик: kafka-exporter (danielqsj/kafka-exporter), формат конфигурации подтверждён через Context7 (/danielqsj/kafka_exporter, /prometheus/docs).
Проверка метрик
# Prometheus собирает метрики ClickHouse
curl -s "http://localhost:9090/api/v1/query?query=ClickHouseAsyncMetrics_MemoryResident"
curl -s "http://localhost:9090/api/v1/query?query=ClickHouseProfileEvents_Query"
# Prometheus собирает метрики Kafka
curl -s "http://localhost:9090/api/v1/query?query=kafka_brokers"
curl -s "http://localhost:9090/api/v1/query?query=kafka_consumergroup_lag"
# Прямая проверка kafka-exporter
curl -s http://localhost:9308/metrics | grep "^kafka_"
# Проверить, что Prometheus собирает метрики
curl -s "http://localhost:9090/api/v1/query?query=ClickHouseAsyncMetrics_MemoryResident"
# Проверить счётчик запросов
curl -s "http://localhost:9090/api/v1/query?query=ClickHouseProfileEvents_Query"
Алерты Grafana
ClickHouse Alerts — provisioning-файл: configs/grafana/provisioning/alerting/clickhouse-alert-rules.yml
Настроены правила:
ClickHouse Failed Queries Rate—rate(ClickHouseProfileEvents_FailedQuery[5m]) > 0в течение2mClickHouse Memory Resident High—MemoryResident / OSMemoryTotal * 100 > 85в течение5mClickHouse Parts Active High—ClickHouseMetrics_PartsActive > 500в течение10m
Kafka Alerts — provisioning-файл: configs/grafana/provisioning/alerting/kafka-alert-rules.yml
Настроены правила:
Kafka Broker Down—kafka_brokers < 1в течение1mKafka Consumer Lag High—kafka_consumergroup_lag > 10000в течение5mKafka No Messages Produced—rate(kafka_topic_partition_current_offset[5m]) < 0.1в течение10mKafka Consumer Group Missingне включён: для демо-стенда даёт шум на стартовых прогонах и не повышает диагностику по сравнению с lag/throughput.
Проверка и reload без рестарта контейнера:
# Список правил unified alerting
curl -s -u admin:admin http://localhost:3000/api/v1/provisioning/alert-rules
# Принудительно перечитать provisioning alerting
curl -s -X POST -u admin:admin http://localhost:3000/api/admin/provisioning/alerting/reload
Troubleshooting мониторинга
Общие проблемы:
- "No data" в Grafana: проверить, что Prometheus видит target (
Status -> Targetsв UI) - Dashboard не загрузился: проверить логи Grafana — provisioning работает при первом старте контейнера
- Prometheus spam
out of boundsи дашборды пустые: выполнитьmake recover-monitoring
ClickHouse:
- Метрики не обновляются: ClickHouse экспортирует метрики на
0.0.0.0:9126внутри сети Docker
Kafka:
connection refusedк Kafka: проверить, что kafka-exporter используетkafka:29092(внутренняя сеть), неlocalhost:9092- Метрики Kafka не появляются: проверить, что kafka-exporter подключился к Kafka —
docker compose logs kafka-exporter - Нет консьюмер-групп: kafka-exporter показывает lag только при наличии активных консьюмеров с закоммиченными offset
Troubleshooting
etl_pipelineпадает с ошибкой схемы: сначала запуститьddl_init.git pullпадает сPermission deniedнаdata/*илиconfigs/grafana/provisioning/*:- Причина: локально есть файлы/каталоги не вашего пользователя (часто после запуска контейнеров с root-пользователем).
- Диагностика:
ls -ld data configs/grafana/provisioning ls -l data | head -n 20 - Быстрое восстановление:
# Владелец и права для рабочей копии репозитория sudo chown -R "$USER:$USER" . find . -type d -exec chmod u+rwx {} \; find . -type f -exec chmod u+rw {} \; - После восстановления повторить
git pull --ff-only. - Не запускать
gitчерезsudo.
grafanaперезапускается с ошибкойattempt to write a readonly database:- Причина: старый
grafana_libсодержитgrafana.db, созданный root-пользователем. - Простой recovery (сбросить только volume Grafana):
docker compose stop grafana docker volume ls | grep grafana_lib docker volume rm <project>_grafana_lib docker compose up -d grafana
- Причина: старый
- В Superset ошибки
DB engine ErrorиCannot load filter, а в логах естьCan't load plugin: sqlalchemy.dialects:clickhouse.connect:- Причина: некорректный URI диалекта ClickHouse (
clickhouse+connect://...). - Используйте URI
clickhousedb://...и пересоберите сервисы Superset:docker compose build superset superset-init docker compose up -d clickhouse docker compose up -d --force-recreate superset-init superset
- Причина: некорректный URI диалекта ClickHouse (
- После
docker compose down -vнужно повторно прогнать:ddl_init->kafka_load->etl_pipeline. - После
make clean/down -vSuperset стартует, но витриныdm.*ещё пустые или отсутствуют до прогона ETL; послеddl_init->kafka_load->etl_pipelineвыполнитьmake superset-init. - Для демо по умолчанию использовать малый срез данных; полный прогон делать осознанно.