@@ -13,12 +13,13 @@
Проверка суммарного потребления памяти уходит из `scripts/stand-smoke.sh` .
Вместе с ней уходят зависящая от её сообщения проверка в `tests/docs-guards.sh`
и описание порога в README. Взамен `make smoke` спрашивает у Docker, не убивало
ли ядро какой -нибудь долгоживущий контейнер за нехватку памяти и не включалась
ли политика перезапуска. Это не бюджет в новой одежде: порога у проверки нет,
она отвечает «да или нет».
ли ядро что -нибудь в долгоживущих контейнерах за нехватку памяти и не включалась
ли политика перезапуска. Прежний бюджет она не заменяет: числа, с которым
что-то сравнивают, у неё нет вовсе — ответ либо «убивало», либо « нет».
Нодам ClickHouse — по 4 ГиБ вместо гигабайта. Остальные `mem_limit` не
меняются.
Нодам ClickHouse — по 4 ГиБ вместо гигабайта. Дальше в этом тексте предел
памяти контейнера (`mem_limit` ) называется коробкой: сервер живёт внутри неё и
о самой машине ничего не знает. Остальные `mem_limit` не меняются.
Числа, выставленные ради прежнего бюджета, остаются в силе, но лишаются
статуса решения: `KAFKA_HEAP_OPTS` , `shared_buffers` , `max_connections` ,
@@ -51,35 +52,47 @@
своей коробки, сумма при этом была в норме — 3181 МиБ из 3242,5, — а красным
стенд сделал пробник. Механизм оповещения работает и без неё.
Замена не возвращает бюджет через заднюю дверь. Дыра, которую она закрывает,
другая: убитый за память контейнер Docker поднимает сам, через полминуты его
проверка состояния снова зелёная, и `make smoke` докладывает, что всё хорошо —
хотя нода умирала и потеряла всё, что держала в памяти. Новая проверка
спрашивает у Docker факт, а не величину, и потому нечего подгонять и незачем
пересматривать при росте стенда .
Новая проверка — не тот же бюджет под другим именем. Она закрывает другую дыру:
убитый за память контейнер Docker поднимает сам, через полминуты его проверка
состояния снова зелёная, и `make smoke` докладывает, что всё хорошо — хотя нода
умирала и потеряла всё, что держала в памяти. Проверка спрашивает у Docker
факт, а не величину, поэ тому её нечего подгонять и незачем пересматривать,
когда стенд растёт .
Гигабайт на ноду был неработоспособен, и причина не та, что предполагал
issue #21 . П раздная нода держит `VmRSS` 846 МиБ, из которых 530 МиБ — страницы
её собственного бинарника: файл `clickhouse` весит 790 МБ, и ядро подгружает
куски по мере обращения к ним. Учёта памяти в этом почти нет, `MemoryTracking`
всего 113 МиБ, но отказ по превышению сравнивается с RSS, куда чистые страницы
кода входят. Значит из гигабайта ноде оставалось около 350 МиБ рабочего места,
а RSS полз вверх просто потому, что каждый новый прогон пробника трогал новый
код: 531 → 774 МиБ за сессию. Рестарт возвращал число назад, и это выглядело
как утечка. Заводские кэши тут ни при чём: в коробке на гигабайт ClickHouse сам
понижает каждый до 512 МиБ, а на стенде без данных они и вовсе пусты.
issue #21 . У п раздной ноды около 530 МиБ RSS — это страницы её собственного
бинарника: файл `clickhouse` весит 790 МБ, ядро подгружает куски по мере
обращения к ним, а отказ по превышению памяти сравнивается с RSS, куда такие
страницы входят. Учёта сервера в них почти нет: `MemoryTracking` при этом
всего 113 МиБ. Это постоянная часть расхода: меньше неё нода не занимает
никогда. Из гигабайта на саму работу оставалось около 350 МиБ.
Лимит для ClickHouse — не потолок , а вход в самонастройку. Сервер берёт 0,9 о т
того, что видит, под общий предел памяти и 0,5 — под размеры кэшей и пороги
сброса на диск. Поэтому «поднять потолок ничего не стоит» верно для девяти
сервисов, которые лимит не читают, и неверно для двух нод: от коробки зависит,
где у них срабатывают предохранители. Снять лимит с нод по той же причине
нельзя — без коробки каждая считает свои доли от всей машины, и память у
машины кончится раньше, чем сервер решит экономить. Панель «не упёрлись ли
ноды в память» из ADR 0002 тоже требует знаменателя. Сумма всех потолков после
правки больше восьми гигабайт, и это не противоречие: `mem_limit` — потолок, а
не бронь, Docker ничего не резервирует, в покое стенд занимает около 3,2 ГБ .
Восемь гигабайт нужны не сумме потолков, а работе с запасом.
Дальше нода набирает рабочую память , и вместе с постоянной частью та перестаё т
помещаться. За обычную сессию стенда замерено: страницы бинарника 523 → 531
МиБ, то есть стоят на месте, а рабочая память 489 → 723 МиБ. Инцидент 31 июля
имел ту же форму — 531 → 774 МиБ: та же постоянная часть плюс наросшая работа.
Рестарт возвращал число назад, и это выглядело как утечка. Отчего именно растёт
рабочая память, здесь не разбирается — для решения хватает того, что одна
только постоянная часть занимала больше половины коробки. Заводские кэши тут
ни при чём: в коробке на гигабайт
ClickHouse сам понижает каждый до 512 МиБ, а на стенде без данных они и вовсе
пусты .
Для ClickHouse коробка — не просто верхняя граница: сервер настраивает себя по
её размеру. При запуске он читает её и берёт 0,9 под общий предел собственной
памяти, а 0,5 — под размеры кэшей и под порог, после которого промежуточные
данные запроса уходят на диск. Поэтому «поднять предел ничего не стоит» верно
для девяти сервисов, которые своей коробки не читают, и неверно для двух нод: от
её размера зависит, когда сервер начинает себя ограничивать. Снять лимит с нод
по той же причине нельзя — без коробки каждая нода считает свои доли от всей
машины, и память кончится у машины раньше, чем сервер решит экономить. Панель
«не упёрлись ли ноды в память» из ADR 0002 без коробки тоже не работает:
упираться становится не во что.
Сумма всех пределов после правки больше восьми гигабайт, и это не противоречие.
`mem_limit` — верхняя граница, а не резерв: Docker ничего не откладывает
заранее, и в покое стенд занимает около 3,2 ГБ. Восемь гигабайт нужны не сумме
пределов, а работе с запасом.
Остальные девять лимитов не меняются, потому что ни один из них ни разу не
сработал. Снять их скопом — то же изменение без свидетельств, каким они были
@@ -111,8 +124,8 @@ has limited RAM`; `cache_size_to_ram_max_ratio` = 0,5; праздный серв
`max_bytes_ratio_before_external_sort` = 0,5. Тяжёлый `GROUP BY` в коробке не
получает отказ, а уходит на диск и досчитывается; отказ по памяти остаётся для
того, что на диск не сбрасывается. Учебный сюжет «тяжёлый запрос — симптом на
графике памяти» из ADR 0002 выглядит полкой и дисковым вводом-выводом, а не
обрывом.
графике памяти» из ADR 0002 выглядит ровной линией у верхней границы и
дисковой нагрузкой, а не обрывом.
cgroup v2: `docker stats` показывает `memory.current` минус неактивные файловые
страницы. На праздном контейнере — 1056 МБ при 779 МБ файловых и 234 МБ
@@ -120,8 +133,8 @@ cgroup v2: `docker stats` показывает `memory.current` минус не
`apache/kafka:4.3.1` : `kafka-server-start.sh` при пустой `KAFKA_HEAP_OPTS`
ставит `-Xmx1G -Xms1G` , а по размеру коробки кучу не подбирает. Поэтому
переменную не убираем: без неё куча стала бы больше, а не меньше, и с нынешней
коробкой на гигабайт это был бы прямой OOM-kill .
переменную не убираем: без неё куча стала бы больше, а не меньше, и в нынешней
коробке Kafka на гигабайт ядро убивало бы контейнер за нехватку памяти .
На стенде с новой коробкой в 4 ГиБ то же поведение подтвердилось:
`max_server_memory_usage` = 3,60 ГиБ, в журнале ноды `Lowered mark cache size