Files
ddadminandClaude Opus 5 5a21684dc4 fix(stand): поправлены находки ревью — причина дрейфа памяти и отзыв довода ADR 0001
Зачем

Двухосевое ревью нашло в PR фактическую ошибку и одну процессную дыру. Ошибка
того же класса, что уже снималась по ходу разбора: в ADR было записано, будто
RSS ноды полз вверх из-за страниц её бинарника. Замер на живой ноде это
опроверг.

Что

- ADR 0004: причина дрейфа переписана по замеру. За обычную сессию страницы
  бинарника 523 -> 531 МиБ, то есть стоят на месте, а рабочая память
  489 -> 723 МиБ. Бинарник объясняет постоянную часть расхода, а не рост;
  отчего растёт рабочая память, для этого решения знать не нужно. Вывод не
  меняется: одна только постоянная часть занимала больше половины гигабайтной
  коробки.
- ADR 0001: ресурсный довод отозван прямо в файле — и строкой статуса, и
  абзацем после самого довода. Обе оси ревью нашли это независимо друг от
  друга: строка «удерживает стенд в пределе 3,4 ГБ» читалась как действующая,
  хотя предела уже нет.
- stand-smoke.sh: OOMKilled поднимается и тогда, когда ядро убило процесс
  внутри живого контейнера, поэтому сообщение говорит про процесс, а не про
  контейнер. Флаг hurt переименован в problems и считает находки — как passed
  и failed по соседству.
- Формулировки ADR 0004 упрощены: «коробка» объясняется при первом упоминании,
  а метафоры «вход в самонастройку», «предохранители», «бронь», «полка» и
  «бюджет в новой одежде» заменены обычными словами. Правило AGENTS.md —
  сложную мысль пояснять при первом упоминании.

Проверка

make config-test — зелено. make smoke — 25 из 25, проверка выживания отработала
с новым сообщением.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 15:18:43 +03:00

7.5 KiB
Raw Permalink Blame History

ADR 0001. Сервисы каркаса стенда

Дата: 30 июля 2026 года. Статус: принято; ресурсный довод отозван ADR 0004.

Решение

Стенд использует Airflow 3.3.0 с LocalExecutor. Airflow разделён на одноразовый airflow-init и три долгоживущих процесса: API, планировщик и обработчик DAG. Triggerer не запускается: в каркасе нет отложенных задач. Два интеграционных пробника написаны через публичный airflow.sdk.

Для входа выбран SimpleAuthManager. У него нет команды создания пользователя, поэтому airflow-init записывает пароль администратора из окружения в JSON-файл отдельного тома airflow_auth. Новый именованный том принадлежит root, а Airflow работает от пользователя airflow. Поэтому airflow-init запускается от root, назначает владельца каталога и сразу выполняет Python и команды Airflow через runuser от пользователя airflow. Все файлы репозитория подключены к этому контейнеру только для чтения. JWT-секрет, ключ подписи ссылок на журналы и ключ Fernet одинаковы для всех процессов и приходят из окружения.

Один Postgres 16 хранит две базы метаданных. У Airflow и Superset разные базы, пользователи и строки подключения. Это экономит один контейнер, но сохраняет границу владения данными.

Airflow получает подготовленное общее подключение к clickhouse-01, а Superset — подключение clickhousedb:// к clickhouse-02. Провайдер ClickHouse для Airflow не нужен: локальный образ содержит прямой клиент. Пробник создаёт служебные таблицы ON CLUSTER, пишет на первой ноде и через remote читает Distributed на второй. Разные ноды сохраняют учебную ловушку: забытый ON CLUSTER проявится в Superset, даже если операция Airflow на первой ноде прошла успешно.

Клиент Kafka также добавлен прямо в образ Airflow. Официальный провайдер использует тот же confluent-kafka, а пробнику не нужны его подключение, операторы и обёртки. Топик пробника постоянный, сообщение каждого запуска отличается уникальным маркером.

Superset собирается от apache/superset:6.1.0. В образ добавлены clickhouse-connect для ClickHouse и psycopg2-binary для метаданных Postgres. Подключение ClickHouse импортируется из YAML при подготовке.

Prometheus читает встроенные точки метрик двух серверов ClickHouse и keeper. Отдельные сборщики не нужны. Grafana получает источник Prometheus из файла.

Почему

Разделение Airflow показывает архитектуру третьей версии и даёт честные проверки здоровья процессов. LocalExecutor достаточен для одного учебного компьютера. Отказ от triggerer, второго Postgres и внешних сборщиков удерживает стенд в пределе 3,4 ГБ.

Ресурсный довод предыдущего абзаца отозван ADR 0004: предела 3,4 ГБ у стенда нет, вместо него объявлено требование к машине. Сами решения остаются в силе по остальным основаниям, названным выше. Отказ от внешних сборщиков вдобавок частично пересмотрен ADR 0002: сборщик метрик Kafka нужен ради отставания чтения.

Тома clickhouse_*_data хранят данные keeper и двух нод ClickHouse. kafka_data, postgres_metadata_data, superset_home, prometheus_data и grafana_data хранят состояние своих сервисов. airflow_logs хранит журналы, а airflow_auth — JSON-файл с учебным паролем администратора. Каталог dags/ и все файлы настройки подключены только для чтения, поэтому контейнеры не меняют рабочее дерево.

Что проверено

Исследование задачи сверило через Context7 публичный API DAG с Task SDK Airflow и аргумент schedule. Решение дополнительно проверено по документации Airflow 3.3.0: публичный интерфейс, архитектура процессов, SimpleAuthManager и API здоровья. Оттуда взяты airflow.sdk, обязательный отдельный обработчик DAG, возможность не запускать triggerer и проверка конкретных компонентов здоровья.

Для интеграционных пробников проверены Connection.get в публичном airflow.sdk, запросы через clickhouse-connect и состав официального провайдера Kafka. Выбран прямой confluent-kafka: провайдер строит свои подключения и обёртки поверх него, которые двум коротким пробникам не нужны.

Драйверы и строки подключения проверены по документации Superset 6.1.0: подключения к базам, ClickHouse и база метаданных. Форма декларативного импорта и команда test-db проверены по исходному коду Superset 6.1.0 и на запущенном образе. Конфигурация метрик проверена по файлам закреплённого образа ClickHouse 26.3.17.56 и на живых точках серверов и keeper.