Я хотел бы иметь одну строку оболочки / bash, которая выполняет что-то в этом роде:
test "`free | grep | awk | whatever` -gt 80" && any_command
Где общий процент барана используется всей системой, сравнивается с жестко запрограммированным числом (80 в моем случае). test
не имеет значения, пока any_command
выполняется, если RAM больше заданного процента.
Есть ответы о том, как это проблема, для решения которой созданы подобные monit / bluepill / god. Я согласен на 100%, и вам, скорее всего, следует следовать советам в этих ответах. Однако этот вопрос касается именно той линии, которую я описал, по каким бы то ни было причинам, с учетом всех возможных предостережений и проблем.
Не изобретайте велосипед :)
В Утилита Monit специально создан для работы в подобных ситуациях. Это хорошо задокументированы и имеет много примеры здесь на ServerFault.
check system kale.GreenLeaf.com
if loadavg (5min) > 16 for 15 cycles then alert
if memory usage > 92% then alert
if swap usage > 10% then alert
или для процесса:
check process cups
with pidfile "/var/run/cupsd.pid"
start program = "/sbin/service cups start"
stop program = "/sbin/service cups stop"
if 10 restarts within 11 cycles then timeout
if total memory > 1000.0 MB for 5 cycles then alert
if total memory > 2000.0 MB for 5 cycles then restart
if cpu usage > 95% for 11 cycles then restart
Вместо предупреждения или действия запуска / остановки / перезапуска вы можете настроить EXEC:
EXEC можно использовать для выполнения произвольной программы и отправки предупреждения. Если вы выбираете это действие, вы должны указать программу, которая будет выполняться, и если программе требуются аргументы, вы должны заключить программу и ее аргументы в строку в кавычки. При желании вы можете указать uid и gid, на которые исполняемая программа должна переключаться при запуске ...
if total memory > 2000.0 MB for 5 cycles then exec "/sbin/service sidekiq restart"
Как насчет:
[ $(free -m| grep Mem | awk '{ print int($3/$2*100) }') -gt "80" ] && echo "greater " || echo "lesser"
А для процесса потребления вот возможная часть решения:
for p in $(pgrep bash); do total=$(($total + $(awk '/VmSize/ { print $2 }' /proc/$p/status))); done ; echo "Total memory usage: $total kb" ; unset total
Объединение их обоих предоставляется читателю в качестве упражнения.
Чего именно вы пытаетесь достичь? Вы, вероятно, пытаетесь сделать это НЕПРАВИЛЬНО.
[ $(free | perl -nE 'if (/Mem/) { (undef,$total,$used) = split; say int(100*$used/$total) }') -gt 80 ] && echo foo
Но обратите внимание, что все, что вы пытаетесь достичь с помощью этого, почти наверняка бесполезен (и, наверное, даже вредно). Не существует такого понятия, как «процент использования ОЗУ». Да, free
покажет вам, сколько памяти «свободно», но это, вероятно, не означает то, что вы думаете (это поле лучше было бы назвать «потрачено впустую» или «количество памяти, которое вам никогда не следовало покупать»).
Например, ядро не «загружает» программы в память, оно отображает их, так что некоторая примерная программа размером в сотни МБ сможет работать независимо от размера всего 12 КБ. Также все файлы, к которым осуществляется доступ, будут кэшироваться в той же памяти (называемой кешем страниц) - нет никакой разницы между программой, которая выполнялась в прошлом (поэтому ее файлы кэшируются, если она запускается снова), или файлами данных, которые были прочитаны / записаны в прошлое (поэтому, если к ним снова обращаются, они будут быстрее)
Итак, если у вас больше диска, чем памяти (довольно обычный случай), ваша «свободная» (также известная как «потраченная впустую») память будет быстро после загрузки сойтись почти на 100% (на самом деле больше похоже на 80-95%, поскольку ядро будет пытаться сохранить некоторые из них бесплатны, поэтому он может быстро получить к нему доступ при нехватке памяти). Это нормально и на самом деле желательно, так как это значительно ускорит ваш доступ к диску (в лучшем случае) или будет равноценно «свободной памяти», если ничто не обратится к тем же файлам снова (в худшем случае).
Итак, вы действительно хотите избегать наличие «свободной» памяти (что случается время от времени после смерти программ, интенсивно использующих память).
Edit1: Кроме того, приведенный выше результат представляет собой только возможные (и совершенно разные) ответы, так как такой вопрос не определен. Например, вместо «Mem used» вы могли бы использовать «Mem used-cached» (который покажет, сколько памяти используется при вычитании дискового кеша), что может дать вам такие результаты, как «15% использовано вместо «Использовано на 80%») и может быть более точным - в зависимости от того, что именно вы пытаетесь выполнить.
Что касается использования памяти процессом, то же самое - существует слишком много способов сказать, сколько памяти использует процесс. Сумма, требуемая для программы (VSZ в ps
вывод). Или текущий объем оперативной памяти (столбец RSS). А как насчет того, когда есть несколько экземпляров с общим кодом (например, если у вас есть 100 процессов apache по 50 МБ RSS каждый, они НЕ используют 100 * 50 = 5000 МБ ОЗУ, а больше всего примерно 200 МБ) и т. Д., Когда вы точно знаете, что вы хотите, только тогда вы можете приступить к его вычислению (просто VSZ, или просто RSS, или RSS-shared, или RSS-shared / num-of-processses-sharing и т. д.)
Также обратите внимание, что этот тип вопросов больше по теме superuser.com
Edit2: Что касается вашего комментария, вы пытаетесь избежать утечки памяти - это какой-то процесс. Проверять наличие свободной памяти здесь однозначно нельзя, так как это даст ложные срабатывания. Вы должны ограничить свой процесс, чтобы утечки памяти не привели к остановке остальной системы (см. help ulimit
в баше). Процесс может справиться с этим (хорошо) или умереть, когда он не может получить требуемый объем памяти, поэтому вы можете перезапустить его (с помощью monit, supervise, runit или аналогичного)
Edit3: в дополнение (или как альтернатива, но лучше в дополнение) к установке ограничений процесса, вы можете использовать что-то вроде этого, чтобы перезапустить процесс, когда RSS становится слишком большим.
[ $(awk '/^VmRSS/ { print $2}' /proc/$PID/status) -gt 200 ] && echo killmeplease
вместо того $PID
вы бы, конечно, использовали свой PID (например, из PID=$(cat /var/run/something.pid)
или PID=$(pidof somedaemon)
и т.п.
Однако обратите внимание, что вам, вероятно, лучше использовать VmSize
(или VmPeak
) вместо того (VmRSS
), так как в противном случае ваш процесс все равно может вывести систему из строя, если он попадет в своп (поэтому VmSize будет большим, а VmRSS маленьким)