Эффекты настройки 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 Мб swap-пространством. Это, похоже, достаточно для подавляющего большинства времени.

Установка overcommit_ratio на 80, вероятно, не является правильным действием. Установка значения ниже 100 почти всегда неверна.
(Существует некоторое недоразумение по поводу этого утверждения. Это утверждение касается рассматриваемого вопроса, где vm.overcommit_memory равен 2. Это утверждение не применяется к другим значениям)

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

Итак, в основном с переполнением на 100, ядро не позволит приложениям выделить больше памяти, чем у вас есть (swap + ОЗУ). Установка значения ниже 100 означает, что вы никогда не используете всю свою память. Если вы собираетесь установить эту настройку, вам следует установить ее выше 100 из-за ранее упомянутого сценария, который довольно распространен.
Однако хотя установка значения больше 100 почти всегда является правильным ответом, существуют некоторые случаи, когда установка его ниже 100 является правильной. Как упоминалось, таким образом вы не сможете использовать всю свою память. Однако ядро все равно может. Таким образом, вы можете эффективно использовать это, чтобы зарезервировать немного памяти для ядра (например, кэш страниц).

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

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

Раздел 9.6 “Переполнение и OOM” в документе, упомянутом @dunxd, особенно наглядно демонстрирует опасности, связанные с разрешением переполнения. Однако 80 также показалось мне интересным, поэтому я провел несколько тестов.

Что я обнаружил, так это то, что overcommit_ratio влияет на общую ОЗУ, доступную для ВСЕХ процессов. Процессы root, похоже, не обрабатываются иначе, чем обычные процессы пользователей.

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

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

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

Вот некоторые настройки overcommit_ratio и сколько ОЗУ моя программа-потребитель ОЗУ могла захватить (при этом каждый раз обращаясь к каждой странице) — в каждом случае программа корректно завершалась, как только 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-killer, происходят асинхронно, даже для программ, которые действительно ответственно управляют памятью. Лично я ненавижу глобальное переполнение в целом и OOM-killer в частности — это содействует легкомысленному подходу к управлению памятью, который заразен для библиотек и через них для каждого приложения, использующего их.

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

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 100

Ответ или решение

Влияние настройки vm.overcommit_memory на производительность вашего VPS

Когда ваш VPS, работающий на базе CentOS 5.4 с ядром Linux 2.6.16.33-xenU, неожиданно становится неотзывчивым из-за срабатывания OOM-убийцы (Out of Memory Killer), это может вызывать серьезные проблемы с доступностью ваших веб-ресурсов. Настройки параметров управления выделением памяти, такие как vm.overcommit_memory и vm.overcommit_ratio, могут оказать значительное влияние на производительность системы и управление памятью.

Что такое vm.overcommit_memory?

Параметр vm.overcommit_memory управляет поведением ядра Linux в отношении выделения памяти. Возможные значения этого параметра:

  1. 0 — Режим по умолчанию. Ядро использует эвристики для определения того, стоит ли позволять выделять память.
  2. 1 — Ядро всегда разрешает выделение памяти. Приложения могут запрашивать больше памяти, чем фактически доступно, что может привести к нехватке ресурсов.
  3. 2 — Ядро запрещает выделение памяти, если сумма используемой физической памяти и памяти подкачки превышает больше, чем указано в vm.overcommit_ratio.

Что такое vm.overcommit_ratio?

Параметр vm.overcommit_ratio работает в тандеме с vm.overcommit_memory, определяя максимально допустимое количество выделяемой памяти. При установке vm.overcommit_memory на 2 система будет выделять память только в объеме, равном swap + (physical_memory * vm.overcommit_ratio / 100).

Плюсы и минусы настройки единиц overcommit

Плюсы:

  1. Снижение риска OOM-убийцы: Настройка vm.overcommit_memory в значение 2 и vm.overcommit_ratio на 80% может уменьшить вероятность случайного срабатывания OOM-убийцы, так как процессам будет запрещено выделять больше памяти, чем вы определили.

  2. Предсказуемое поведение памяти: При фиксированном максимуме выделяемой памяти становится легче прогнозировать, сколько ресурсов будет доступно для приложений, что может улучшить стабильность.

  3. Запас памяти: Установка более низкого значения коэффициента может помочь зарезервировать память для системных процессов и кэша, тем самым поддерживая производительность.

Минусы:

  1. Ограничение на использование памяти: Установка vm.overcommit_ratio ниже 100% может привести к тому, что приложения не смогут использовать все доступные ресурсы, даже если в системе достаточно свободной памяти. Это может привести к пустым ошибкам выделения памяти (например, malloc).

  2. Недостаточная эффективность: Приложения, создающие множество мелких объектов (например, веб-серверы), могут не использовать выделение памяти эффективно. Это приведет к потенциальному недополноценному использованию ресурсов, даже если в системе достаточно физической памяти.

  3. Правильная настройка: Неправильные значения могут сделать систему более уязвимой к сбоям. К примеру, установка слишком низкого значения для vm.overcommit_ratio может вызывать завершение работы требовательных процессов, даже если в системе достаточно памяти.

Рекомендации

  1. Экспериментируйте с настройками: Настройте vm.overcommit_memory на 2 и vm.overcommit_ratio на 100%. Это позволит системе управлять памятью более эффективно, но без необоснованных ограничений.

  2. Мониторьте систему: Используйте команды, такие как watch -n 1 cat /proc/meminfo, чтобы наблюдать за использованием памяти. Убедитесь, что значения Committed_AS и CommitLimit соответствуют ожиданиям.

  3. Тестирование приложений: После внесения изменений в настройки, проведите тщательное тестирование нагрузки на сервер, чтобы оценить, как новые параметры влияют на производительность и стабильность.

  4. Документация и анализ: Поддерживайте актуальную документацию на основании тестирования и настройки. Анализируйте логи OOM-убийцы и другие системные журналы, чтобы лучше понять, когда и почему происходят сбои.

Заключение

Корректная настройка vm.overcommit_memory и vm.overcommit_ratio имеет значение для стабильности и производительности вашего веб-сервера. Установив эти параметры с умом, вы сможете значительно улучшить управление памятью на вашем VPS и свести к минимуму риск отключений из-за нехватки памяти. Помните, что каждая среда уникальна, и важно адаптировать настройки к конкретным потребностям ваших приложений и серверов.

Оцените материал
Добавить комментарий

Капча загружается...