docs(course): согласованы уроки со startup-history

- Зачем:
  - курс должен проходить на чистом стенде без архивного сида и скрытых шагов.
- Что:
  - уроки 00, 01 и 05 согласованы с генераторными топиками, no-live default и consumer lag.
  - упражнение с kafka_msg_ts переведено на повторную заливку без сброса схемы.
  - учебный путь в операционной документации ведёт через startup-history.
- Проверка:
  - make generated-history-analytics; make up; doc rg checks; git diff --check.
This commit is contained in:
2026-07-05 22:01:00 +03:00
parent 67313494d9
commit 77e4fb6119
5 changed files with 78 additions and 27 deletions
+12 -4
View File
@@ -60,9 +60,17 @@ make up
- `geo_events` — гео;
- `location_events` — местоположение.
Рядом может быть служебный топик `__consumer_offsets` (если включён показ внутренних
топиков) — его Kafka использует сама, мы его не трогаем. У каждого нашего топика в колонке
с партициями стоит **1**: топик маленький, делить не на что.
Рядом могут быть служебные топики:
- `__consumer_offsets` — внутренний топик Kafka. В нём Kafka хранит прогресс
consumer-групп;
- `generator_state` — слепок состояния генератора на правой границе стартовой истории.
По нему live-продолжение понимает, откуда продолжать тот же мир;
- `generator_startup_history_manifest` — паспорт стартовой истории: seed, границы
модельного времени и контрольные числа.
Служебные топики нужны стенду, но в упражнениях курса мы их не меняем. У каждого нашего
топика событий в колонке с партициями стоит **1**: топик маленький, делить не на что.
**Сообщения в топике.** Открой `browser_events` → вкладку *Messages*. Это и есть события
стенда. У каждого сообщения видно:
@@ -127,7 +135,7 @@ consumer-группа помнит, где остановилась: дочит
| Действие | Где смотреть | Что ожидать |
|----------|--------------|-------------|
| открыть список топиков | Kafka UI → *Topics* | 4 топика событий (`*_events`), у каждого 1 партиция |
| открыть список топиков | Kafka UI → *Topics* | 4 топика событий (`*_events`) и, возможно, служебные топики генератора |
| открыть `browser_events` | вкладка *Messages* | сообщения с offset'ами 0, 1, 2, …; в Value — JSON события |
| сравнить два времени | Value (`event_timestamp`) vs Kafka *Timestamp* | время события и время доставки в Kafka различаются |
| открыть consumers | Kafka UI → *Consumers* | 4 группы `ch_stg_*`, статус `STABLE`, по 1 участнику |
@@ -189,20 +189,20 @@ SELECT
FROM stg.kafka_browser_raw;
```
**Перезаливаем срез, чтобы новая колонка заполнилась.** Сначала чистим таблицу — иначе
рядом останутся строки из секции 2, вставленные ещё *до* `ADD COLUMN`, и в них
`kafka_msg_ts` будет пустой (`1970-01-01`):
**Перезаливаем срез, чтобы новая колонка заполнилась.** Сначала чистим только таблицу
приёмника — иначе рядом останутся строки из секции 2, вставленные ещё *до*
`ADD COLUMN`, и в них `kafka_msg_ts` будет пустой (`1970-01-01`):
```sql
TRUNCATE TABLE stg.browser_raw;
```
Затем возвращаем стенд в чистое состояние и заново создаём стартовую историю, чтобы
Kafka-движок прочитал сообщения уже с новой схемой:
Затем повторно создаём стартовую историю **без очистки volumes**. Это важно:
`CLEAN_START=0` сохраняет твою новую колонку и пересозданное MV, но добавляет свежие
сообщения в Kafka, чтобы ClickHouse прочитал их уже с новой схемой.
```bash
make generated-history-analytics
make up
CLEAN_START=0 make generated-history-analytics
```
**Смотрим результат:**
@@ -232,7 +232,7 @@ ALTER TABLE stg.browser_raw DROP COLUMN kafka_msg_ts;
```
```bash
make ddl # пересоздаёт эталонный MV из 10_stg.sql схема снова как в репозитории
make ddl # пересоздаёт эталонное MV из 10_stg.sql, схема снова как в репозитории
```
Если запутался в состоянии — всегда есть полный чистый прогон:
+35 -12
View File
@@ -81,16 +81,19 @@ make up
Открой Prometheus: `http://localhost:9090`. В меню зайди в **Status → Targets**.
Ожидаем три job:
Ожидаем основные job:
| Job | Target внутри Docker | Что это значит |
|-----|----------------------|----------------|
| `clickhouse` | `clickhouse:9126` | ClickHouse отдаёт встроенный Prometheus endpoint |
| `kafka` | `kafka-exporter:9308` | `kafka-exporter` подключился к Kafka и отдаёт метрики |
| `airflow` | `statsd-exporter:9102` | `statsd-exporter` отдаёт метрики Airflow в формате Prometheus |
| `generator` | `generator:9109` | live-генератор отдаёт свои метрики, только когда явно запущен |
У всех трёх состояние должно быть `UP`. Если один target `DOWN`, Grafana дальше будет показывать
`No data` или старые значения.
У `clickhouse`, `kafka` и `airflow` состояние должно быть `UP`. `generator` на штатном
backfill-only стенде может быть `DOWN`, потому что `make up` не запускает live-генератор.
Это нормально для курса до явного `make generator-continue`. Если один из трёх основных
target `DOWN`, Grafana дальше будет показывать `No data` или старые значения.
То же можно проверить из терминала:
@@ -157,8 +160,14 @@ URL: `http://localhost:3000/d/kafka-overview/kafka-overview`
- **Partitions** и **Partition Offsets (Current)** — текущие offset-ы по партициям.
**Consumer lag** — это разница между тем, что уже лежит в топике, и тем, что consumer group
успела прочитать. В нашем стенде lag обычно быстро возвращается к нулю: данных мало, ClickHouse
читает быстро. Если lag растёт и не снижается, downstream не успевает за Kafka.
успела прочитать. В нашем стенде ClickHouse обычно читает быстро, поэтому большой устойчивый
lag не ожидается.
Есть важная оговорка из урока 0: ClickHouse-движок не всегда показывает свой прогресс как
обычная Kafka-группа. Поэтому в Kafka UI колонки offset/lag у `ch_stg_*` могут быть пустыми,
а в Grafana панель lag может быть пустой или нулевой. Это не конфликт между уроками. Для
точной проверки чтения со стороны ClickHouse смотри `system.kafka_consumers`, а Grafana здесь
используй как общий сигнал: появился ли большой lag, который не уходит.
### Airflow Overview
@@ -187,7 +196,7 @@ URL: `http://localhost:3000/d/airflow-overview/airflow-overview`
### `scrape_configs`: кого опрашивает Prometheus
В файле три блока:
В файле четыре блока:
```yaml
scrape_configs:
@@ -202,10 +211,12 @@ scrape_configs:
`localhost`: Prometheus живёт внутри compose-сети и ходит к соседним контейнерам по их service
name.
Kafka и Airflow устроены так же, но с exporter-ами:
Kafka, Airflow и generator устроены так же, но источники разные:
- `kafka``kafka-exporter:9308`;
- `airflow``statsd-exporter:9102`.
- `airflow``statsd-exporter:9102`;
- `generator``generator:9109`, только когда live-генератор явно запущен.
Без live этот target может быть `DOWN`, как в проверке Prometheus выше.
### Почему Airflow идёт через StatsD
@@ -257,9 +268,21 @@ Grafana.
| Airflow Alerts | `High Task Failure Rate` | растёт rate failed tasks |
| Airflow Alerts | `High DAG Parse Time` | DAG-файлы долго парсятся |
Не все эти правила обязаны стрелять в учебном стенде. Часть порогов специально похожа на
продовые: они показывают, как формулируется условие, но не создают шум на каждом маленьком
прогоне.
Не все эти правила обязаны быть тихими в учебном стенде. По умолчанию `make up` и
`make generated-history-analytics` **не запускают live-генератор**, поэтому после готовой
стартовой истории новые сообщения перестают приходить. Из-за этого `Kafka No Messages Produced`
может перейти в `Alerting` на полностью здоровом backfill-only стенде. Если хочешь проверить
это правило в спокойном состоянии, явно включи live:
```bash
make generator-continue
```
После наблюдения останови live-генератор, чтобы он не менял стенд дальше:
```bash
make generator-down
```
---
@@ -334,7 +357,7 @@ make recover-monitoring
| Действие | Где смотреть | Что ожидать |
|----------|--------------|-------------|
| открыть Prometheus targets | `http://localhost:9090` → Status → Targets | `clickhouse`, `kafka`, `airflow` в состоянии `UP` |
| открыть Prometheus targets | `http://localhost:9090` → Status → Targets | `clickhouse`, `kafka`, `airflow` в состоянии `UP`; `generator` может быть `DOWN` без live |
| открыть `ClickHouse Overview` | Grafana dashboards | панели `Queries per Second`, `Failed Queries (total)`, `Inserted Rows/sec` не пустые |
| открыть `Kafka Overview` | Grafana dashboards | видны `Brokers Up`, `Topics`, `Consumer Lag by Group` |
| открыть `Airflow Overview` | Grafana dashboards | видны `Scheduler Heartbeat Rate`, `Queued Tasks`, `Task Failures vs Success Rate` |