Назад | Перейти на главную страницу

Однострочный сценарий для проверки и реакции на использование памяти

Я хотел бы иметь одну строку оболочки / 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 маленьким)