ddadminandClaude Fable 5 103ac021c8 feat(generator): инкрементальные счётчики manifest без перечитки Kafka
- Зачем:
  - world_next_day перечитывал всю историю топиков Kafka ради
    накопительных счётчиков — время прогона росло с возрастом мира
    (issue #5, находка F9).
- Что:
  - счётчики засеваются при import из уже прочитанного артефакта и при
    backfill из потока; next-day продвигает их только событиями нового
    дня, полного чтения Kafka больше нет;
  - катящаяся контрольная сумма — сумма SHA-256 событий по модулю 2^256
    (инкремент равен полному пересчёту), старый формат артефакта
    принимается без изменений;
  - точные множества click_id/user_domain_id вынесены из manifest в
    цепочку контент-адресуемых фрагментов (<=10 000 ID, SHA-256-цепочка,
    отдельный топик counter_chunks) — потолок сообщения Kafka не грозит,
    предел 900 000 байт проверяется явно с понятной ошибкой;
  - порядок записи всюду: фрагменты -> manifest -> state; старое локальное
    состояние отклоняется с подсказкой перезапустить import;
  - документация manifest/state обновлена (ARCHITECTURE, OPERATIONS,
    runbook startup-history).
- Проверка:
  - make test (216+31) и make lint зелёные;
  - живая приёмка на чистом стенде: import 235 с; три прогона
    world_next_day — 716/718/716 с (плоское время, O(нового дня));
    мир 3->6 дней, 561 942 события; make generated-history-chain-check —
    все порции и стыки однородны;
  - тест равенства инкремента и полного пересчёта:
    test_incremental_counters_equal_full_recompute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 23:47:02 +03:00

Учебный стенд DWH кликстрима

Stack Layers

Живой стек для работы с кликстримом: Kafka, ClickHouse, Airflow, Superset и мониторинг (Prometheus с Grafana) поднимаются в Docker одной командой. На этом стенде можно учиться по курсу или просто поднять его у себя и поэкспериментировать с потоковой загрузкой и витринами.

Поток данных коротко:

  • стартовая история: world_init → Kafka → ClickHouse (STG) → batch STG → ODS → DDS → DM → Superset.
  • живое продолжение: generator live → Kafka → ClickHouse (STG) → batch ETL → Superset.

Файлы data/*.jsonl больше не основной источник аналитики. Пока они остаются архивной кладовкой значений для генератора: браузеры, страны, устройства и UTM.

Куда дальше

Быстрый старт

Перед первой командой нужны Docker с docker compose, make, bash, curl, git и uv. uv нужен для локальных Python-проверок и команд разработки.

Для ручной работы поднимите стенд:

make up
docker compose ps

Дальше всё делается в Airflow: http://localhost:8080 (admin/admin). Список DAG'ов читается лесенкой сверху вниз; на свежем стенде все DAG'и создаются на паузе, поэтому перед запуском снимайте паузу переключателем слева от имени.

  1. ddl_init — снимите паузу и запустите: DAG создаст схему ClickHouse (отдельная команда в терминале не нужна).
  2. etl_pipeline — только снимите паузу: его запустит следующий шаг.
  3. world_init — снимите паузу и запустите с пустой формой: DAG импортирует эталонный мир, запустит ETL и сверит витрины.
  4. world_next_day — когда захотите добавить ровно один модельный день, запустите его с пустой формой. Расписание задано каждые 30 минут, но по умолчанию DAG стоит на паузе.

make up не запускает live-генератор; live включается отдельно командой make generator-continue.

После обновления репозитория снова выполните make up: команда пересобирает Airflow-образ и подтягивает новые зависимости и DAG-и. Superset-дэшборд собирается позже, когда DM уже готов: через make generated-history-analytics или make superset-init.

Для полностью автоматического чистого прогона из консоли есть команда — это тот же путь, что выше через Airflow UI, но одной командой и без ручных шагов (схему ClickHouse она применяет сама):

make generated-history-analytics

По умолчанию используется учебный профиль daily-wave: 3 суток с суточной волной. В live-продолжении он идёт с ×60: модельные сутки проходят примерно за 24 настенные минуты. Плоский профиль ci на 6 часов остаётся служебным для автоматических тестов.

Разовую длительность можно задать без ручного расчёта правой границы:

GEN_HISTORY_DURATION=2d make generated-history-analytics

Повторить техническую проверку после такого прогона только стартовой истории:

CHECK_LIVE_SEAM=0 make generated-history-check

Стык backfill/live проверяйте отдельным коротким сценарием:

make generated-history-runtime-check

Перед коммитом используйте быстрые проверки:

make test
make lint

Они не чистят volumes и не запускают долгие стендовые сценарии. Полная проверка стыка backfill/live остаётся отдельной командой make generated-history-runtime-check.

Сохранить стартовую историю в файл и восстановить её без новой генерации можно по runbook стартовой истории.

Проверить, что данные дошли до витрин:

docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
  --query "SELECT count() FROM dm.v_events_enriched"

Подробный сценарий запуска, параметры DAG-ов и разбор частых проблем — в OPERATIONS.

Сервисы и доступы

Сервис Адрес Назначение Логин/пароль
Airflow http://localhost:8080 оркестрация ETL admin/admin
ClickHouse http://localhost:9123/play SQL-запросы default/123456
Kafka UI http://localhost:8082 просмотр топиков
Superset http://localhost:8088 дашборды admin/admin
Prometheus http://localhost:9090 метрики
Grafana http://localhost:3000 графики метрик admin/admin

Готовый дашборд в Superset: http://localhost:8088/superset/dashboard/ecommerce-analytics/ — он создаётся во время make generated-history-analytics. Состав и настройка дашборда описаны в SUPERSET_DASHBOARD.

Как устроен поток данных

flowchart LR
    subgraph GEN["Generator"]
        BF["backfill"]
        LIVE["live"]
    end

    subgraph Kafka["Kafka"]
        Topics[4 топика]
    end

    subgraph CH["ClickHouse"]
        STG["STG: сырые данные"]
        ODS["ODS: типизация + DQ"]
        DDS["DDS: сущности"]
        DM["DM: витрины VIEW"]
    end

    BF -->|стартовая история| Kafka
    LIVE -->|продолжение| Kafka
    Kafka -->|Kafka MV| STG
    STG -->|batch| ODS -->|batch| DDS -->|VIEW| DM

    DDL["DDL"] -.-> CH

«Грязные» записи не роняют пайплайн: ошибки разбора складываются в ods.*_errors и в поле parse_errors, а обработка продолжается.

Подробное описание слоёв STG/ODS/DDS/DM, диаграммы и обоснование решений — в ARCHITECTURE.

Документация

S
Description
No description provided
Readme
34 MiB
Languages
Python 85.3%
Shell 13.1%
Makefile 1.5%
Dockerfile 0.1%