- Каков самый быстрый способ восстановить контроль над системой Linux, которая перестала отвечать или стала очень вялой из-за чрезмерной подкачки?
Уже ответил выше с Alt-SysRq-F
- Существует ли эффективный способ предотвратить такой обмен в первую очередь, например, путем ограничения объема памяти, который процессу разрешено пытаться выделить?
Я отвечаю на эту 2-ю часть. Да, ulimit
все еще работает достаточно хорошо, чтобы ограничить один процесс. Вы можете:
- установить мягкий предел для процесса, который, как вы знаете, скорее всего выйдет из-под контроля
- установить жесткий лимит для всех процессов, если вы хотите дополнительную страховку
Также, как кратко сказано:
Вы можете использовать CGroups для ограничения использования ресурсов и предотвращения таких проблем
Действительно, cgroups предлагают более продвинутый контроль, но в настоящее время, по моему мнению, его сложнее настроить.
Старая школа ulimit
Один раз
Вот простой пример:
$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)
Это:
- Устанавливает мягкое ограничение общего использования памяти в 1 ГБ (ulimit предполагает ограничение в единицах кБ)
- Запускает рекурсивный вызов функции bash
r2(){ r2 $@$@;};r2 r2
, который экспоненциально жует ЦП и ОЗУ, бесконечно удваивая себя при запросе стековой памяти.
Как видите, он остановился при попытке запросить более 1 ГБ.
Обратите внимание, -v
работает с распределением виртуальной памяти (всего, то есть физического + подкачка).
Постоянная защита
Для того, чтобы ограничить виртуальное выделение памяти, as
эквивалент -v
для limits.conf
Я делаю следующее, чтобы защитить себя от любого неправильного поведения:
- Установите жесткое ограничение адресного пространства для всех процессов.
address space limit = <physical memory> - 256MB
.
- Поэтому ни один процесс с использованием жадной памяти или активной петли и утечки памяти не может потреблять ВСЕ физическую память.
- Запас 256 Мбайт для существенной обработки с помощью SSH или консоли.
Один лайнер:
$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"
Для проверки это приводит к следующему (например, в системе 16 ГБ):
$ cat /etc/security/limits.d/mem.conf
* hard as 16135196
$ ulimit -H -v
161351960
Заметки:
- Только смягчает против одного процесса, идущего за борт с использованием памяти.
- Не предотвратит многопроцессорную рабочую нагрузку с большой нагрузкой на память, вызывающей побои (тогда ответом будет cgroups).
- Не используйте опцию
rss
в limit.conf. Это не соблюдается новыми ядрами.
- Это консервативно.
- Теоретически, процесс может спекулятивно запрашивать много памяти, но только активно использовать подмножество (меньшее использование рабочего набора / резидентная память).
- Вышеуказанное жесткое ограничение приведет к тому, что такие процессы будут прерваны (даже если бы они могли нормально работать, учитывая, что Linux допускает перегрузку адресного пространства виртуальной памяти).
Более новые CGroups
Предлагает больше контроля, но в настоящее время более сложный в использовании:
- Улучшает предложение ulimit.
memory.max_usage_in_bytes
может учитывать и ограничивать физическую память отдельно.
- Принимая во внимание, что
ulimit -m
и / или rss
в limits.conf
должны предлагать аналогичную функциональность, но это не работает с ядра Linux 2.4.30!
- Необходимо включить некоторые флаги cgroup ядра в загрузчике:
cgroup_enable=memory swapaccount=1
.
- Это не произошло по умолчанию с Ubuntu 16.04.
- Вероятно, из-за некоторых последствий для производительности дополнительных накладных расходов.
- Материал cgroup / systemd является относительно новым и немного меняющимся, поэтому поток вверх по течению подразумевает, что производители дистрибутивов Linux еще не сделали его простым в использовании. Между 14.04LTS и 16.04LTS изменился инструментарий пользовательского пространства для использования cgroups.
cgm
теперь кажется официально поддерживаемым инструментом для пользователей.
- Похоже, что в системных файлах юнитов пока нет предопределенных значений по умолчанию "vendor / distro", чтобы расставить приоритеты для важных сервисов, таких как ssh.
Например, чтобы проверить текущие настройки:
$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...
Например, чтобы ограничить память одного процесса:
$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed
Чтобы увидеть это в действии, пережевывающее ОЗУ как фоновый процесс и затем убитое:
$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
0.0 0.0 2876
102 0.2 44056
103 0.5 85024
103 1.0 166944
...
98.9 5.6 920552
99.1 4.3 718196
[1]+ Killed bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'
Обратите внимание на экспоненциальный (степень 2) рост запросов памяти.
Будем надеяться, что в будущем «дистрибутив / вендоры» предварительно сконфигурируют приоритеты и ограничения cgroup (через модули systemd) для таких важных вещей, как SSH и графический стек, чтобы они никогда не испытывали недостатка памяти.