Однажды одно криво написанное java-приложение серьёзно поднапрягло сервер - почти на любую команду в консоли вылазила такая вот ошибка:
"bash: fork: Resource temporarily unavailable"
Конечно, первым желанием было запустить top или ps чтобы вычислить и пристрелить зажравшийся процесс, но, вот незадача, консоль всё тупо продолжала гнуть свою линию в виде "bash: fork: Resource temporarily unavailable" на все мои попытки запустить какую-либо внешнюю (не из списка bash builtins) команду... Я сразу заподозрил, что зажравшимся процессом, скорей всего, является java. Но вот как прибить оный, не зная его PID-а? И тут я вспомнил, про файловую систему /proc... Затем после пары минут экспериментов родился такой вот скрипт, который успешно позволил решить мне задачу нахождения PID-а процесса java, используя только встроенные в коммандный интерпретатор (bash) команды:
#!/bin/bash
for p in /proc/[0-9]* ; do
exec 9< $p/cmdline
read -u 9 line
[[ $line =~ java ]] && echo "|$p|: |$line|"
exec 9<&-
done
В строке 3 мы назначаем файловому дескриптору 9 псевдо-файл /proc/<pid>/cmdline, далее читаем из него в переменную line, потом сравниваем эту переменную со строкой "java" и в случае совпадения выводим имя файла, имя которого соответствует PID-у процесса. В строке 6 освобождаем файловый дескриптор 9. Затем оставалось только набрать команду kill с найденным таким образом вожделенным PID-ом (к счастью, kill является встроенной в bash). И, о чудо, консоль снова стала себя адекватно вести, LA упало, память освободилась. Уже потом, по графикам cacti стало понятно, что причиной такого безобразия стало неимоверно большое количество потоков (около 70000), которое успело наплодить вышеупомянутое криво написанное java-приложение.
А вот если бы мне не удалось прибить процесс, тогда, пожалуй, пришлось бы сервер перезагружать. Поскольку стоит он далеко, за морями-океанами, то нажать кнопочку reset на корпусе тут не получилось бы. Тогда бы я просто набрал в консоли
echo s > /proc/sysrq-trigger
echo u > /proc/sysrq-trigger
echo b > /proc/sysrq-trigger
Что привело бы к сбросу дисковых буферов (строка 1), перемонтированию файловых систем в режим read-only (строка 2) и немедленной перезагрузке (строка 3). Если же к консоли всё таки имеется непосредственный доступ (физически или через IP-KVM), то следует предусмотрительно в /etc/sysctl.conf добавить строчку
kernel.sysrq = 1
Тогда будет работать волшебная комбинация клавиш AltGr+PrtScr+<command>, где <command> - однобуквенная команда, посылаемая ядру. Список всех поддерживаемых команд с их очень кратким описанием можно получить на консоли (и в /var/log/messages) если нажать комбинацию AltGr+PrtScr+h или выполнить команду:
echo h > /proc/sysrq-trigger
Полный список магических буковок можно найти тут.
Так тоже работает. Не нужно открывать другие дескрипторы.
for p in /proc/[0-9]* ; do
read line < $p/cmdline
[[ $line =~ chrome ]] && echo "|$p|: |$line|"
done
Гм, действительно. Так как-то изящнее и проще для понимания выходит.
Тут раньше первыми двумя командами было "echo e > /proc/sysrq-trigger" и "echo i > /proc/sysrq-trigger". Но как показала практика, это была плохая идея :) Ибо после выполнения команды "e", запущенной в ssh-сессии, прибиваются все процессы, включая ssh-демон :) И дальше уже ничего сделать нельзя, кроме как перегрузить сервер по питанию.
Можно написать echo $(( 2+4+8+16+32+128 )) > /proc/sys/kernel/sysrq , тем самым отключить возможность посылать сигналы процессам средствами sysrq. Удобно в том случае если не планируется иметь консольное подключение к серверу.