Script Bash que mata automáticamente los procesos cuando el uso de CPU / memoria es demasiado alto

11

He creado un script que mata los procesos si el uso de CPU y / o memoria alcanza el 80%. Crea una lista de procesos eliminados cuando esto sucede. ¿Qué puedo hacer para mejorarlo?

while [ 1 ];
do 
echo
echo checking for run-away process ...

CPU_USAGE=$(uptime | cut -d"," -f4 | cut -d":" -f2 | cut -d" " -f2 | sed -e "s/\.//g")
CPU_USAGE_THRESHOLD=800
PROCESS=$(ps aux r)
TOPPROCESS=$(ps -eo pid -eo pcpu -eo command | sort -k 2 -r | grep -v PID | head -n 1)

if [ $CPU_USAGE -gt $CPU_USAGE_THRESHOLD] ; then
  kill -9 $(ps -eo pid | sort -k 1 -r | grep -v PID | head -n 1) #original
  kill -9 $(ps -eo pcpu | sort -k 1 -r | grep -v %CPU | head -n 1)
  kill -9 $TOPPROCESS
  echo system overloading!
  echo Top-most process killed $TOPPROCESS
      echo CPU USAGE is at $CPU_LOAD

else
    fi
    exit 0
    sleep 1;
    done
Ketan Patel
fuente
3
¿Has intentado ejecutar el script? while [ 1 ]me hace preguntarme cuánto CPU consumirá este script solo. Además, ¿3 llamadas a kill -9un script que se ejecuta constantemente? Esto me da escalofríos ...
rahmu
1
Buen avatar de todos modos, @rahmu se puso sleep 1al día
daisy
1
El primer lunes del mes y mi PC está comprobando un conjunto RAID6 (lento). La carga de la CPU llega fácilmente a picos por encima de 8 porque constantemente está esperando el disco IO de este conjunto RAID. No hay nada malo, el sistema sigue siendo muy receptivo. Su secuencia de comandos mataría a mi firefox que usa solo el 3.6% del 400% disponible. Solo digo que puedes estar buscando fantasmas con este script. Por cierto: su sistema no se dañará debido a la alta carga y cuando se agote la memoria, el kernel hará una suposición semi educada sobre qué proceso (s) matar.
jippie
¿Entonces el proceso de matar en una carga basada estará bien o no?
Ketan Patel
En mi caso de uso, el asesinato no es deseado.
jippie

Respuestas:

11

Estoy adivinando el problema que desea resolver es que tiene algún tipo de proceso que se ejecuta en su caja, que a veces se porta mal, y se sienta siempre un núcleo de vinculación.

Lo primero que debes hacer es intentar arreglar el programa que se vuelve loco. Esa es, con mucho, la mejor solución. Voy a suponer que eso no es posible, o necesita un rápido Kluge para mantener su caja funcionando hasta que se solucione.

Usted, como mínimo, desea limitar su secuencia de comandos para que solo llegue al único programa que le preocupa. Sería mejor si los permisos limitaran su script de esta manera (por ejemplo, su script se ejecuta como usuario X, lo único que se ejecuta como X es el programa).

Aún mejor sería usar algo como ulimit -tlimitar la cantidad de tiempo total de CPU que el programa puede usar. Del mismo modo, si consume toda la memoria, verifique ulimit -v. El núcleo impone estos límites; vea la página de bashmanual (es un shell incorporado) y la página de setrlimit(2)manual para más detalles.

Si el problema no es un proceso que se está volviendo loco, sino que se están ejecutando demasiados procesos, entonces implemente alguna forma de bloqueo para evitar que se ejecute más de X (o, esto debería estar familiarizándose ulimit -u). También puede considerar cambiar la prioridad del planificador de esos procesos (usando niceo renice), o incluso más drástico, usando sched_setschedulerpara cambiar la política SCHED_IDLE.

Si necesita aún más control, eche un vistazo a los grupos de control (cgroups). Dependiendo del núcleo que esté ejecutando, en realidad puede limitar la cantidad de tiempo de CPU, memoria, E / S, etc., que consume un grupo completo de procesos. Los grupos de control son bastante flexibles; probablemente puedan hacer lo que sea que intentes hacer, sin ningún tipo de fragilidad. Arch Linux Wiki tiene una introducción a cgroups que vale la pena leer, al igual que la serie cgroups de Neil Brown en LWN.

derobert
fuente
3

Cuestiones:

  • Al ordenar los campos numéricos es probable que desee utilizar la -nopción: sort -nrk 2. De lo contrario, una línea con un %CPUvalor de 5.0 terminará más alta que una con un valor de 12.0.
  • Dependiendo de su psimplementación, es posible que desee utilizar la --no-headersopción para deshacerse de él grep -v. Eso evita que descarte los comandos que contiene PID.
  • Supongo que en lugar de echo CPU USAGE is at $CPU_LOAD, quisiste decir echo CPU USAGE is at $CPU_USAGE.
  • Supongo que olvidó eliminar el exit 0que insertó durante la depuración (?).

Estilo:

  • Es posible que desee mover la CPU_USAGE_THRESHOLD=800línea al comienzo del archivo, ya que esto es lo más informativo y es más probable que cambie incluso después de que su script sea estable.
  • Está repitiendo la -eopción: ps -eo pid -eo pcpu -eo commandes lo mismo que ps -eo pid -o pcpu -o command(como es ps -eo pid,pcpu,command).
  • Hay una elsecláusula vacía . Eso siempre parece que debería manejarse, pero no fue por alguna razón desconocida.
Yurim
fuente
2

Eliminar los procesos que utilizan la mayor parte de la CPU / memoria es un problema: solo mira lo que están ahora en tu máquina (aquí actualmente firefox, systemd (init), Xorg, gnome-terminal, un conjunto de hilos del núcleo, xemacs; ninguno de los cuales es prescindible). Mira cómo ajustar el OOM-killer de Linux, por ejemplo aquí .

También tenga en cuenta que la "memoria utilizada por el proceso" es un concepto nebuloso, ya que hay bibliotecas compartidas, se ejecutan archivos ejecutables e incluso partes de áreas de datos. Se puede obtener algún número cargando a cada usuario con una fracción del espacio utilizado, pero incluso sumando eso realmente no da "memoria utilizada" (aún menos "memoria liberada si el proceso desaparece", las partes compartidas permanecen detrás).

vonbrand
fuente
1

He creado un script, kill-process , que mata algunos procesos enumerados en una matriz, si el uso de la CPU es mayor al XX% durante los segundos YY o elimina los procesos que se ejecutan más de ZZ segundos.

  • Puede configurar XX, YY, ZZ en la parte superior del archivo.
  • Puede usar una ps o superior para los procesos de verificación.
  • También hay un modo de ejecución en seco, para verificar pero no matar.
  • Al final, el script envía un correo electrónico si se mataron algunos procesos.

NOTA: Aquí está mi repositorio en Github: https://github.com/padosoft/kill-process

Aquí hay una captura de pantalla:

         ss # 1

Referencias

Parte esencial del script (un resumen de código para el comando superior):

#!/usr/bin/env bash

#max cpu % load
MAX_CPU=90
#max execution time for CPU percentage > MAX_CPU (in seconds 7200s=2h)
MAX_SEC=1800
#sort by cpu
SORTBY=9

#define a processes command name to check
declare -a KILLLIST
KILLLIST=("/usr/sbin/apache2" "/usr/bin/php5-cgi")

#iterate for each process to check in list
for PROCESS_TOCHECK in ${KILLLIST[*]}
do

    #retrive pid with top command order by SORTBY
    PID=$(top -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $1}')

    CPU=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $9}')
    TIME_STR=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $11}')

    # Decode the top CPU time format [dd-]hh:mm.ss.
    TIME_SEC=0
    IFS="-:" read c1 c2 c3 c4 <<< "$TIME_STR"

    #with top command time format is hh:mm.ss, so truncare seconds in c2
    c2=${c2%%.*}

    if [ -n "$c4" ]
    then
      TIME_SEC=$((10#$c4+60*(10#$c3+60*(10#$c2+24*10#$c1))))
    elif [ -n "$c3" ]
    then
      if [ "$CMD" = "ps" ]; then
        TIME_SEC=$((10#$c3+60*(10#$c2+60*10#$c1)))
      else
        TIME_SEC=$(((10#$c3*24)*60*60)+60*(10#$c2+60*10#$c1))             
      fi   
    else
      if [ "$CMD" = "ps" ]; then
        TIME_SEC=$((10#0+(10#$c2+60*10#$c1)))
      else
        TIME_SEC=$((10#0+60*(10#$c2+60*10#$c1)))
      fi
    fi

    #check if need to kill process
    if [ $CPU -gt $MAX_CPU ] && [ $TIME_SEC -gt $MAX_SEC ]; then
        kill -15 $PID
    fi

done
Uso:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]
Lorenzo Padovani
fuente
Parece que sortdebería ser sort -k9nr. Sin n, obtendrá `5.9`> 29.4.
lk_vc