Repository navigation
perf(image): cap the panel's Node young generation at 16 MB semi-spaces - #122
Merged
Merged
Conversation
Что: - В образе панели `ENV NODE_OPTIONS=--max-semi-space-size=16`. Полупространство молодого поколения кучи V8 ограничено 16 МБ, молодое поколение под нагрузкой растёт до 32 МБ вместо ~60. Зачем: - Node 26 выбирает размер молодого поколения по RAM хоста. На сервере с 4 ГБ оно под нагрузкой растёт до ~60 МБ, а короткоживущий мусор запросов панели помещается в меньший объём. - На изолированном стенде пик памяти сервера панели под нагрузкой ниже на 19–22 МБ (около 4%), скорость и процессорное время не изменились. Риски: - Сборки молодого поколения идут чаще; на стенде это не видно ни по процессорному времени, ни по скорости. В простое V8 и без флага сжимает молодое поколение, поэтому память в простое не меняется. - `NODE_OPTIONS`, заданный у сервиса, заменяет значение из образа. Проверки: - Команды и результаты: на сервере с 4 ГБ `node -e` в контейнере панели: молодое поколение без флага 59 МБ, с `--max-semi-space-size=16` 32 МБ. Стенд: нативный arm64-образ `AgentHits-Dev` в Docker-in-Docker с `NODE_OPTIONS` и без него, лимит памяти сервиса 3915 МБ как на сервере; три прохода сценария по 3 прогона и отдельная проверка скорости из 4 пар прогонов вперемешку. - Ограничения: стенд на Mac, а не на сервере; образ этой ветки целиком не собирался, флаг проверен переменной окружения на образе базовой ветки. What: - The panel image sets `ENV NODE_OPTIONS=--max-semi-space-size=16`. The V8 young-generation semi-space is capped at 16 MB, so under load the young generation grows to 32 MB instead of ~60. Why: - Node 26 sizes the young generation from the host's RAM. On a 4 GB server it grows to ~60 MB under load, while the panel's short-lived request garbage fits in less. - On the isolated bench, the panel server's peak memory under load is 19–22 MB lower (about 4%), with unchanged speed and CPU time. Risks: - Young-generation collections run more often; the bench shows no difference in CPU time or speed. When idle, V8 shrinks the young generation even without the flag, so idle memory does not change. - A `NODE_OPTIONS` set on the service replaces the image value. Checks: - Commands and results: on a 4 GB server, `node -e` in the panel container: young generation 59 MB without the flag, 32 MB with `--max-semi-space-size=16`. Bench: a native arm64 `AgentHits-Dev` image in Docker-in-Docker with and without `NODE_OPTIONS`, service memory limit 3915 MB as on the server; three scenario passes of 3 runs and a separate speed check of 4 interleaved run pairs. - Limitations: the bench runs on a Mac, not the server; the image of this branch was not built as a whole, the flag was checked through the environment variable on the base branch image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Зачем
Node 26 выбирает размер молодого поколения кучи V8 по RAM хоста. На сервере с 4 ГБ полупространство получается 32 МБ, и под нагрузкой молодое поколение растёт до ~60 МБ. Короткоживущий мусор запросов панели помещается в меньший объём, а лишнее молодое поколение — это просто память сверху на каждом пике нагрузки.
Замер на рабочей панели (
node -eв контейнере, тот же Node и те же 4 ГБ): молодое поколение без флага 59 МБ, с--max-semi-space-size=1632 МБ.Что изменилось
Dockerfile, финальный этап:ENV NODE_OPTIONS=--max-semi-space-size=16.NODE_OPTIONS, заданный у сервиса, заменяет значение из образа. В простое V8 и без флага сжимает молодое поколение до 1–2 МБ, поэтому флаг срезает только пики.Проверки
AgentHits-Dev. Сервис панели ограничен 3915 МБ, как RAM рабочего сервера: от этого Node берёт размер кучи (2054 МиБ) и молодого поколения.NODE_OPTIONSна том же образе: в Dockerfile ставится та же переменная. Образ этой ветки целиком на стенде не собирался; CI собирает его вmain-image-smoke.Скорость в этих прогонах гуляла на ±20%, поэтому её проверили отдельно: 4 пары коротких прогонов вперемешку, средние по второму и третьему повтору сценария.
Скорость с флагом не ниже; разница в её пользу меньше разброса между прогонами, поэтому выигрышем её не считаем. Пик памяти ниже в каждом прогоне: с флагом 496–500 МиБ, без флага 503–526 МиБ.
Сценарий: вход; пять страниц панели; 10 запросов
project.allподряд; 1000 запросов к API по 10 одновременно и 200 к странице проектов по 5; проект; деплой Compose со сборкой и живым логом; логи и терминал контейнера; деплой из образа; добавление сервера и SSH-терминал.Что проверить вручную на dev
node -p process.env.NODE_OPTIONSв контейнере панели показывает--max-semi-space-size=16, панель открывается, деплой проходит.🤖 Generated with Claude Code