Точно - никак. Сама постановка задачи несколько странная.
Во-первых, OOM killer настраивается, и далеко не всегда его поведение имеет отношение к абстрактному "сколько памяти свободно". В некоторых режимах оверкоммита первостепенное значение начинает иметь аппроксимация первой или второй производной роста потребления у конкретного процесса и его могут прибить превентивно, иногда сильно далеко от конкретных лимитов потребления памяти.
Во-вторых, даже если таки как-то уговорить OOM killer погодить (в частном случае - отключив его или сильно закрутив лимиты) и выжрать памяти впритык - такая система внезапно становится сильно менее работоспособной, чем обычно, вплоть до "совсем неработоспособной". Особенно если в ней больше, чем один процесс.
Вопрос чисто теоретический или все-таки практический? На практике - подавляющее большинство живет примерной оценкой через чтение /proc/meminfo или /proc/vmstat и отнимания от них взятых с потолка 7-10-15%. Или все-таки это какая-то специфическая задача?
Итак, речь про обычный (дефолтный) режим №1. Меня интересует ситуация, когда free говорит, что памяти свободной много (допустим, free 300Mb, cached 3Gb, buffers 300Mb, в свопе +2Гб свободно), приложение пишет в 400Мб блок уже аллоцированной памяти, тут прилетает OOM и бьёт всех по рукам.
Экспериментально-эвристически было обнаружено, что дельта явно связана с объёмом записанного на tmpfs, но там ещё что-то есть.
.... А для мониторинга проблема, что "взятые с потолка 15%" ничего не гарантируют.
Ну, вообще почти везде дефолтный - как раз vm.overcommit_memory = 0, а не 1 - и там как раз эта эвристика, первая-вторая производная и все такое в полный рост
( ... )
Я попутал. Чтобы числа не писать, давай говорить guess, never, always. Дефолтный режим guess, именно его я и отлаживаю. При режиме never оно не работоспособно - приложения слишком много virt берут.
NUMA исключаем, у нас interleave.
За shmem спасибо.
У меня задача не приложение отлаживать, а понять, когда на сервере OOM придёт, чтобы мониторинг настроить. Обычными методами он промахивается и срабатывает либо сильно заранее, либо не предупреждает о предстоящем OOM'е.
Скорее так: Committed_AS меньше, чем CommitLimit. При этом vm.overcommit_memory должно быть равно 2, чтобы убрать эвристику. В этом случае OOM-killer не будет вызываться вообще, так как для памяти всегда будут назначены virtual pages.
Если же CommitLimit превышен, то OOM-killer может быть вызван даже если память уже не выделять - достаточно будет приложениям начать работать со всей памятью, которую они уже себе выделили.
Эту часть я читал. Но CommitLimit обычно больше объёма оперативной памяти.
Проблема в том, что tmpfs'ные данные засчитываются в buffered (или cached?), но вытеснены не могут быть, из-за этого все эвристики думают, что памяти дофига, а происходит OOM из-за того, что COW'у во время PF не найти свободной страницы.
CommitLimit - это swap + какая-то часть RAM. Поэтому он может быть больше RAM, например, если swap большой.
tmpfs выделяет себе память когда ей они понадобились, не резервируя. Поэтому Committed_AS про эту память ничего не знает. Плюс ещё inodes надо хранить - они тоже динамически выделяются.
В твоём случае, получается, что "гарантированная свободная память" - это CommitLimit минус Committed_AS, и минус "сколько ещё может себе забрать tmpfs", и минус "сколько ещё может себе забрать другие части ядра".
Пока что по моим наблюдениям про tmpfs как раз Committed_AS знает, а все остальные нет.
Это если локально.
А если глобально, я понял, что в линуксах никто не знает, сколько памяти свободной, кроме MemFree. Всё остальное спекуляции и гадание на ядерной гуще.
... Да и MemFree не знает. Сколько раз я уже наблюдал, как в экстремальных тестах при 8 свободных мегабайтах, программу, попросившую 4, сносили с треском.
(лирическое отступление) я тут слышал от чувака, пишущего патчи в mm-подсистему ядра высказывание вида "memory mgmt in linux is a pile of crap mixed with legacy crap".
не применим ли в твоей ситуации workaround вида сказать oom-killer-у чтоб "вот этот процесс по oom не убивать ваще, даже если ядро придётся в своп вытеснить"?
Comments 25
Во-первых, OOM killer настраивается, и далеко не всегда его поведение имеет отношение к абстрактному "сколько памяти свободно". В некоторых режимах оверкоммита первостепенное значение начинает иметь аппроксимация первой или второй производной роста потребления у конкретного процесса и его могут прибить превентивно, иногда сильно далеко от конкретных лимитов потребления памяти.
Во-вторых, даже если таки как-то уговорить OOM killer погодить (в частном случае - отключив его или сильно закрутив лимиты) и выжрать памяти впритык - такая система внезапно становится сильно менее работоспособной, чем обычно, вплоть до "совсем неработоспособной". Особенно если в ней больше, чем один процесс.
Вопрос чисто теоретический или все-таки практический? На практике - подавляющее большинство живет примерной оценкой через чтение /proc/meminfo или /proc/vmstat и отнимания от них взятых с потолка 7-10-15%. Или все-таки это какая-то специфическая задача?
Reply
Итак, речь про обычный (дефолтный) режим №1. Меня интересует ситуация, когда free говорит, что памяти свободной много (допустим, free 300Mb, cached 3Gb, buffers 300Mb, в свопе +2Гб свободно), приложение пишет в 400Мб блок уже аллоцированной памяти, тут прилетает OOM и бьёт всех по рукам.
Экспериментально-эвристически было обнаружено, что дельта явно связана с объёмом записанного на tmpfs, но там ещё что-то есть.
.... А для мониторинга проблема, что "взятые с потолка 15%" ничего не гарантируют.
Reply
Reply
NUMA исключаем, у нас interleave.
За shmem спасибо.
У меня задача не приложение отлаживать, а понять, когда на сервере OOM придёт, чтобы мониторинг настроить. Обычными методами он промахивается и срабатывает либо сильно заранее, либо не предупреждает о предстоящем OOM'е.
Reply
https://gist.github.com/dobrokot/3321085c1b1daa901894
Reply
Reply
Если же CommitLimit превышен, то OOM-killer может быть вызван даже если память уже не выделять - достаточно будет приложениям начать работать со всей памятью, которую они уже себе выделили.
Reply
Проблема в том, что tmpfs'ные данные засчитываются в buffered (или cached?), но вытеснены не могут быть, из-за этого все эвристики думают, что памяти дофига, а происходит OOM из-за того, что COW'у во время PF не найти свободной страницы.
Reply
tmpfs выделяет себе память когда ей они понадобились, не резервируя. Поэтому Committed_AS про эту память ничего не знает. Плюс ещё inodes надо хранить - они тоже динамически выделяются.
В твоём случае, получается, что "гарантированная свободная память" - это CommitLimit минус Committed_AS, и минус "сколько ещё может себе забрать tmpfs", и минус "сколько ещё может себе забрать другие части ядра".
Reply
Это если локально.
А если глобально, я понял, что в линуксах никто не знает, сколько памяти свободной, кроме MemFree. Всё остальное спекуляции и гадание на ядерной гуще.
... Да и MemFree не знает. Сколько раз я уже наблюдал, как в экстремальных тестах при 8 свободных мегабайтах, программу, попросившую 4, сносили с треском.
Reply
не применим ли в твоей ситуации workaround вида сказать oom-killer-у чтоб "вот этот процесс по oom не убивать ваще, даже если ядро придётся в своп вытеснить"?
Reply
Reply
Reply
Leave a comment