Назад | Перейти на главную страницу

Эффекты настройки vm.overcommit_memory

Мой веб-сервер VPS, работающий на CentOS 5.4 (ядро Linux 2.6.16.33-xenU) нерегулярно (например, раз в месяц плюс-минус несколько недель), перестает отвечать из-за срабатывания oom-killer. Мониторинг сервера показывает, что это не так обычно заканчивается память, но очень часто.

Я прочитал пару блогов, которые указывают на эта страница в котором обсуждается настройка ядра для лучшего управления избыточной фиксацией с использованием следующих параметров sysctl:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

Я понимаю это (что может быть неверным, но я не могу найти канонического определения, чтобы прояснить), что это предотвращает чрезмерное выделение памяти ядром сверх swap + 80% физической памяти.

Однако я также прочитал некоторые другие источники предполагают, что эти настройки не являются хорошей идеей - хотя критики этого подхода, похоже, говорят: «Не делайте ничего, чтобы сломать вашу систему, вместо того, чтобы пытаться использовать этот кладж» в предположении, что причинно-следственная связь всегда известна.

Итак, мой вопрос: каковы плюсы и минусы такого подхода, в контексте веб-сервера Apache2, на котором размещено около 10 сайтов с низким трафиком? В моем конкретном случае у веб-сервера 512 МБ ОЗУ и 1024 МБ пространства подкачки. Кажется, этого достаточно в большинстве случаев.

Настройка overcommit_ratio до 80, скорее всего, не правильное действие. Установка значения меньше 100 почти всегда неверна.

Причина этого в том, что приложения Linux выделяют больше, чем им действительно нужно. Скажем, они выделяют 8 Кбайт для хранения пары символов текста. Ну вот и несколько килобайт не используются. Приложения делают это часто, и именно для этого и разработан overcommit.

Таким образом, в основном с overcommit на 100 ядро ​​не позволяет приложениям выделять больше памяти, чем у вас (swap + ram). Установка менее 100 означает, что вы никогда не будете использовать всю свою память. Если вы собираетесь установить этот параметр, вы должны установить его выше 100 из-за вышеупомянутого сценария, который довольно распространен.

Теперь, что касается вашей проблемы с запуском убийцы OOM, ручная установка overcommit вряд ли решит это. Настройка по умолчанию (эвристическое определение) довольно разумна.

Если вы хотите узнать, действительно ли это причина проблемы, посмотрите /proc/meminfo когда запускается убийца OOM. Если вы видите это Committed_AS близко к CommitLimit, но free по-прежнему показывает доступную свободную память, тогда да, вы можете вручную отрегулировать превышение лимита для вашего сценария. Установка слишком низкого значения приведет к тому, что OOM killer начнет убивать приложения, когда у вас еще достаточно свободной памяти. Установка слишком большого значения может привести к тому, что случайные приложения умирают, когда они пытаются использовать выделенную им память, которая фактически недоступна (когда вся память фактически израсходована).

Раздел 9.6 «Overcommit and OOM» в документе, который упоминает @dunxd, особенно хорошо показывает опасности, связанные с разрешением overcommit. Однако 80 Мне тоже это показалось интересным, поэтому я провел несколько тестов.

Я обнаружил, что overcommit_ratio влияет на общий объем оперативной памяти, доступной ВСЕМ процессам. Похоже, что корневые процессы не обрабатываются иначе, чем обычные пользовательские процессы.

Установка соотношения на 100 или меньше должны обеспечивать классическую семантику, когда возвращаемые значения из malloc/sbrk надежны. Установка коэффициентов ниже, чем 100 может быть способом зарезервировать больше оперативной памяти для непроцессных действий, таких как кеширование и т. д.

Итак, на моем компьютере с 24 ГиБ ОЗУ, с отключенной подкачкой, используется 9 ГиБ, с top показывая

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

Вот некоторые overcommit_ratio настройки и сколько ОЗУ могла захватить моя программа-потребитель RAM (касаясь каждой страницы) - в каждом случае программа завершалась чисто один раз malloc не смогли.

 50    ~680 MiB
 60   ~2900 MiB
 70   ~5200 MiB
100  ~12000 MiB

Запуск нескольких одновременно, даже если некоторые из них были пользователем root, не изменил общую сумму, которую они потребляли вместе. Интересно, что он не смог использовать последние 3+ ГиБ или около того; то free не сильно упала ниже того, что показано здесь:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

Эксперименты были запутанными - все, что использует malloc в тот момент, когда используется вся оперативная память, имеет тенденцию к сбою, так как многие программисты ужасно относятся к проверке сбоев malloc в C, некоторые популярные библиотеки коллекций полностью игнорируют это, а C ++ и другие языки даже хуже.

Большинство ранних реализаций воображаемой ОЗУ, которые я видел, были предназначены для очень специфического случая, когда один большой процесс - скажем, 51% + доступной памяти - нуждался в fork() чтобы exec() какая-то программа поддержки, обычно гораздо меньшая. Операционные системы с семантикой копирования при записи позволят fork(), но с оговоркой, что если бы разветвленный процесс на самом деле попытался изменить слишком много страниц памяти (каждая из которых затем должна была бы быть создана как новая страница, независимая от начального огромного процесса), он в конечном итоге погибнет. Родительский процесс находился в опасности только в том случае, если выделял больше памяти, и мог справиться с нехваткой памяти, в некоторых случаях просто подождав, пока какой-нибудь другой процесс умрет, а затем продолжил. Дочерний процесс обычно просто заменяется программой (обычно меньшей) через exec() и тогда был освобожден от оговорки.

Концепция чрезмерной нагрузки в Linux - это крайний подход к разрешению как fork() происходить, а также допускать массовое превышение доступности отдельных процессов. Смерти, вызванные OOM-убийцами, происходят асинхронно даже для программ, которые делать ответственно относитесь к распределению памяти. Я лично ненавижу общесистемный overcommit в целом и oom-killer в частности - он поощряет наплевательский подход к управлению памятью, который заражает библиотеки и через них все приложения, которые их используют.

Я бы предложил установить коэффициент равным 100, а также иметь раздел подкачки, который, как правило, будет использоваться только огромными процессами, которые часто используют только крошечную часть своей части, которая помещается в подкачку, и, следовательно, защитить подавляющее большинство процессов от некорректных функций убийцы OOM. Это должно защитить ваш веб-сервер от случайной смерти, и если он был написан для обработки malloc ответственно, даже не убивая себя (но не ставьте на последнее).

Это означает, что я использую это в /etc/sysctl.d/10-no-overcommit.conf

vm.overcommit_memory = 2
vm.overcommit_ratio = 100