Files
clickstream-data-platform/docs/architecture/monitoring.md
T
ddadmin e5c573bb25 fix(monitoring): панели уточнены по ревью, приёмка снята на стенде
- Зачем:
  - две линии ревью нашли, что колонки панели брака читаются как
    непересекающиеся кучи, «вовремя ли» из ADR 0002 не считается вовсе, а
    отказ от ряда «против вчерашнего» нигде не записан рядом с решением.
- Что:
  - в панели брака столбец назван «Из них в брак»: брак — часть приехавшего,
    а не соседняя куча.
  - панель слепка считает паузу после прошлого слепка — это и есть «вовремя
    ли» из ADR 0002; пустая пауза у самого раннего слепка держится
    обнуляемым типом.
  - отказ от ряда «против вчерашнего» записан в ADR 0002 и в monitoring.md с
    доводом: сдвиг на модельные сутки прописал бы ускорение мира в JSON.
  - в monitoring.md сказано, почему свежесть читает физическую _dist, а не
    ods.*_v, и почему панель слепка не знает окна; довод про сломанный JSON
    оставлен у кода, а не задвоен в доке.
  - README больше не утверждает, что панелей нет.
  - у разбора дашбордов убран флаг -e: он обещал утверждение, которого нет.
- Проверка:
  - make config-test (краснеет на нарочно сломанном JSON дашборда), make lint,
    make smoke 21/21, make check-clickhouse 10/10; все шесть панелей отвечают
    через /api/ds/query. Опыты приёмки и их следы — monitoring.md,
    «Что проверено».
2026-08-21 11:23:05 -04:00

206 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Мониторинг: из чего собран и что скребёт
Документ описывает зону мониторинга: какие сервисы в неё входят, что собирает
Prometheus, какие источники данных подготовлены в Grafana, каким пользователем
она ходит в ClickHouse и что показывают собранные дашборды. Зачем зоне именно
такой состав и какие дашборды на нём задуманы — [ADR
0002](../adr/0002-monitoring-scope.md); устройство доступа — [ADR
0007](../adr/0007-clickhouse-access.md).
**Что здесь есть и чего ещё нет.** Собран пол: свой образ Grafana с плагином
ClickHouse, два подготовленных источника данных, экспортёр метрик Kafka и цель
для него у Prometheus. Поверх пола стоит главный дашборд — «Данные»; «Кластер»
и «Запросы» приносят отдельные тикеты. Правил оповещения и серверного журнала
`system.text_log` тоже пока нет.
## Состав
| Сервис | Образ | Что делает |
|---|---|---|
| `prometheus` | `prom/prometheus:v3.13.2` | опрашивает цели раз в 15 секунд, порт стенда `29090` |
| `grafana` | `clickstream-grafana:local` | интерфейс мониторинга; собирается из `infra/grafana/`, порт стенда `23000` |
| `kafka-exporter` | `danielqsj/kafka-exporter:v1.9.0` | переводит состояние брокера в метрики Prometheus, порт `9308` |
Плагин ClickHouse 4.20.0 входит в образ Grafana. Фоновая установка плагинов
при запуске отключена.
## Что скребёт Prometheus
| Цель | Задание | Метка `role` | Откуда метрики |
|---|---|---|---|
| `clickhouse-01:9363` | `clickhouse` | `server` | встроенный экспортёр ноды |
| `clickhouse-02:9363` | `clickhouse` | `server` | встроенный экспортёр ноды |
| `clickhouse-keeper:9363` | `clickhouse-keeper` | `keeper` | встроенный экспортёр keeper |
| `kafka-exporter:9308` | `kafka` | `exporter` | внешний экспортёр |
Ровно эти четыре цели пересчитывает `check_prometheus_targets` в
`scripts/stand-smoke.sh` — и по значению `up`, и по списку адресов. Пятая цель
красит смоук; это и есть способ заметить, что состав пола поменяли молча.
## Источники данных Grafana
Оба источника подготовлены файлами в `infra/grafana/provisioning/datasources/`
и объявлены `editable: false`: править их через интерфейс нельзя, источник
истины — репозиторий.
- `prometheus` — основной по умолчанию, ходит на `http://prometheus:9090`.
- `clickhouse` — плагин `grafana-clickhouse-datasource`, нативный протокол,
`clickhouse-01:9000`, пользователь `grafana`, пароль из `.env`.
Источник ClickHouse смотрит на `clickhouse-01`. Системные таблицы обеих нод
панели читают через `clusterAllReplicas`, как принято в ADR 0002.
## Доступ к ClickHouse
Grafana ходит пользователем `grafana` с ролью `monitoring_reader`: читает слои,
таблицы базы `dic` и системные таблицы. `REMOTE` разрешает
`clusterAllReplicas`, `CLUSTER` — запросы `ON CLUSTER`. Решение о своей роли
записано в [ADR 0007](../adr/0007-clickhouse-access.md). Пароль задаётся
переменной `CLICKHOUSE_GRAFANA_PASSWORD`.
## Куда кладутся дашборды
Каталог `infra/grafana/provisioning/dashboards/` смонтирован в контейнер и
объявлен провайдером в `provider.yml`: Grafana подхватывает оттуда файлы
дашбордов, удалять и править их через интерфейс запрещено. Новый дашборд — это
новый файл в каталоге и больше ничего: в `compose.yaml` заходить не нужно, ради
этого каталог и заведён заранее.
Файлы каталога разбирает `make config-test`, рядом с файлами дагов и по тому же
доводу ([testing.md](testing.md)).
## Дашборд «Данные»
`infra/grafana/provisioning/dashboards/data.json` — шесть панелей на один
экран. Вопрос у экрана один: с потоком всё в порядке? Состав панелей и довод за
каждую — [ADR 0002](../adr/0002-monitoring-scope.md).
Порогов и цветовых вердиктов на панелях нет: на дашборд смотрят глазами,
красное и зелёное живёт в проверках и дагах DQ.
| Панель | Откуда берёт | О чём отвечает |
|---|---|---|
| Свежесть | `ods.event_dist`, `ods.order_dist` | сколько прошло с последней доехавшей строки |
| Поток | `stg.hits_raw_dist`, `stg.orders_raw_dist` | сколько строк приезжает в слой сырья |
| Брак | те же и `ods.*_errors_dist` | сколько приехавшего не разобралось и какая это доля |
| Сходимость | экспортёр Kafka и `stg.hits_raw_dist` | произведённое против приземлившегося |
| Отставание | `kafka_consumergroup_lag` | сколько сообщений не прочитано |
| Дневной слепок | `stg.orders_raw_dist` | какой слепок доехал, когда и после какой паузы |
### Почему слои у панелей разные
Свежесть спрашивают у ODS. Это слой, который читают, и у заказов дорога до него
длиннее: сырьё привозит забор, а типизированную строку кладёт разбор. Встань
разбор — свежесть ODS это покажет, свежесть сырья нет.
Читает свежесть физическую `_dist`, а не каноническое `ods.*_v`. Представление
прячет за собой `FINAL` и отвечает про текущее состояние сущностей, а вопрос
здесь про доставку: местом диагностики доставленных версий физическая таблица
названа там же, где заведено представление (`sql/ddl/30-ods-views.sql`).
Поток и брак считаются по слою сырья. Сырьё записывает каждую доставку и ничего
не схлопывает, а `ReplacingMergeTree` в ODS схлопнет и повтор доставки события,
и все версии одного заказа. Считай мы поток по ODS — он занизился бы, и тем
сильнее, чем дольше живёт стенд.
Доля брака берётся от приехавшего, а не от суммы «годные плюс брак»: брак не
отдельная куча, а часть сырья, которая не прошла разбор.
Окно у панели брака — окно дашборда, и это не косметика. Сырьё живёт трое
суток, а брак — месяц: доля за всё время делила бы месяц брака на трое суток
приехавшего и однажды перевалила бы за сотню процентов.
Панель дневного слепка, наоборот, окна не знает. Её вопрос про состояние, а не
про отрезок, и последние десять слепков она показывает всегда.
Отдельного ряда «против вчерашнего» на панели потока нет, и это решение, а не
пропуск. Реальное «вчера» на стенде чаще всего приходится на время, когда
стенда ещё не было. А сдвинуть ряд на модельные сутки значит записать в JSON
дашборда ускорение мира — ровно ту пометку про тик, которую [ADR
0002](../adr/0002-monitoring-scope.md) в дашборде держать не велит: поменяют
ускорение, и панель молча соврёт. Сравнение остаётся глазу: модельные сутки
укладываются в минуты реального времени, и соседние дни мира помещаются в одно
окно панели сами.
### Чтецов Kafka панели не читают
`stg.hits_raw_kafka` и `stg.orders_raw_kafka` — таблицы движка Kafka, а не
хранилище: запрос из панели у второго забрал бы слепок себе и сдвинул офсеты
(`kafka_commit_on_select`, см. `sql/ddl/10-stg-tables.sql`), а даг приёма
приехал бы к пустому топику. Приземлившееся панели считают по `stg.*_raw_dist`,
произведённое — по метрикам экспортёра.
### Как считается сходимость
Произведённое живёт в Kafka, приземлившееся — в ClickHouse, и со своей стороны
ни одна из них не видит другую. Поэтому панель смешанная: ряд «произведено в
Kafka» приходит из Prometheus, ряд «приземлилось в ClickHouse» — из ClickHouse.
Единицы общие — сообщений за интервал панели. Со стороны Kafka это разность
офсетов топика, «сейчас минус интервал назад», с суммой по обеим партициям; со
стороны ClickHouse — `count()` строк сырья по тому же интервалу.
Два соседних способа отвергнуты, и оба по замеру на живом стенде. `increase`
растягивает приращение на всё окно и на минутном интервале промахивается на
проценты: здоровый стенд выглядел бы расходящимся. Накопленный итог от начала
окна точнее обоих приростов, но отсчитывать его надо от края окна — а на
свежем стенде окно начинается раньше, чем появился экспортёр, и ряд пропадает
целиком.
Столбцы ClickHouse подписаны правым краем, а не левым. Точка Prometheus — это
прирост к моменту времени, а `count()` по интервалу — сумма, которая набирается
к его концу; подпиши мы её началом, здоровые ряды разъехались бы ровно на один
столбец. Шаг панели при этом не мельче минуты: экспортёр опрашивают раз в
пятнадцать секунд, и на более мелком шаге ряд Kafka пошёл бы ступеньками там,
где ряд ClickHouse идёт гладко.
Точка в точку ряды всё равно не совпадут, и ждать этого не надо: опрос
экспортёра не попадает на границы столбцов, поэтому на разгоне потока линия
Kafka идёт чуть выше. Читается устойчивый разрыв между линиями, а не разница в
один столбец.
Панель смотрит на топик событий. У него приём непрерывный, и разрыв виден
сразу. Слепок заказов уезжает пачкой раз в модельные сутки, и вопрос к нему
другой — не «сходится ли поток», а «доехала ли выгрузка и вовремя ли». На него
отвечает своя панель, и модельный день она берёт из самого сообщения: в сырьё
он приезжает полем `snapshot_date`.
## Что проверено
Права роли `monitoring_reader` сверены 21 августа 2026 года по документации
ClickHouse через MCP Context7; разбор — в
[ADR 0007](../adr/0007-clickhouse-access.md), раздел «Что проверено».
Сам состав проверен на живом стенде 21 августа 2026 года, собранном заново
после `make clean`.
- Grafana видит плагин `grafana-clickhouse-datasource` 4.20.0
(`/api/plugins?type=datasource`), оба подготовленных источника здоровы.
- Запрос источника ClickHouse к `system.one` через `clusterAllReplicas` вернул
2 — с одной ноды видны обе.
- Prometheus видит ровно четыре цели, все со значением `up = 1`; запрос
`kafka_consumergroup_lag` вернул ряды по группам `clickstream_*`.
- `make smoke` 21/21, `make check-clickhouse` 10/10, `make check-services` 7/7.
Дашборд «Данные» проверен на живом стенде в тот же день, `world_live` снят с
паузы.
- Дашборд поднимается из каталога сам: файл положен, панели появились без
ручного импорта. Сохранение и удаление через API отвергнуты («Cannot save
provisioned dashboard», «provisioned dashboard cannot be deleted»).
- Все шесть панелей отвечают через `/api/ds/query` — и в окне часа по
умолчанию, и в окне на шесть часов, которое начинается раньше, чем поднялся
экспортёр. Пустых нет ни при идущем потоке, ни при остановленном.
- Брак: подсунутое в топик `hits` негодное сообщение легло в
`ods.event_errors` с классом `keyset_mismatch`; панель показала единицу и
долю 0,039 % в десятиминутном окне. Строка убрана мутациями из
`stg.hits_raw_rep` и `ods.event_errors_rep`, обе таблицы вернулись к нулю.
- Сходимость: на живом потоке за двадцать пять минут медиана расхождения между
рядами 3 %, худший столбец 11 % — на переломе потока, как и описано выше.
Отказы тоже по замеру: `increase` расходился сильнее, а накопленный итог
пропадал целиком, стоило окну начаться раньше экспортёра.
- Свежесть реагирует на остановленный поток и возвращается. Через пять минут
после конца модельного дня панель показала 305 с у событий и 288 с у
заказов; стоило пустить следующий день, события вернулись к секунде.
Свежесть заказов при этом растёт до конца дня и садится, когда доедет его
слепок, — так и устроен второй источник.