Pergunta

Tenho um problema com alguns processos semelhantes a zumbis em um determinado servidor que precisam ser eliminados de vez em quando.Como posso identificar melhor aqueles que funcionaram por mais de uma hora ou mais?

Foi útil?

Solução

Se eles só precisam ser mortos:

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

Se você quiser ver o que está combinando

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

O -i flag solicitará sim/não para cada correspondência de processo.

Outras dicas

Encontrei uma resposta que funciona para mim:

aviso:isso vai encontrar e matar processos de longa duração

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

(Onde ID do usuário é um ID de usuário específico com processos de longa execução.)

A segunda expressão regular corresponde a um horário que possui um número de dias opcional, seguido por uma hora, um minuto e um segundo componente e, portanto, tem pelo menos uma hora de duração.

Para qualquer coisa com mais de um dia,

ps aux

lhe dará a resposta, mas ela se resume à precisão do dia, o que pode não ser tão ú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]

Se você estiver no Linux ou em outro sistema com o sistema de arquivos /proc, neste exemplo, você só poderá ver que o processo 1 está em execução desde 22 de junho, mas nenhuma indicação da hora em que foi iniciado.

stat /proc/<pid>

lhe dará uma resposta mais precisa.Por exemplo, aqui está um carimbo de data/hora exato para o processo 1, que ps mostra apenas 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

Desta forma você pode obter a lista dos dez processos mais antigos:

ps -elf | sort -r -k12 | head -n 10

Jodie C e outros apontaram que killall -i pode ser usado, o que é bom se você quiser usar o nome do processo para matar.Mas se você quiser matar pelos mesmos parâmetros que pgrep -f, você precisa usar algo como o seguinte, usando bash puro e o /proc sistema de arquivo.

#!/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     

Isso permite que você encontre e elimine processos mais antigos que max_age segundos usando o nome completo do processo;ou seja, o processo denominado /usr/bin/python2 offlineimap pode ser eliminado por referência a "offlineimap", enquanto o killall as soluções apresentadas aqui funcionarão apenas na string "python2".

O Proc::ProcessTable do Perl resolverá o problema:http://search.cpan.org/dist/Proc-ProcessTable/

Você pode instalá-lo no Debian ou Ubuntu com sudo apt-get install libproc-processtable-perl

Aqui está uma frase:

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" } }'

Ou, mais formatado, coloque isso em um arquivo chamado 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";
    }
}

então corra perl process.pl

Isso oferece mais versatilidade e resolução de 1 segundo na hora de início.

Você pode usar bc para juntar os dois comandos na resposta do mob e saber quantos segundos se passaram desde o início do processo:

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

editar:

Por causa do tédio enquanto esperava a execução de longos processos, foi isso que surgiu depois de alguns minutos de manipulação:

#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

Se você colocar isso no seu caminho e chamar assim:desde então

ele imprimirá o cmdline do processo e os segundos desde o início.Você também pode colocar isso no seu caminho:

#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

E do que se você executar:

greptime <pattern>

onde padrões é uma string ou expressão regular estendida, ele imprimirá todos os processos que correspondem a esse padrão e os segundos desde que foram iniciados.:)

faça um ps -aef.isso mostrará a hora em que o processo foi iniciado.Então usando o date comando encontre a hora atual.Calcule a diferença entre os dois para encontrar a idade do processo.

Fiz algo semelhante à resposta aceita, mas um pouco diferente, pois quero fazer a correspondência com base no nome do processo e no processo incorreto em execução por mais de 100 segundos

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')

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

para obter a hora de início do processo em segundos desde a época.Compare com a hora atual (date +%s) para obter a idade atual do processo.

Usar ps é o caminho certo.Já fiz algo semelhante antes, mas não tenho a fonte em mãos.Geralmente - ps tem a opção de informar quais campos mostrar e por quais classificar.Você pode classificar a saída por tempo de execução, executar o grep no processo desejado e, em seguida, eliminá-lo.

HTH

Caso alguém precise disso em C, você pode usar readproc.h e 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;
}

Me deparei com algum lugar..pensei que é simples e útil

Você pode usar o comando diretamente no crontab,

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

ou podemos escrevê-lo 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);'

E chame isso de crontab assim,

* * * * * longprockill.sh

Minha versão de sincetime acima por @Rafael S.Calsaverini:

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

Isso inverte os campos de saída:tempo decorrido primeiro, comando completo incluindo argumentos depois.Isto é preferido porque o comando completo pode conter espaços.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top