fix(docs): расхождение нод при обновлении словаря названо верно

Зачем: горячее ревью поймало ошибку в трёх местах сразу. Было записано, что
после правки каталога ноды расходятся до тридцати секунд — число взято из
ширины окна LIFETIME(MIN 60 MAX 90). Ширина тут ни при чём: каждая нода ждёт
правки от нуля до верхней границы окна, фазы у них независимы, поэтому
расходиться они могут почти на все полторы минуты.

Что: исправлены ADR 0012, опорная точка мастер-спеки и комментарий DDL. Заодно
уточнено, что LIFETIME(0) неатомарность не предотвращал, а сжимал до разброса
исполнения SYSTEM RELOAD DICTIONARY ON CLUSTER, и что витрина выручки пока
спроектирована, а не построена.

Проверка: рассуждением, замером не подтверждалось — прежнее число тоже было
выведено, а не измерено. Замер в ADR (116 секунд на окне MIN 60 MAX 120)
относится к другому утверждению: что словарь обновляется сам.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 11:47:23 +03:00
co-authored by Claude Opus 5
parent b3e66034fc
commit d77acfdf6c
3 changed files with 20 additions and 14 deletions
+12 -9
View File
@@ -26,7 +26,7 @@
## Почему зона, а не прописка в слое
**Справочник читают несколько слоёв, а производит его ни один.** Каталог нужен
**Справочник читают несколько слоёв, а не производит ни один.** Каталог нужен
модели заказов в DDS и витрине выручки в DM; будущие регионы — представлению
событий в DDS; `analyst` читает его напрямую. Писателя нет вовсе: содержимое
приходит из файла репозитория. Прописка внутри `dds` приписывала слою модели
@@ -82,7 +82,7 @@ DM объекта, лежащего в DDS, — течение вниз, ров
**Историзацию и представление «последняя загрузка» из образца не берём.** В
промышленном примере таблица копит загрузки с меткой времени, а представление
берёт последнюю: источник приезжал извне, и версий у него не было нигде. У нас
версии есть — **история каталога это git**. Дублировать её в ClickHouse значит
версии есть — **история каталога это и есть git**. Дублировать её в ClickHouse значит
поставить конструкцию, у которой на стенде нет причины, а расшифровывать её
менти всё равно придётся.
@@ -137,17 +137,20 @@ DM объекта, лежащего в DDS, — течение вниз, ров
- **Обновление словаря на кластере не атомарно, и это заявленное свойство.**
Случайный момент внутри окна разводит опросы разных серверов, чтобы они не
ходили к источнику разом. Побочный эффект — ноды перезагружают словарь в
разное время, и на нашей паре расхождение доходит до 30 секунд: правка
каталога полминуты видна одной ноде и не видна другой. Прежнее решение
`LIFETIME(0)` эту неатомарность предотвращало; теперь она предъявлена
намеренно. Урок записан опорной точкой в мастер-спеке, тащить его в курс —
разное время. Ждать правки каталога каждой из них приходится от нуля до
верхней границы окна, а фазы у них независимы, поэтому расходиться они могут
почти на все полторы минуты: одна перезагрузилась сразу после правки, вторая
ещё нет. Прежнее решение `LIFETIME(0)` окно не закрывало, а сжимало до
разброса исполнения `SYSTEM RELOAD DICTIONARY ON CLUSTER`; теперь оно
раскрыто намеренно. Урок записан опорной точкой в мастер-спеке, тащить его в курс —
отдельное решение.
- **Номенклатура товаров — медленно изменяющийся справочник**, и в предметной
области это так. Стенд упрощает: файл в репозитории под версией git.
Историзации в хранилище нет, и обещать её этот документ не должен.
- Витрина выручки представление, поэтому категория подставляется в момент
запроса, и правка каталога меняет отчёт задним числом. Материализуй мы
категорию при приёме — не изменила бы.
- Витрина выручки спроектирована представлением, поэтому категория будет
подставляться в момент запроса, и правка каталога изменит отчёт задним
числом. Материализуй мы категорию при приёме — не изменила бы. Самой витрины
ещё нет, она приходит этапом 4.
## Что проверено
+4 -3
View File
@@ -696,9 +696,10 @@ v2, этап 0).
- словарь регионов из CSV той же машинерией, что каталог товаров (оживляет
`RegionCityID`);
- неатомарное обновление словаря на кластере: ноды перезагружают его в
случайный момент внутри окна `LIFETIME`, и после правки каталога до
тридцати секунд две ноды отвечают на один `dictGet` по-разному. Обвязка
готова ([ADR 0012](../adr/0012-dictionary-home.md)), урок остаётся на выбор;
случайный момент внутри окна `LIFETIME`, фазы у них независимы, и после
правки каталога две ноды отвечают на один `dictGet` по-разному — почти всё
окно целиком. Обвязка готова ([ADR
0012](../adr/0012-dictionary-home.md)), урок остаётся на выбор;
- лаба сессий: менти сначала собирает сессии сам, и только после — рассказ,
что с октября 2025 Метрика отдаёт `VisitID` прямо в хитах; частично
синтетическая постановка — осознанный приём;
+4 -2
View File
@@ -35,8 +35,10 @@ ENGINE = File(CSVWithNames, './catalog/products.csv');
--
-- Окно обновления вместо LIFETIME(0): словарь перезагружается сам в случайный
-- момент внутри окна. Случайность разводит обращения разных серверов к
-- источнику, и цена у неё заявленная — ноды обновляются вразнобой, до 30
-- секунд одна видит правку каталога, а вторая ещё нет.
-- источнику, и цена у неё заявленная — ноды обновляются вразнобой. Ждать
-- правки каталога каждой из них приходится от нуля до верхней границы окна,
-- фазы у них независимы, поэтому расходиться они могут почти на все
-- полторы минуты: одна перезагрузилась сразу после правки, вторая ещё нет.
--
-- Ключ строковый, поэтому COMPLEX_KEY_HASHED: числовой FLAT здесь неприменим.
--