# Учебная дата-платформа кликстрима Стенд для работы с кликстримом: Kafka, кластер ClickHouse (2 шарда и clickhouse-keeper), Airflow, Superset. Преемник учебного стенда [clickstream-ch-kafka-superset-demo](https://git.dementev.space/ddmitry/clickstream-ch-kafka-superset-demo). ## Статус Репозиторий строится по спеке [«Боевой реализм стенда (v2)»](docs/specs/2026-07-30-stand-v2-realism.md). Сейчас готов первый элемент каркаса: кластер ClickHouse из двух шардов и отдельного clickhouse-keeper. ## Быстрый старт Нужны Docker с Compose и свободные порты `28123`, `28124`, `29000`, `29001`. Настройки портов и образа лежат в `.env` и не попадают в git: ```bash cp .env.example .env make up make smoke ``` `make up` поднимает единственный режим стенда: два шарда ClickHouse по одной реплике и отдельный keeper. Команда ждёт здорового состояния всех трёх контейнеров. Нода `clickhouse-01` служит инициатором DDL и позже будет точкой подключения Airflow. К `clickhouse-02` позже подключится Superset. `make smoke` одной командой проверяет описание кластера, макросы нод, связь с keeper, создание `ReplicatedMergeTree` и `Distributed` через `ON CLUSTER`, путь в keeper из макроса, вставку через первую ноду и чтение со второй, очередь распределённых DDL и удаление временных таблиц. Скрипт печатает каждый шаг и зелёный результат по-русски. `make smoke-guards` проверяет саму smoke-команду: аварийную очистку, обработку прерывания, подсказку о незапущенном стенде и окружение keeper. Остановить контейнеры можно командой `make down`. Для холодного старта с удалением данных используйте `make clean`. HTTP-интерфейсы доступны только с локальной машины: - нода 1 — `http://127.0.0.1:28123`; - нода 2 — `http://127.0.0.1:28124`. У локального учебного кластера нет пароля: ноды используют общего пользователя `default` для запросов `Distributed`. Порты поэтому привязаны к `127.0.0.1` и не открыты во внешнюю сеть. В бою перед репликами ClickHouse обычно был бы балансировщик. Здесь в каждом шарде одна реплика, поэтому балансировать нечего. Балансировщик и топология 2×2 намеренно не входят в стенд. Конфигурация сверена 30 июля 2026 года с официальной документацией ClickHouse: [настройками сервера](https://clickhouse.com/docs/operations/server-configuration-parameters/settings), [Keeper](https://clickhouse.com/docs/guides/oss/deployment-and-scaling/keeper/), [ReplicatedMergeTree](https://clickhouse.com/docs/engines/table-engines/mergetree-family/replication), [ON CLUSTER](https://clickhouse.com/docs/sql-reference/distributed-ddl) и [Distributed](https://clickhouse.com/docs/engines/table-engines/special/distributed). Описание кластера задаётся через `remote_servers`, макросы — через `macros`, подключение к keeper — через `zookeeper`; путь `ReplicatedMergeTree` содержит `{shard}` и `{replica}`, а `Distributed` получает имя кластера, базу, локальную таблицу и ключ шардирования. Макросы выбраны, чтобы один DDL через `ON CLUSTER` создавал отдельный путь каждого шарда без вписанных вручную значений. Для образа зафиксирован точный текущий [LTS-выпуск 26.3.17.56](https://github.com/ClickHouse/ClickHouse/releases/tag/v26.3.17.56-lts); серверы и keeper используют один образ. ## Что здесь будет - одно широкое событие кликстрима по образцу выгрузки Яндекс Метрики вместо четырёх топиков; - второй источник — заказы бэкенда, ежедневным слепком в ту же Kafka; - сверка клиентской покупки с заказом бэкенда: деньги считаем по бэкенду, поведение и атрибуцию — по трекеру; - анонимный кликстрим и склейка кука↔пользователь через покупки; - ClickHouse кластером как единственным режимом. ## Чем отличается от предшественника Предшественник остаётся стабильным учебным стендом и заморожен для новых фич: там событие разрезано на четыре топика, есть только просмотры страниц, посетители опознаны по email, ClickHouse — одна нода. Развитие идёт здесь. ## Документация - [docs/specs/](docs/specs/) — спеки: источник истины о задуманном. - [docs/research/](docs/research/) — исследования; сейчас это формат кликстрима Яндекса, по которому строится модель события. - [AGENTS.md](AGENTS.md) — контракт работы в репозитории.