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

41

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

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

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

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

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

dunxd
источник

Ответы:

32

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

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

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

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

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

Патрик
источник
1
Спасибо - я пытаюсь что-то с overcommit_ratio, установленным на 100, посмотреть, что получится. Основная проблема у меня заключается в том, что при запуске oom-killer он неизменно убивает sshd, мешая мне получить доступ к серверу и посмотреть, что происходит. Я думаю, что мне действительно нужно, чтобы остановить запуск oom-killer и некоторые средства записи того, что произойдет, когда он запустится, чтобы я мог найти причину проблемы.
Данксд
4
@dunxd вы можете использовать /proc/<PID>/oom_score_adjдля этой цели. Например, если вы установите для oom_score_adj значение -1000 для sshd, oom killer никогда не нацелится на sshd, когда захочет что-то убить. Полное прекращение работы oom killer не является хорошей идеей, так как тогда ваши программы не смогут распределить память, и они все равно умрут.
Патрик
4
@dunxd наследуется. ваш скрипт инициализации устанавливает его на себя, и все, что запускается скриптом инициализации, наследует его.
Патрик
4
Ваш пример 4 КБ неверен. Виртуальная память используется со страницами, и (наименьший) размер страницы в Linux составляет 4 КБ. Это означает, что для хранения пары символов требуется 4 КБ для сопоставления где-либо независимо от настроек чрезмерной передачи. Подходящим примером использования памяти по выделению будет, например, выделение 10 КБ и использование только первых 4100 байтов. Это означает, что две страницы по 4 КБ должны хранить данные, а одна дополнительная страница не используется. У систем без избыточной загрузки всегда будет третья страница, готовая для хранения данных в случае поступления запроса, поскольку системы с обязательной передачей данных не будут применять это.
июля
2
/ proc / self указывает на текущий процесс, поэтому / proc / self / oom_score_adj может использоваться для изменения oom_score_adj текущего процесса.
r_2
23

Раздел 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настройки и объем оперативной памяти, которую могла бы получить моя программа-потребитель (касаясь каждой страницы) - в каждом случае программа выходила чисто после 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() и был тогда свободен от оговорки.

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

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

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

vm.overcommit_memory = 2
vm.overcommit_ratio = 100
Алекс Норт-Киз
источник
И вы бы порекомендовали оставить vm.overcommit_memory равным 2?
UT xD
1
Хорошая заметка - это действительно то, что я использую; Я думаю, что пропустил это в своем ответе, потому что это уже в вопросе
Алекс Норт-Киз