fix(stand): снят несуществующий бюджет памяти, нодам ClickHouse — 4 ГиБ #25

Merged
ddmitry merged 3 commits from feat/21-resource-limits into main 2026-08-01 15:29:09 +03:00
Owner

Closes #21

Разбор задачи #21 увёл в сторону от её собственной гипотезы, поэтому решение
записано отдельным ADR: ADR 0004 «Ограничения ресурсов на стенде».

Что выяснилось

Гипотеза #21 — «кэши остались заводскими, суммарно на тринадцать гигабайт» —
опровергнута опытом. В коробке на гигабайт ClickHouse сам понижает каждый
кэш до 512 МиБ, а на стенде без данных они пусты.

Настоящая причина — сама коробка. Праздная нода держит VmRSS 846 МиБ, из
которых 530 МиБ — страницы её собственного бинарника: файл clickhouse весит
790 МБ, ядро подгружает куски по мере обращения, а отказ по превышению
сравнивается с RSS. На работу оставалось около 350 МиБ, и двадцать прогонов
пробника их выбирали.

Второе: предел 3,4 ГБ никто не выдавал. Это была оценка расхода из спеки,
посчитанная по стенду-предшественнику до первой сборки v2 и превращённая в
жёсткий порог. Порог стал критерием приёмки каждого этапа — и дальше блокировал
бы любой рост стенда на этапах 2-9.

Что сделано

  • ADR 0004. Бюджета памяти у стенда нет, есть требование к машине — около
    8 ГБ, доступных Docker. Ресурсный довод ADR 0001 отозван (сами решения в силе
    по своим основаниям; ближайшее следствие — вопрос triggerer на этапе 5
    решается по существу, а не по остатку памяти).
  • Нодам ClickHouse 4 ГиБ. Остальные лимиты не тронуты. Числа, выставленные
    ради прежнего бюджета, названы в ADR и лишены статуса решения: кто в них
    упрётся, меняет по первому свидетельству.
  • Проверка суммы убрана. Она мерила docker stats вместе со страничным
    кэшем и с появлением настоящих данных краснела бы на здоровом стенде — ровно
    тот грех, который уже осуждён в ADR 0002.
  • Взамен smoke спрашивает у Docker, не убивало ли ядро контейнер за память
    и не включалась ли политика перезапуска. Порога нет, ответ «да или нет».
    Дыра реальная: убитый контейнер Docker поднимает сам, healthcheck зеленеет, и
    стенд рапортует «всё хорошо» о ноде, которая умирала.
  • README и спека переписаны с предела на требование к машине; README
    объясняет, что такое «память, доступная Docker», и как её поднять в WSL2.

Проверка

команда итог
make config-test зелено
make smoke 25 из 25
make smoke-cluster 8 из 8
make smoke-guards 3 из 3, включая шаг «после восстановления стенд проходит make smoke» — тот, что падал 31 июля

На живом стенде с новой коробкой: max_server_memory_usage = 3,60 ГиБ, в
журнале Lowered mark cache size to 2.00 GiB because the system has limited RAM.

Семантика счётчиков Docker снята отдельными контейнерами: ручной restart
оставляет RestartCount = 0 (значит документированный перезапуск нод проверку
не роняет), убийство за память даёт OOMKilled = true и растущий счётчик,
убийство не за память OOMKilled не поднимает.

Что осталось за рамками

Рассуждение проходило слепое ревью свежей сессией: из десяти опорных утверждений
четыре оказались неверны и в PR не попали. Подробности — в ADR.

Closes #21 Разбор задачи #21 увёл в сторону от её собственной гипотезы, поэтому решение записано отдельным ADR: [ADR 0004 «Ограничения ресурсов на стенде»](docs/adr/0004-resource-limits.md). ## Что выяснилось Гипотеза #21 — «кэши остались заводскими, суммарно на тринадцать гигабайт» — **опровергнута опытом**. В коробке на гигабайт ClickHouse сам понижает каждый кэш до 512 МиБ, а на стенде без данных они пусты. Настоящая причина — сама коробка. Праздная нода держит `VmRSS` 846 МиБ, из которых 530 МиБ — страницы её собственного бинарника: файл `clickhouse` весит 790 МБ, ядро подгружает куски по мере обращения, а отказ по превышению сравнивается с RSS. На работу оставалось около 350 МиБ, и двадцать прогонов пробника их выбирали. Второе: предел 3,4 ГБ никто не выдавал. Это была оценка расхода из спеки, посчитанная по стенду-предшественнику **до первой сборки v2** и превращённая в жёсткий порог. Порог стал критерием приёмки каждого этапа — и дальше блокировал бы любой рост стенда на этапах 2-9. ## Что сделано - **ADR 0004.** Бюджета памяти у стенда нет, есть требование к машине — около 8 ГБ, доступных Docker. Ресурсный довод ADR 0001 отозван (сами решения в силе по своим основаниям; ближайшее следствие — вопрос triggerer на этапе 5 решается по существу, а не по остатку памяти). - **Нодам ClickHouse 4 ГиБ.** Остальные лимиты не тронуты. Числа, выставленные ради прежнего бюджета, названы в ADR и лишены статуса решения: кто в них упрётся, меняет по первому свидетельству. - **Проверка суммы убрана.** Она мерила `docker stats` вместе со страничным кэшем и с появлением настоящих данных краснела бы на здоровом стенде — ровно тот грех, который уже осуждён в ADR 0002. - **Взамен** smoke спрашивает у Docker, не убивало ли ядро контейнер за память и не включалась ли политика перезапуска. Порога нет, ответ «да или нет». Дыра реальная: убитый контейнер Docker поднимает сам, healthcheck зеленеет, и стенд рапортует «всё хорошо» о ноде, которая умирала. - **README и спека** переписаны с предела на требование к машине; README объясняет, что такое «память, доступная Docker», и как её поднять в WSL2. ## Проверка | команда | итог | | --- | --- | | `make config-test` | зелено | | `make smoke` | 25 из 25 | | `make smoke-cluster` | 8 из 8 | | `make smoke-guards` | 3 из 3, включая шаг «после восстановления стенд проходит make smoke» — тот, что падал 31 июля | На живом стенде с новой коробкой: `max_server_memory_usage` = 3,60 ГиБ, в журнале `Lowered mark cache size to 2.00 GiB because the system has limited RAM`. Семантика счётчиков Docker снята отдельными контейнерами: ручной `restart` оставляет `RestartCount` = 0 (значит документированный перезапуск нод проверку не роняет), убийство за память даёт `OOMKilled` = true и растущий счётчик, убийство не за память `OOMKilled` не поднимает. ## Что осталось за рамками Рассуждение проходило слепое ревью свежей сессией: из десяти опорных утверждений четыре оказались неверны и в PR не попали. Подробности — в ADR.
ddmitry added 1 commit 2026-08-01 14:36:52 +03:00
Зачем

Стенд упирался в память ноды ClickHouse: пробник валился на CREATE TABLE
ON CLUSTER, вместе с ним краснели make smoke и make smoke-guards. Причина не
та, что предполагал #21: дело не в заводских кэшах, а в коробке на гигабайт.
Около 550 МиБ RSS праздной ноды — страницы её собственного бинарника, и на
работу оставалось около 350 МиБ, которые пробник добирал за сессию.

Заодно выяснилось, откуда взялся предел 3,4 ГБ. Это была оценка расхода из
спеки, посчитанная по стенду-предшественнику до первой сборки v2 и превращённая
в жёсткий порог проверки. Порог стал критерием приёмки каждого этапа и дальше
блокировал бы любой рост стенда на этапах 2-9.

Что

- ADR 0004: бюджета памяти у стенда нет, есть требование к машине — около 8 ГБ,
  доступных Docker. Ресурсный довод ADR 0001 отозван, сами решения в силе.
- Нодам ClickHouse 4 ГиБ вместо гигабайта. Остальные лимиты не тронуты: ни один
  из них ни разу не сработал, а снять их скопом — то же изменение без
  свидетельств, каким они были выставлены.
- Из make smoke убрана проверка суммарного потребления. Она мерила docker stats
  вместе со страничным кэшем, то есть отвечала на вопрос «сколько файлов стенд
  потрогал», и с появлением настоящих данных краснела бы на здоровом стенде.
  Вместе с ней убрана привязанная к её сообщению проверка docs-guards.
- Взамен smoke спрашивает у Docker, не убивало ли ядро долгоживущий контейнер
  за память и не включалась ли политика перезапуска. Порога у проверки нет:
  убитый контейнер Docker поднимает сам, и без этого вопроса стенд отрапортует
  «всё хорошо» о ноде, которая умирала.
- README и раздел «Ресурсный бюджет» спеки переписаны с предела на требование
  к машине; README объясняет менти, что такое «память, доступная Docker».

Проверка

make config-test; make up; make smoke — 25 из 25; make smoke-cluster — 8 из 8;
make smoke-guards — 3 из 3, включая шаг «после восстановления стенд проходит
make smoke», который падал 31 июля.

На живом стенде с новой коробкой: max_server_memory_usage = 3,60 ГиБ, в журнале
ноды «Lowered mark cache size to 2.00 GiB because the system has limited RAM».
Семантика счётчиков Docker снята отдельными контейнерами: ручной restart
оставляет RestartCount = 0, убийство за память даёт OOMKilled = true и растущий
счётчик, убийство не за память OOMKilled не поднимает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry added 1 commit 2026-08-01 15:18:49 +03:00
Зачем

Двухосевое ревью нашло в PR фактическую ошибку и одну процессную дыру. Ошибка
того же класса, что уже снималась по ходу разбора: в ADR было записано, будто
RSS ноды полз вверх из-за страниц её бинарника. Замер на живой ноде это
опроверг.

Что

- ADR 0004: причина дрейфа переписана по замеру. За обычную сессию страницы
  бинарника 523 -> 531 МиБ, то есть стоят на месте, а рабочая память
  489 -> 723 МиБ. Бинарник объясняет постоянную часть расхода, а не рост;
  отчего растёт рабочая память, для этого решения знать не нужно. Вывод не
  меняется: одна только постоянная часть занимала больше половины гигабайтной
  коробки.
- ADR 0001: ресурсный довод отозван прямо в файле — и строкой статуса, и
  абзацем после самого довода. Обе оси ревью нашли это независимо друг от
  друга: строка «удерживает стенд в пределе 3,4 ГБ» читалась как действующая,
  хотя предела уже нет.
- stand-smoke.sh: OOMKilled поднимается и тогда, когда ядро убило процесс
  внутри живого контейнера, поэтому сообщение говорит про процесс, а не про
  контейнер. Флаг hurt переименован в problems и считает находки — как passed
  и failed по соседству.
- Формулировки ADR 0004 упрощены: «коробка» объясняется при первом упоминании,
  а метафоры «вход в самонастройку», «предохранители», «бронь», «полка» и
  «бюджет в новой одежде» заменены обычными словами. Правило AGENTS.md —
  сложную мысль пояснять при первом упоминании.

Проверка

make config-test — зелено. make smoke — 25 из 25, проверка выживания отработала
с новым сообщением.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry added 1 commit 2026-08-01 15:26:28 +03:00
Зачем

Комментарии к правке были размером с объяснение, хотя объяснение уже лежит
в ADR 0004. В compose.yaml четыре строки на одну настройку; в stand-smoke.sh
одиннадцать новых строк там, где на весь файл до этого было две — шебанг и
одна строка про разбор подстановок. Заодно в комментариях остались метафоры
(«бронь», «предохранители»), вычищенные из ADR прошлым коммитом.

Что

- compose.yaml: одна строка вместо четырёх — почему не гигабайт и куда идти
  за подробностями.
- stand-smoke.sh: две строки вместо шести — зачем проверка вообще нужна.
  Комментарий про разбор `--format` убран целиком: он оправдывался перед
  читателем, а не помогал ему.
- Комментарий про OOMKilled оставлен, но в одну строку: без него сообщение
  «убило процесс, а не контейнер» выглядит опиской.

Проверка

make config-test — зелено.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry merged commit c6c9e1082a into main 2026-08-01 15:29:09 +03:00
ddmitry deleted branch feat/21-resource-limits 2026-08-01 15:29:10 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ddmitry/clickstream-data-platform#25