Apache mpm-worker + mod_fcgid + php5_cgi parcialmente e esporadicamente para baixo

1

Recentemente, mudei do Apache mpm-prefork (módulo PHP) para o mpm-worker (PHP-FPM) devido a problemas de memória. Eu estou executando um aplicativo PHP bastante grande que requer ~ 20-30M por processo prefork.

No geral, o servidor funciona de maneira estável e rápida. No entanto, de tempos em tempos, a página fica indisponível para alguns usuários por alguns minutos.

A hipótese de trabalho 1 (= idéia aproximada) é que um dos processos (geralmente 2, em algum momento até 5 ou 6) trava e cada cliente atribuído a esse processo (por exemplo, 50% dos clientes) recebe uma mensagem de erro. / p>

A hipótese de trabalho 2 é que MaxRequestsPerProcess é responsável. Após 500 chamadas, o processo tenta desligar, o mod_fcgid não mata graciosamente e enquanto o processo está aguardando o kill, outros clientes são designados (e rejeitados pelo) processo. Mas não consigo imaginar que o Apache seja tão estúpido.

Meu problema é: não há nada nos registros de erro, exceto alguns

[warn] mod_fcgid: process ???? graceful kill fail, sending SIGKILL

Estou ficando sem ideias para rastrear o problema. Aparece esporadicamente e ainda não consegui provocá-lo. O desempenho do servidor (CPU / RAM) não será um problema, já que a carga geral esteve na faixa mais baixa nas últimas semanas.

Obrigado por qualquer sugestão. Quaisquer comentários sobre minhas hipóteses (que não ajudaram o meu a encontrar uma solução, ainda - eu tentei desativar o MaxRequestsPerProcess mas ainda não sei se ajudou)? Eu apreciaria muito algumas idéias de como rastrear esse problema.

Configuração do Apache

    <Directory /var/www/html>
           ...

            # PHP FCGI
            <FilesMatch \.php$>
                    SetHandler fcgid-script
            </FilesMatch>
            Options +ExecCGI
    </Directory>

    <IfModule mod_fcgid.c>
            FcgidWrapper /var/www/php-fcgi-starter .php
            # Allow request up to 33 MB
            FcgidMaxRequestLen 34603008
            FcgidIOTimeout 300
            FcgidBusyTimeout 3600
            # Set 1200 (>1000) for PHP_FCGI_MAX_REQUESTS to avoid problems
            FcgidMaxRequestsPerProcess 1000
    </IfModule>

Configuração do módulo do Apache

<IfModule mod_fcgid.c>
  AddHandler    fcgid-script .fcgi
  FcgidConnectTimeout 20
  FcgidBusyTimeout 7200

  DefaultMinClassProcessCount 0
  IdleTimeout 600
  IdleScanInterval 60
  MaxProcessCount 20

  MaxRequestsPerProcess 500
  PHP_Fix_Pathinfo_Enable 1
</IfModule>

Nota: O tempo limite foi definido para 2 horas porque raramente, o aplicativo pode exigir algum tempo para ser executado (por exemplo, o cronjob noturno que otimiza o banco de dados).

Script inicial

#!/bin/sh
PHP_FCGI_MAX_REQUESTS=1200
export PHP_FCGI_MAX_REQUESTS

export PHPRC="/etc/php5/cgi"
exec /usr/bin/php5-cgi

#PHP_FCGI_CHILDREN=10
#export PHP_FCGI_CHILDREN

Versões do pacote

  • Sistema: Ubuntu 12.04.2 LTS
  • apache2-mpm-worker: 2.2.22-1ubuntu1.4
  • libapache2-mod-fcgid: 1: 2.3.6-1.1
  • php5-common: 5.3.10-1ubuntu3.7
por BurninLeo 29.07.2013 / 14:13

2 respostas

1

Eu consideraria 20-30MB por processo como muito pequeno. É tudo relativo, mas, por exemplo, a maioria dos aplicativos CMS exigirá pelo menos 100MB. Além disso, seu tamanho máximo de upload será limitado pelo tamanho máximo do processo, se isso for importante.

Quando o servidor não está disponível, é provável que os processos do operador php estejam todos ocupados, mas isso é apenas uma causa imediata. Algo está a abrandar o seu servidor de tal forma que por um tempo, pelo menos, os processos de php não conseguem acompanhar as solicitações recebidas. O que está a atrasar o seu servidor é difícil de julgar, mas a 'falha na matança graciosa' faz-me pensar que o processo que estava para ser morto provavelmente está à espera no disco.

Você logou enquanto isso está acontecendo? O sistema se sente responsivo?

Na parte superior, observe os estados do processo e procure os 'D', que estão aguardando o IO. Existem muitos desses? O 'wa' no resumo no topo é o tempo total que os processos gastam esperando no IO. (Diz porcentagem, mas é provável que seja uma porcentagem do tempo de um processador). Ferramentas como iotop, top e vmstat também podem ser úteis para obter uma visualização de quais processos estão vinculados ao disco e até que ponto o disco está limitando seu desempenho geral.

Sua compreensão do que acontece quando um processo de trabalho não está disponível para receber novas solicitações está incorreta. Novas solicitações não serão atribuídas a ele.

1000 solicitações antes de matar o trabalhador é alto. Eu sugiro soltá-lo em algum lugar entre 10 e 50.

    
por 14.08.2013 / 15:29
1

Eu acho que você está no caminho certo com a Hypopthesis 1. O conselho do mc0e é bastante sólido, então estou adicionando mais a ele.

Essas mensagens de log que você está vendo sugerem que processos individuais estão sendo bloqueados sob o prefork trabalhador . Eu já vi isso em um ambiente de produção antes e isso significa que você tem algum código mal-comportado.

Entre suas solicitações de alta máxima por criança e seus processos de suspensão, isso prepara o cenário para o inchaço da memória. A documentação cobre especificamente o fato de que um um valor diferente de zero ajuda a proteger contra vazamentos de memória , mas se você definir esse valor muito alto, os benefícios serão perdidos. Ter seus processos pendurados em cima disso apenas aumenta ainda mais o consumo geral de memória.

Isso deixa você com dois tópicos imediatos:

  • Menor MaxRequestsPerChild por uma margem significativa, como mc0e estava sugerindo. Isso ajuda a evitar que os processos individuais vivam o suficiente para acumular vazamentos significativos de memória ... mas, como ele disse, 20 a 30M provavelmente não é tão grande assim.
  • Encontre seus bugs. Você está procurando vazamentos de memória e deadlocks de execução (a contenção de recursos, como o mc0e estava sugerindo, mas também dê uma olhada no que seu código faz quando os recursos da rede se tornam inacessíveis ou não respondem). A execução de lsof em seus processos grandes pode fornecer uma dica, dependendo do que o código está fazendo (isto é, vazamento do identificador de arquivo e atingir o limite máximo do arquivo). você está olhando para depuração de código.
por 14.08.2013 / 15:50