- Зачем: - одно длинное ТЗ заставляло одновременно держать в голове три самостоятельных опыта и их очистку. - Что: - проверки, разбор ODS и сборка DDS разнесены по трем последовательным заданиям. - уточнены границы учебной реализации, место диагностики и выбор закрытого дня. - оглавление ступени 5 дополнено ссылками на все три задания. - Проверка: - проверены ссылки, пробная пачка jq, кластерные мутации и отсутствие ошибок пробелов в diff.
125 lines
8.6 KiB
Markdown
125 lines
8.6 KiB
Markdown
# Перепишите сборку заказов в DDS
|
||
|
||
**Чему учит:** переписать пересборку заказов по состоянию слоев и доказать ее
|
||
результат на пропущенном закрытом дне.
|
||
|
||
## Сначала прочитать
|
||
|
||
- [проверки заказов](5-1-order-checks.md);
|
||
- [разбор заказов в ODS](5-2-order-parsing.md);
|
||
- [модель заказа DDS](../architecture/dds/order.md);
|
||
- [дневной конвейер](../architecture/etl.md#объём-прогона);
|
||
- [раскладку по шардам](../architecture/storage.md#раскладка-по-шардам).
|
||
|
||
## Граница задания
|
||
|
||
Удалите готовый SQL и перепишите только три файла:
|
||
|
||
- `sql/dds/order_scope.sql`;
|
||
- `sql/dds/order_rebuild.sql`;
|
||
- `sql/dds/order_replace.sql`.
|
||
|
||
Даг `dds_transform`, DDL, донор, ODS и обе проверки из первого задания уже
|
||
задают границу работы. Перед началом убедитесь, что пробные строки предыдущего
|
||
задания удалены, а семь DQ дают зеленый результат.
|
||
|
||
Поставьте `world_live` на паузу и дождитесь завершения активных прогонов. До
|
||
завершения опыта не запускайте `world_live_day`, `world_initialize` и
|
||
`world_recreate`. `world_next_day` понадобится только в явно указанном ниже
|
||
случае.
|
||
|
||
## Договор с дагом
|
||
|
||
Сохраните интерфейс `dds_transform`:
|
||
|
||
| Файл | Вход | Результат |
|
||
|---|---|---|
|
||
| `order_scope.sql` | без параметров | одна строка `first_day`, `last_day` |
|
||
| `order_rebuild.sql` | `{first_day:Date}`, `{last_day:Date}`, `{load_id:String}` | выбранные дни в `dds.order_stage_dist` |
|
||
| `order_replace.sql` | день в `{{ params.day }}` | партиция дня в `dds.order_rep` |
|
||
|
||
Объем состоит из текущего окна источника и хвоста от первого дня, который есть
|
||
в ODS, но отсутствует в DDS. Текущее окно дают строки последнего
|
||
`snapshot_date`: их минимальный и максимальный день заказа. Если источник
|
||
пуст, `order_scope.sql` не возвращает строку. Если дыр нет, `first_day` равен
|
||
началу окна. Если дыра старше, непрерывный отрезок начинается с нее.
|
||
|
||
`order_rebuild.sql` сначала очищает все партиции `dds.order_stage_rep` на
|
||
кластере, затем записывает в `dds.order_stage_dist` весь выбранный отрезок. Он
|
||
читает текущее состояние `ods.order_v`, вычисляет `order_date`, переводит
|
||
времена в `Europe/Samara`, разбирает `items` в три параллельных массива и
|
||
ставит координаты запуска.
|
||
|
||
Запись через Distributed должна завершиться до замены и использовать ключ
|
||
целевой таблицы для раскладки строк. Способ собрать весь отрезок внутри файла
|
||
выберите сами.
|
||
|
||
`order_replace.sql` работает с локальными `dds.order_rep` и
|
||
`dds.order_stage_rep` на всем кластере. `REPLACE PARTITION` переносит готовую
|
||
дневную партицию из донора и оставляет донор на месте. Структура, ключи и
|
||
политика хранения совпадают: DDL объявляет донор через `AS dds.order_rep`.
|
||
|
||
## Восстановите ближайший закрытый день
|
||
|
||
Найдите последний по дате день DDS, который лежит левее начала текущего окна
|
||
ODS. Это ближайший к окну закрытый день: его удаление показывает расширение
|
||
объема на дыру без пересборки всей истории.
|
||
|
||
Если такого дня еще нет, один раз продвиньте мир через `world_next_day`,
|
||
дождитесь `orders_ingest`, затем запустите `etl_pipeline`. После этого снова
|
||
зафиксируйте модельное время до конца опыта и выберите ближайший закрытый день.
|
||
|
||
Сохраните для него число заказов и контрольную сумму деловых полей без
|
||
`_load_id` и `_load_ts`. Удалите только его партицию:
|
||
|
||
```sql
|
||
ALTER TABLE dds.order_rep ON CLUSTER clickstream_cluster
|
||
DROP PARTITION 'YYYY-MM-DD';
|
||
```
|
||
|
||
Сразу запустите `dq_check`, до восстановления партиции. Красный результат
|
||
должны дать `orders_vs_ods` и `purchase_vs_orders_vs_dds`.
|
||
`revenue_daily_vs_dds` тоже даст красный результат, если в партиции были
|
||
оплаченные заказы. `classes_vs_inventory` останется зеленым: до запуска
|
||
`dm_transform` эта проверка читает прежнюю витрину сверки.
|
||
|
||
Запустите `etl_pipeline`. В группе `dds_transform.order` значение `first_day`
|
||
должно совпасть с удаленным днем, а задачи `replace` - покрыть непрерывный
|
||
отрезок от него до конца текущего окна. `first_day` ищите в строке про объем
|
||
пересборки в журнале задачи `order.scope` дага `dds_transform`. После успешного
|
||
прогона число заказов и контрольная сумма выбранного дня должны совпасть с
|
||
сохраненными.
|
||
|
||
## Проверьте раскладку и повтор
|
||
|
||
Напишите отдельный запрос к `dds.order_dist`, который получает фактическую
|
||
ноду через `hostName()`, вычисляет ожидаемую по `cityHash64(order_id) % 2` и
|
||
считает несовпадения по каждой ноде. Остаток 0 соответствует
|
||
`clickhouse-01`, остаток 1 - `clickhouse-02`. На обеих нодах число строк на
|
||
чужом шарде должно быть нулевым. Счетные DQ читают Distributed-таблицы и такую
|
||
ошибку раскладки не обнаруживают.
|
||
|
||
Запустите `etl_pipeline` еще раз при неизменном модельном времени. Группа
|
||
заказов снова должна пересобрать текущее изменяемое окно. Контрольные суммы
|
||
деловых полей остаются прежними, а все семь проверок дают зеленый результат.
|
||
|
||
## Когда можно остановиться
|
||
|
||
Удаленная партиция восстановлена, ее число строк и контрольная сумма совпали
|
||
с исходными. На чужих шардах строк нет, повторный прогон не изменил деловые
|
||
данные, семь DQ зелены. Если до упражнения `world_live` работал, теперь его
|
||
можно снять с паузы.
|
||
|
||
## Приемка
|
||
|
||
- [ ] переписаны только три файла `sql/dds/order_*.sql`, инфраструктура
|
||
упражнения не изменена;
|
||
- [ ] удален ближайший к окну закрытый день, а красный DQ зафиксирован до
|
||
восстановления;
|
||
- [ ] `first_day` начался с удаленного дня, задачи замены покрыли непрерывный
|
||
отрезок до конца окна;
|
||
- [ ] число заказов и контрольная сумма восстановленного дня совпали;
|
||
- [ ] `order_items_total`, `orders_vs_ods` и пять прежних DQ зелены;
|
||
- [ ] проверка `hostName()` не нашла заказов DDS на чужом шарде;
|
||
- [ ] повторный `etl_pipeline` сохранил деловые данные и зеленые проверки.
|