Como posso evitar que meu servidor seja invadido por zumbis deste trabalho cron do Ubuntu para remover sessões do PHP?

1

Recentemente, percebi que, ao fazer login, tinha vários milhares de processos marcados como "zumbi". Após investigação adicional, encontrei o seguinte em ps fax :

  701 ?        Ss     0:28 cron
 3363 ?        S      0:00  \_ CRON
 3364 ?        Ss     0:00      \_ /bin/sh -c   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete
 3371 ?        S      0:00          \_ find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +24 ! -execdir fuser -s {} ; -delete
 3451 ?        S      0:02              \_ fuser -s ./sess_jns5af2mvm81e2fg1rbuctlt54
 3452 ?        Z      0:00                  \_ [fuser] <defunct>
 3453 ?        Z      0:00                  \_ [fuser] <defunct>
 3454 ?        Z      0:00                  \_ [fuser] <defunct>

... many, many lines omitted ...

13642 ?        Z      0:00                  \_ [fuser] <defunct>

Tanto quanto eu posso dizer, este é um script em /etc/cron.d/php que deve limpar as sessões de PHP morto aos 10 e 40 minutos após a hora.

Editar: Este é o texto do script. É instalado por padrão com PHP no Ubuntu.

# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete

Por algum motivo (atualmente estou supondo que um rastreador da Web mal comportado esteja fazendo uma nova sessão em cada solicitação, mas ainda estou examinando os logs), às vezes há muitos milhares de sessões de php abandonadas em /var/lib/php/ , e quando esse script for executado, ele terá um novo processo de fusor para cada um. Isso atinge rapidamente o limite do processo e traz as coisas para um rastreamento.

O que posso fazer, além de apenas excluir este cron job e limpar as coisas manualmente?

    
por josePhoenix 30.10.2011 / 01:24

5 respostas

4

Provavelmente seria melhor mover a lógica de find para um script que percorra todos os arquivos na linha de comando para ver se eles estão sendo acessados e, se não, exclua-os:

#!/bin/bash

for x; do
  if ! /bin/fuser -s "$x" 2>/dev/null; then
    rm "$x"
  fi
done

Em seguida, altere o cron job para apenas

09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -execdir thatscript.sh {} +

Isso fará com que find colete todos os arquivos de sessão correspondentes à idade máxima e, em seguida, execute thatscript.sh com todos eles de uma vez (devido ao + em vez de ; ). O script é responsável por garantir que o arquivo não esteja em uso e excluí-lo. Dessa forma, find deve ter apenas um filho direto, e o bash não deve ter nenhum problema em limpar os filhos fuser e rm .

A partir dos documentos de find , não está claro se a localização dividirá automaticamente a lista de nomes de arquivos em múltiplas execuções se excederem os limites do shell / OS (e 13000 arquivos podem fazer isso ... versões mais antigas do bash tiveram um limite de argumento de linha de comando padrão de algo em torno de 5000) Nesse caso, você pode alterar -execdir thatscript.sh {} + para -print0 | xargs -0 thatscript.sh para ter xargs dividir os arquivos.

Como alternativa, se você não tiver a unidade montada noatime , altere -cmin para -amin e dispense completamente os testes:

    09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -amin +$(/usr/lib/php5/maxlifetime) -delete

Isso removerá todos os arquivos da sessão por último acessados mais do que [saída do comando maxlifetime ] minutos atrás. Contanto que você não tenha nenhum processo php que abra uma sessão, então fique sentado por um longo tempo (o padrão para esse maxlifetime no Debian parece ser de 24 minutos, o que seria muito muito tempo para um página para carregar) sem fazer nada, isso não deve zapar as sessões atualmente em uso.

    
por 30.10.2011 / 02:22
4

Eu tenho esse problema também no ubuntu 11.10 e resolvi esse problema editando:

/etc/cron.d/php5 

e substitua o código por:

09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -delete

Esta é a tarefa cron do ubuntu 11.04 para php.

    
por 17.11.2011 / 23:00
1

Corrija o script para que aguarde seus filhos ou ignore SIG_CHILD. Você pode colocar o script em algum lugar que possamos ver?

Atualização : parece que você está acionando um bug em find !

    
por 30.10.2011 / 01:29
1

Eu resolvi isso para um cliente movendo as sessões do sistema de arquivos para o memcache. Eles não tinham os processos zumbis, mas ainda tinham zilhões de sessões que o cronjob não conseguia acompanhar na exclusão. Demorou 10 minutos para instalar o memcache, reconfigurar o php.ini, testá-lo e adicionar alguns gráficos munin para observar o tamanho do memcache. Presto - a carga do servidor diminuiu, todo mundo feliz.

link link

    
por 30.10.2011 / 02:32
1

Isso também será muito útil:

link

Leia os comentários 4 e 8, com o último até mesmo consertando o fusor!

    
por 16.02.2012 / 12:23

Tags