feat(orders): добавить приём слепков в STG
Зачем: - связать проигрывание модельных дней с пакетным приёмом заказов - показать на одном стенде различие потокового push и пакетного pull Что: - добавлен топик, Kafka-чтец и реплицированное сырьё заказов - добавлен даг orders_ingest с одним прямым чтением и идентификатором загрузки - работники мира отправляют слепок, ждут приём и только затем двигают позицию - решения, границы отказа и проверки отражены в ADR и архитектурных документах Проверка: - make lint - make config-test - make smoke - make check-clickhouse - make check-services
This commit is contained in:
@@ -57,8 +57,9 @@
|
||||
доли классов, стоимость доставки — калибровка при реализации; финальная
|
||||
фиксация чисел — пересборка эталонного мира, этап 7. При пересборке правки
|
||||
потребуют только числа, не устройство.
|
||||
- **Проверки приёма** — разовая приёмка допущения «один запуск — одно чтение»
|
||||
и опыты из [«Рисков и проверки»](ingestion.md) — тикет реализации приёма.
|
||||
- **Проверки приёма** — опыты из [«Рисков и проверки»](ingestion.md) про брак
|
||||
и версии в ODS — тикет перехода STG → ODS (#94). Допущение «один запуск —
|
||||
одно чтение» принято живым прогоном при исполнении #93.
|
||||
- **`_load_id` выше ODS** — вместе с устройством `dds.order` (#85).
|
||||
- **Контур проверок качества для расхождений** (даг DQ, `dm.dq_summary`) —
|
||||
остаётся в тумане карты #69; естественное место разговора — этап 4.
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
## Поток данных
|
||||
|
||||
После завершения генератора Airflow один раз читает байтовый Kafka-чтец и
|
||||
записывает полученную порцию в `stg.orders_raw`. Все строки получают `_load_id`,
|
||||
равный `run_id` Airflow. `_load_ts` вычисляется при этой записи и дальше
|
||||
переносится без пересчёта.
|
||||
записывает полученную порцию в `stg.orders_raw`. Даг зовётся `orders_ingest`, а
|
||||
дёргает его тот, кто положил слепок в топик, — работник пульта мира, — и ждёт
|
||||
конца прогона. Все строки получают `_load_id`, равный `run_id` Airflow.
|
||||
`_load_ts` вычисляется при этой записи и дальше переносится без пересчёта.
|
||||
|
||||
Один следующий `task_id` отвечает за весь переход STG → ODS. Внутри него два
|
||||
последовательных `INSERT SELECT` читают неизменный срез по `_load_id`: первый
|
||||
@@ -119,6 +120,13 @@ JSON-объектом с точным набором ключей: `order_id`, `
|
||||
из следующих запусков. После отказа от замены партиции это задержка, а не потеря
|
||||
или публикация неполного дня.
|
||||
|
||||
Отказ — случай другой, и «хвост дождётся» на него не распространяется. Офсеты
|
||||
порции коммитятся в момент чтения, поэтому упавшая вставка уносит прочитанное с
|
||||
собой: повторное чтение вернёт ноль, а часть строк может уже лежать на шарде.
|
||||
Позиция мира при этом не двигается, и тот же день уедет заново — в сырье он
|
||||
окажется частичным дублем, а старый хвост, ушедший той же порцией, не вернётся
|
||||
([ADR 0008](../../adr/0008-order-ingestion.md), «Следствия»).
|
||||
|
||||
## Отклонённые варианты
|
||||
|
||||
- Партиционная идемпотентность — `REPLACE PARTITION snapshot_date` или
|
||||
@@ -137,9 +145,6 @@ JSON-объектом с точным набором ключей: `order_id`, `
|
||||
|
||||
## Риски и проверка
|
||||
|
||||
- На стандартном мире сверить число отправленных заказов с числом строк,
|
||||
принятых одним прямым чтением. Это разовая приёмка допущения, не постоянный
|
||||
сторож.
|
||||
- На малой управляемой порции дать по одной строке каждого класса брака и две
|
||||
годные версии одного `order_id`. Две цели должны сохранить все непустые
|
||||
сообщения, а `ods.order_v` — вернуть новую версию независимо от фонового
|
||||
@@ -151,6 +156,11 @@ JSON-объектом с точным набором ключей: `order_id`, `
|
||||
|
||||
## Что проверено
|
||||
|
||||
Забор из Kafka в STG снят на живом стенде 18 августа 2026 года при исполнении
|
||||
#93: одно прямое чтение приносит весь слепок дня, метаданные доставки доступны,
|
||||
офсеты коммитятся, а сбой забора не двигает позицию мира. Числа — [ADR
|
||||
0008](../../adr/0008-order-ingestion.md), раздел «Что проверено».
|
||||
|
||||
MCP Context7 в сессии проектирования был недоступен. На локальном ClickHouse
|
||||
`26.3.17.56` проверено, что прямой `SELECT` Kafka Engine завершается после
|
||||
одной порции, а `FINAL` через `Distributed` исполняется на таблицах шардов.
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
keeper, Kafka, каркас сервисов. Этап 2 идёт: в `sql/ddl/` лежит вся цепочка
|
||||
`Kafka → STG → ODS` — чтец топика `hits`, таблицы сырья, типизированное
|
||||
событие с таблицей ошибок, поверхность актуального состояния и три матвью.
|
||||
Дальше по тексту устройство описано так, как оно проектируется; построенное от
|
||||
заложенного отличает карта таблиц в конце.
|
||||
Этап 3 добавил вход второго источника: топик `orders`, свой чтец и своё сырьё,
|
||||
которое наполняет даг `orders_ingest`, а не матвью. Дальше по тексту устройство
|
||||
описано так, как оно проектируется; построенное от заложенного отличает карта
|
||||
таблиц в конце.
|
||||
|
||||
Зона ответственности у документа одна — хранилище. Генератор описан отдельно:
|
||||
его замысел — в [спеке генератора](../specs/2026-08-01-generator.md), формат
|
||||
@@ -248,6 +250,11 @@ UTC+4), и пересчёт идёт один раз при наполнении
|
||||
|
||||
## Приём: поток и его свойства
|
||||
|
||||
Раздел — про события. У заказов приём устроен иначе: слепок забирает по команде
|
||||
даг `orders_ingest`, а не подписанная навсегда матвью — [ADR
|
||||
0008](../adr/0008-order-ingestion.md) и [спецификация приёма
|
||||
заказов](orders/ingestion.md).
|
||||
|
||||
Цепочка одна: чтец топика → матвью → сырьё STG → матвью разбора → событие и
|
||||
таблица ошибок ODS.
|
||||
|
||||
@@ -414,7 +421,7 @@ kafka_offset)`: смотрят такую таблицу от класса, а
|
||||
| Файл | Что в нём |
|
||||
|---|---|
|
||||
| `00-databases.sql` | базы слоёв |
|
||||
| `10-stg-tables.sql` | Kafka-таблица, локальная и распределённая таблицы сырья |
|
||||
| `10-stg-tables.sql` | чтецы топиков `hits` и `orders`, локальные и распределённые таблицы сырья обоих источников |
|
||||
| `20-ods-tables.sql` | типизированное событие и таблица ошибок |
|
||||
| `30-ods-views.sql` | актуальные события и матвью разбора в ODS |
|
||||
| `40-stg-views.sql` | матвью приёма: чтец в сырьё |
|
||||
@@ -430,10 +437,12 @@ ODS. Второе: матвью приёма создаётся последне
|
||||
отладке.
|
||||
|
||||
Применение — двумя одноразовыми сервисами при `make up`, по образцу уже
|
||||
работающих `airflow-init` и `superset-init`. Сначала `kafka-init` создаёт топик
|
||||
`hits` с двумя партициями, затем `clickhouse-init` дожидается его завершения и
|
||||
применяет файлы с ноды 1, `ON CLUSTER`. Этот порядок страхует от автосоздания
|
||||
топика с одной партицией. Переключателей тут два, и путать их не надо: брокер
|
||||
работающих `airflow-init` и `superset-init`. Сначала `kafka-init` создаёт топики
|
||||
— `hits` с двумя партициями и `orders` с одной ([ADR
|
||||
0008](../adr/0008-order-ingestion.md)), — затем `clickhouse-init` дожидается его
|
||||
завершения и применяет файлы с ноды 1: всё `ON CLUSTER`, кроме чтеца заказов —
|
||||
он объявлен только на этой ноде. Порядок страхует `hits` от автосоздания с
|
||||
одной партицией. Переключателей тут два, и путать их не надо: брокер
|
||||
автосоздание разрешает, а потребитель librdkafka внутри ClickHouse его не
|
||||
просит — оба конца измерены, см. «Что проверено». То есть стенд держится на
|
||||
умолчании клиента, а урок «обе ноды читают топик» умирает тихо, поэтому топик и
|
||||
@@ -460,13 +469,15 @@ ODS. Второе: матвью приёма создаётся последне
|
||||
|
||||
## Карта таблиц
|
||||
|
||||
Ниже — то, что закладывает этап 2; всё перечисленное лежит в `sql/ddl/`.
|
||||
Ниже — то, что закладывают этапы 2 и 3; всё перечисленное лежит в `sql/ddl/`.
|
||||
|
||||
| Слой | Объект | Что это |
|
||||
|---|---|---|
|
||||
| STG | `stg.hits_raw_kafka` | чтец топика `hits`, формат `RawBLOB` |
|
||||
| STG | `stg.hits_raw_rep` / `_dist` | сырая строка сообщения плюс метаданные доставки |
|
||||
| STG | `stg.hits_raw_mv` | наполняет сырьё из чтеца |
|
||||
| STG | `stg.orders_raw_kafka` | чтец топика `orders`, формат `RawBLOB`, только на ноде 1 и без матвью |
|
||||
| STG | `stg.orders_raw_rep` / `_dist` | сырое сообщение слепка, метаданные доставки и `_load_id` |
|
||||
| ODS | `ods.event_rep` / `_dist` | типизированное широкое событие |
|
||||
| ODS | `ods.event_v` | актуальная версия события с полями источника |
|
||||
| ODS | `ods.event_errors_rep` / `_dist` | строки, не прошедшие строгий приём |
|
||||
|
||||
Reference in New Issue
Block a user