¿Cómo se matan todos los procesos de Linux que son más viejos que una cierta edad?


Tengo un problema con algunos procesos similares a zombis en un servidor determinado que necesitan ser asesinados de vez en cuando. ¿Cómo puedo identificar mejor los que han funcionado durante más de una hora o así?

Author: Mark Harrison, 2008-08-08

14 answers

Si solo necesitan ser asesinados:

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi

Si quieres ver qué coincide

if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi

El indicador -i le indicará sí/no para cada coincidencia de proceso.

 29
Author: Jodie C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-09 23:50:32

Encontré una respuesta que funciona para mí:

Advertencia: esto encontrará y matará procesos de larga ejecución

ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}

(Donde user-id es un ID de usuario específico con procesos de larga ejecución.)

La segunda expresión regular coincide con el tiempo a que tiene una figura opcional días, seguido de un componente hora, minuto y segundo, y por lo tanto tiene al menos una hora de duración.

 36
Author: yukondude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-12 00:54:23

Para cualquier cosa más vieja que un día,

ps aux

Le dará la respuesta, pero se reduce a la precisión del día que podría no ser tan útil.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   7200   308 ?        Ss   Jun22   0:02 init [5]
root         2  0.0  0.0      0     0 ?        S    Jun22   0:02 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Jun22   0:18 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Jun22   0:00 [watchdog/0]

Si está en linux u otro sistema con el sistema de archivos /proc, en este ejemplo, solo puede ver que el proceso 1 se ha estado ejecutando desde el 22 de junio, pero no hay indicación de la hora en que se inició.

stat /proc/<pid>

Le dará una respuesta más precisa. Por ejemplo, aquí hay una marca de tiempo exacta para el proceso 1, que ps muestra solo como Jun22:

ohm ~$ stat /proc/1
  File: `/proc/1'
  Size: 0               Blocks: 0          IO Block: 4096   directory
Device: 3h/3d   Inode: 65538       Links: 5
Access: (0555/dr-xr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2008-06-22 15:37:44.347627750 -0700
Modify: 2008-06-22 15:37:44.347627750 -0700
Change: 2008-06-22 15:37:44.347627750 -0700
 22
Author: Mark Harrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-09 00:27:05

De esta manera puede obtener la lista de los diez procesos más antiguos:

ps -elf | sort -r -k12 | head -n 10
 9
Author: ggasp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-08 17:20:01

Perl's Proc:: ProcessTable hará el truco: http://search.cpan.org/dist/Proc-ProcessTable /

Puede instalarlo en debian o ubuntu con sudo apt-get install libproc-processtable-perl

Aquí hay una sola línea:

perl -MProc::ProcessTable -Mstrict -w -e 'my $anHourAgo = time-60*60; my $t = new Proc::ProcessTable;foreach my $p ( @{$t->table} ) { if ($p->start() < $anHourAgo) { print $p->pid, "\n" } }'

O, más formateado, poner esto en un archivo llamado process.pl:

#!/usr/bin/perl -w
use strict;
use Proc::ProcessTable;
my $anHourAgo = time-60*60;
my $t = new Proc::ProcessTable;
foreach my $p ( @{$t->table} ) {
    if ($p->start() < $anHourAgo) {
        print $p->pid, "\n";
    }
}

Luego ejecuta perl process.pl

Esto le da más versatilidad y resolución de 1 segundo en la hora de inicio.

 7
Author: Peter V. Mørch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-13 07:19:40

Jodie C y otros han señalado que se puede usar killall -i, lo cual está bien si quieres usar el nombre del proceso para matar. Pero si quieres matar por los mismos parámetros que pgrep -f, necesitas usar algo como lo siguiente, usando pure bash y el sistema de archivos /proc.

#!/bin/sh                                                                                                                                               

max_age=120 # (seconds)                                                                                                                                 
naughty="$(pgrep -f offlineimap)"                                                                                                                       
if [[ -n "$naughty" ]]; then # naughty is running                                                                                                       
  age_in_seconds=$(echo "$(date +%s) - $(stat -c %X /proc/$naughty)" | bc)                                                                              
  if [[ "$age_in_seconds" -ge "$max_age" ]]; then # naughty is too old!                                                                                 
    kill -s 9 "$naughty"                                                                                                                                
  fi                                                                                                                                                    
fi     

Esto le permite encontrar y matar procesos más antiguos que max_age segundos usando el nombre completo del proceso ; es decir, el proceso llamado /usr/bin/python2 offlineimap se puede matar por referencia a "offlineimap", mientras que las soluciones killall presentado aquí solo trabajará en la cuerda "python2".

 7
Author: g33kz0r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-14 15:54:11

Puede usar bc para unir los dos comandos en la respuesta de mob y obtener cuántos segundos cayeron desde que comenzó el proceso:

echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc

Editar:

Por aburrimiento mientras se espera que se ejecuten largos procesos, esto es lo que salió después de unos minutos jugueteando:

#file: sincetime
#!/bin/bash
init=`stat -t /proc/$1 | awk '{print $14}'`
curr=`date +%s`
seconds=`echo $curr - $init| bc`
name=`cat /proc/$1/cmdline`
echo $name $seconds

Si pones esto en tu camino y lo llamas así: desde el tiempo

Imprimirá el proceso cmdline y los segundos desde que se inició. También puedes poner esto en tu camino:

#file: greptime
#!/bin/bash
pidlist=`ps ax | grep -i -E $1 | grep -v grep | awk '{print $1}' | grep -v PID | xargs echo`
for pid in $pidlist; do
    sincetime $pid
done

Y que si usted ejecutar:

greptime <pattern>

Donde patterns es una cadena o expresión regular extendida, imprimirá todos los procesos que coincidan con este patrón y los segundos desde que comenzaron. :)

 3
Author: Rafael S. Calsaverini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-15 00:22:27

Haz un ps -aef. esto le mostrará el momento en el que comenzó el proceso. Entonces usando el comando date encuentre la hora actual. Calcule la diferencia entre los dos para encontrar la edad del proceso.

 2
Author: Maniraj Patri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-09 18:31:39

Hice algo similar a la respuesta aceptada, pero ligeramente diferente, ya que quiero coincidir en función del nombre del proceso y en función del proceso incorrecto que se ejecuta durante más de 100 segundos

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')
 1
Author: Rodney Amato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 03:15:05

stat -t /proc/<pid> | awk '{print $14}'

Para obtener la hora de inicio del proceso en segundos desde la época. Compare con el tiempo actual (date +%s) para obtener la antigüedad actual del proceso.

 1
Author: mob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-16 17:39:07

Usar ps es la forma correcta. Ya he hecho algo similar antes, pero no tengo la fuente a mano. Generalmente-ps tiene una opción para indicarle qué campos mostrar y por qué ordenar. Puede ordenar la salida por tiempo de ejecución, grep el proceso que desee y luego matarlo.

HTH

 0
Author: abyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-08 16:54:49

En caso de que alguien necesite esto en C, puede usar readproc.h y libproc:

#include <proc/readproc.h>
#include <proc/sysinfo.h>

float
pid_age(pid_t pid)
{
        proc_t proc_info;
        int seconds_since_boot = uptime(0,0);
        if (!get_proc_stats(pid, &proc_info)) {
                return 0.0;
        }

        // readproc.h comment lies about what proc_t.start_time is. It's
        // actually expressed in Hertz ticks since boot

        int  seconds_since_1970 = time(NULL);
        int time_of_boot = seconds_since_1970 - seconds_since_boot;
        long  t = seconds_since_boot - (unsigned long)(proc_info.start_time / Hertz);

        int delta = t;
        float days = ((float) delta / (float)(60*60*24));
        return days;
}
 0
Author: David Jeske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-02 09:07:24

Se encontró en alguna parte..pensé que es simple y útil

Puede usar el comando en crontab directamente,

* * * * * ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);'

O, podemos escribirlo como shell script ,

#!/bin/sh
# longprockill.sh
ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F[13]; kill
+ 9, $F[3] if ($h > 1);'

Y llámalo crontab así,

* * * * * longprockill.sh
 0
Author: user3743785,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-06 09:21:36

Mi versión de sincetime anterior por @ Rafael S. Calsaverini:

#!/bin/bash
ps --no-headers -o etimes,args "$1"

Esto invierte los campos de salida: tiempo transcurrido primero, comando completo incluyendo argumentos segundo. Esto es preferible porque el comando completo puede contener espacios.

 0
Author: Phil Hudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-26 04:29:40