O trabalho do cron de coleta de lixo do Ubuntu para sessões PHP leva 25 minutos para ser executado, por quê?


13

O Ubuntu possui um trabalho cron configurado para procurar e excluir sessões antigas do PHP:

# 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

Meu problema é que esse processo está demorando muito tempo para ser executado, com muitas E / S de disco. Aqui está o meu gráfico de uso da CPU:

Gráfico de uso da CPU

A execução da limpeza é representada pelos pontos da cerceta. No início do período, os trabalhos de limpeza do PHP eram agendados nos horários padrão de 09 e 39 minutos. Às 15:00, removi o tempo de 39 minutos do cron, portanto, um trabalho de limpeza com o dobro do tamanho é executado com metade da frequência (você pode ver os picos obterem o dobro da largura e a metade da frequência).

Aqui estão os gráficos correspondentes para o tempo de IO:

Tempo de IO

E operações de disco:

Operações de disco

No pico em que havia cerca de 14.000 sessões ativas, a limpeza pode ser executada por 25 minutos, aparentemente usando 100% de um núcleo da CPU e o que parece ser 100% da E / S do disco durante todo o período. Por que é tão intensivo em recursos? Um lsdiretório da sessão /var/lib/php5leva apenas uma fração de segundo. Então, por que são necessários 25 minutos para aparar as sessões antigas? Há algo que eu possa fazer para acelerar isso?

O sistema de arquivos deste dispositivo está atualmente ext4, sendo executado no Ubuntu Precise 12.04 de 64 bits.

Edição: Eu suspeito que a carga é devido ao processo incomum "fusor" (desde que eu espero que um simples rmseja uma visão muito mais rápida do que o desempenho que estou vendo). Vou remover o uso do fusor e ver o que acontece.


Quanto tráfego seu site gera para gerar tantas sessões?
Michael Hampton

Respostas:


9

A remoção de fuserdeve ajudar. Este trabalho executa um fusercomando (verifique se um arquivo está aberto no momento) para cada arquivo de sessão encontrado , o que pode facilmente levar alguns minutos em um sistema ocupado com 14k sessões. Este foi um bug do Debian (o Ubuntu é baseado no Debian).

Em vez de memcached, você também pode tentar usar tmpfs (um sistema de arquivos na memória) para arquivos de sessão. Assim como o memcached, isso invalidaria as sessões na reinicialização (isso pode ser contornado, fazendo backup deste diretório em algum lugar do script de desligamento e restaurando o script de inicialização), mas será muito mais fácil de configurar. Mas isso não vai ajudar com o fuserproblema.


Parece que o bug no fusor foi que uma versão anterior foi bifurcada, mas nunca foi colhida após a conclusão, deixando milhares de fuserprocessos em um estado zumbi consumindo memória, o que leva a uma falha no servidor. Eu acho que isso já foi corrigido na versão do psmisc que estou usando.
thenickdude

Esse é outro bug. Você tem um problema simples de iniciar milhares de fuserprocessos, todos os quais devem procurar /proc/arquivos abertos no todo .
Tometzky

9

Parabéns por ter um site popular e por mantê-lo funcionando em uma máquina virtual por todo esse tempo.

Se você está realmente puxando em dois milhões de pageviews por dia, então você está indo para empilhar um monte de sessões PHP no sistema de arquivos, e eles vão levar um longo tempo para apagar não importa se você usa fuserou rmou um aspirador de pó.

Nesse ponto, recomendo que você procure maneiras alternativas de armazenar suas sessões:

  • Uma opção é armazenar sessõesmemcached . Isso é muito rápido, mas se o servidor travar ou reiniciar, todas as suas sessões serão perdidas e todos sairão.
  • Você também pode armazenar sessões em um banco de dados. Isso seria um pouco mais lento que o memcached, mas o banco de dados seria persistente e você poderia limpar sessões antigas com uma simples consulta SQL. Para implementar isso, no entanto, você precisa escrever um manipulador de sessão personalizado .

Memcached é certamente uma opção, embora deva ser um pool separado da instância principal do memcached, caso contrário, as sessões seriam despejadas aleatoriamente da pressão do cache. Não estou convencido de que a exclusão de 14.000 arquivos deva demorar 25 minutos. Isso parece muito lento para mim. Vou esperar algumas horas e ver como é o desempenho de um simples rm.
thenickdude

Sem saber mais sobre sua arquitetura geral, hesito em recomendar uma sobre a outra.
Michael Hampton

Você pode agrupar servidores Memcached para redundância, definindo memcache.session_redundancy = 2. Consulte serverfault.com/questions/164350/… . Redis é uma boa opção se você estiver preocupado com persistência e muito mais rápido que os armazenamentos de banco de dados SQL.
jfountain

4

Portanto, as opções de armazenamento do Memcached e da sessão de banco de dados sugeridas pelos usuários aqui são boas opções para aumentar o desempenho, cada uma com seus próprios benefícios e desvantagens.

Mas, testando o desempenho, descobri que o enorme custo de desempenho dessa manutenção de sessão se deve quase inteiramente à chamada fuserno trabalho cron. Aqui estão os gráficos de desempenho após a reversão para o trabalho cron Natty / Oneiric, que usa em rmvez de fuseraparar sessões antigas, a alternância ocorre às 2:30.

utilização do CPU

Tempo decorrido de IO

Operações de disco

Você pode ver que a degradação periódica do desempenho causada pela limpeza da sessão PHP do Ubuntu é quase totalmente removida. Os picos mostrados no gráfico Operações de disco agora são muito menores em magnitude e tão finos quanto esse gráfico pode medir, mostrando uma pequena e curta interrupção em que anteriormente o desempenho do servidor era significativamente reduzido por 25 minutos. O uso extra da CPU é totalmente eliminado, agora este é um trabalho vinculado a E / S.

(um trabalho de E / S não relacionado é executado às 05:00 e o trabalho de CPU é executado às 7:40, o que causa seus próprios picos nesses gráficos)

O trabalho cron modificado que estou executando agora é:

09 *     * * *     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) -print0 \
   | xargs -n 200 -r -0 rm

-print0 | xargs ...não é necessário - você pode simplesmente sair de -deletelá. Mas funcionará nos dois sentidos com velocidade comparável.
Tometzky

1

Me deparei com este post ao fazer uma pesquisa sobre sessões. Embora a resposta aceita seja muito boa (e a chamada do fusor tenha sido removida do script gc por algum tempo), acho que vale a pena observar algumas outras considerações, caso alguém se depare com um problema semelhante.

No cenário descrito, o OP estava usando ext4. Os diretórios no ext4 armazenam dados de arquivos em um formato de banco de dados htree - o que significa que há um impacto insignificante na retenção de muitos arquivos em um único diretório, em comparação com a distribuição deles em vários diretórios. Isso não é verdade para todos os sistemas de arquivos. O manipulador padrão no PHP permite que você use vários subdiretórios para arquivos de sessão (mas observe que você deve verificar se o processo de controle está recorrendo nesses diretórios - o trabalho cron acima não).

Muito do custo da operação (após a remoção da chamada para o fusor) decorre da observação de arquivos que ainda não estão obsoletos. O uso (por exemplo) de um único nível de subdiretórios e 16 tarefas cron procurando em cada subdiretório (0 /, 1 /, ... d /, e /, f /) suavizará os choques de carga resultantes.

Usar um manipulador de sessão personalizado com um substrato mais rápido ajudará - mas há muito por onde escolher (memcache, redis, soquete do manipulador mysql ...) deixando de lado o intervalo de qualidade daqueles publicados na Internet, que você escolhe depende da exata requisitos em relação à sua aplicação, infraestrutura e habilidades, para não esquecer que frequentemente existem diferenças no tratamento da semântica (principalmente o bloqueio) em comparação com o manipulador padrão.


0

Com esse tipo de tráfego, você não deve colocar sessões em um dis. Você deve usar algo como memcache. Tudo que você precisa fazer é configurar o php e não haverá necessidade de alterar o código. Veja por exemplo

http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/

A razão pela qual está demorando tanto é devido à enorme quantidade de arquivos que ele precisa classificar para ver quais podem ser excluídos. O Memcache pode expirar automaticamente, considerando a duração da sessão que você definiu no seu código.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.