Erro FastCGI e Apache 500 de forma intermitente

4

Eu tenho um problema FastCGI (mod_fastcgi). Isso acontece de vez em quando e não resulta em um colapso completo do servidor, apenas 500 erros. Aqui estão algumas coisas. Primeiro eu estou usando o APC, então o PHP está no controle de seus próprios processos, não do FastCGI. Além disso, tenho o webroot definido como:

/var/www/html

E o fcgi-bin dentro:

/var/www/html/fcgi-bin

Primeiro, aqui está o error_log do apache:

[Fri Jan 07 10:22:39 2011] [error] [client 50.16.222.82] (4)Interrupted system call: FastCGI: comm with server "/var/www/html/fcgi-bin/php.fcgi" aborted: select() failed, referer: http://www.domain.com/

Eu também executei strace no processo 'fcgi-pm'. Aqui está um recorte do rastro no momento em que ele é lançado:

21725 gettimeofday({1294420603, 14360}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6503 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 96595}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6154 23*C /var/www/html/fcgi-bin/php.fcgi - - 6483 28*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 270744}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 5741 38*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 311502}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6064 32*", 16384) = 46
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 365598}, NULL) = 0
21725 read(14, "C /var/www/html/fcgi-bin/php.fcgi - - 6179 33*C /var/www/html/fcgi-bin/php.fcgi - - 5906 59*", 16384) = 92
21725 alarm(131)                        = 0
21725 select(15, [14], NULL, NULL, NULL) = 1 (in [14])
21725 alarm(0)                          = 131
21725 gettimeofday({1294420603, 454405}, NULL) = 0

Eu notei que o 'select ()' parece permanecer o mesmo, no entanto, o read () muda seu retorno de 46 para algum outro número enquanto está sendo bombardeado. Alguém já viu algo como isso. Isso poderia ser algum tipo de bloqueio de arquivo?

Obrigado Ben

    
por benkorn1 07.01.2011 / 18:35

3 respostas

6

Sinopse

Eu observei o mesmo comportamento com o Apache; parece que esse problema não é específico para o lighttpd.

No meu caso, os sintomas eram exatamente os mesmos; os logs de acesso do Apache foram salpicados com códigos de resposta intermitentes 500, e não havia entradas correspondentes no log de erros do PHP (e o relatório de erros do PHP foi configurado para ser detalhado ao máximo).

Eu descrevi o problema extensivamente na lista de discussão do Apache (pesquise os arquivos da lista pelo assunto "Intermitente 500 respostas no access.log sem as entradas correspondentes no error.log").

Causa Raiz

A resposta do 1100110 sugere a causa raiz, mas fornecerei documentação adicional, diretamente do Apache, bem como sugestões para eliminar o problema.

Aqui está a palavra oficial do Apache sobre este assunto:

link :

Special PHP considerations

By default, PHP FastCGI processes exit after handling 500 requests, and they may exit after this module has already connected to the application and sent the next request. When that occurs, an error will be logged and 500 Internal Server Error will be returned to the client. This PHP behavior can be disabled by setting PHP_FCGI_MAX_REQUESTS to 0, but that can be a problem if the PHP application leaks resources. Alternatively, PHP_FCGI_MAX_REQUESTS can be set to a much higher value than the default to reduce the frequency of this problem. FcgidMaxRequestsPerProcess can be set to a value less than or equal to PHP_FCGI_MAX_REQUESTS to resolve the problem.

PHP child process management (PHP_FCGI_CHILDREN) should always be disabled with mod_fcgid, which will only route one request at a time to application processes it has spawned; thus, any child processes created by PHP will not be used effectively. (Additionally, the PHP child processes may not be terminated properly.) By default, and with the environment variable setting PHP_FCGI_CHILDREN=0, PHP child process management is disabled.

The popular APC opcode cache for PHP cannot share a cache between PHP FastCGI processes unless PHP manages the child processes. Thus, the effectiveness of the cache is limited with mod_fcgid; concurrent PHP requests will use different opcode caches.

Lá nós temos isso.

Soluções possíveis

Opção 1

Uma solução é definir PHP_FCGI_MAX_REQUESTS como zero, mas essa medida introduz o potencial de vazamentos de memória para crescer fora de controle.

Os vários pedaços de documentação que consultei não deixam claro se o PHP via Fast-CGI sofre de vazamento inerente de memória (daí o comportamento de "reciclagem de processo") ou se o risco é limitado a um mau desempenho. scripts escritos, "fugitivos".

Em qualquer caso, existe o risco inerente de definir PHP_FCGI_MAX_REQUESTS como zero, especialmente em um ambiente de hospedagem compartilhada.

Opção 2

Uma segunda solução, conforme descrito no trecho acima, é definir FcgidMaxRequestsPerProcess como um valor menor ou igual a PHP_FCGI_MAX_REQUESTS. A documentação omite um ponto importante, no entanto: o valor também deve ser maior que zero (porque zero significa "ilimitado" ou "desativa a verificação" neste contexto). Dado que o valor padrão para FcgidMaxRequestsPerProcess é zero, e o valor padrão para PHP_FCGI_MAX_REQUESTS é 500, qualquer administrador que não tenha sobrescrito esses valores experimentará os 500 códigos de resposta intermitentes. Por esse motivo, não consigo entender por que FcgidMaxRequestsPerProcess e PHP_FCGI_MAX_REQUESTS não compartilham o mesmo valor padrão. Talvez isso aconteça porque configurar essas duas diretivas como tal produz o mesmo resultado líquido que definir PHP_FCGI_MAX_REQUESTS como zero; a documentação é ambígua a esse respeito.

Opção 3

Uma terceira solução é abandonar totalmente a Fast-CGI, em favor de uma alternativa comparável, como suPHP ou antigo CGI + SuExec. Realizei alguns benchmarking de desempenho básico e bruto em vários modos do PHP, e minhas descobertas são as seguintes:

  1. Mod-PHP 77.7
  2. CGI 69,0
  3. suPHP 67,0
  4. Fast-CGI 55.7

O Mod-PHP é o de maior desempenho, com uma pontuação de 77,7. As pontuações são arbitrárias e servem apenas para demonstrar a variação relativa nos tempos de carregamento da página nos modos PHP.

Se assumirmos que esses benchmarks são bastante representativos, então parece haver muito poucas razões para se agarrar à Fast-CGI, dada essa falha (bastante séria) em sua implementação. A única razão substancial que vem à mente é o cache de código operacional. Meu entendimento é que o PHP não pode utilizar o cache de código operacional através do modo CGI ou suPHP (porque os processos não persistem entre as solicitações).

Enquanto a Fast-CGI não tira proveito do cache de op-code (por exemplo, via APC), usuários inteligentes criaram um método para tornar a APC efetiva com Fast-CGI (via caches por usuário ): link . Existem várias desvantagens, no entanto:

  1. Os requisitos de memória (RAM) são consideráveis, pois há um cache dedicado para cada usuário. (Para perspectiva, considere que no modo Mod-PHP, todos os usuários compartilham um único cache.)
  2. O Apache deve usar o módulo mais antigo, mod_fastcgi, em vez do equivalente mais novo, mod_fcgid. (Para detalhes, veja o artigo citado no parágrafo acima).
  3. A configuração é bastante complexa.

Como corolário relacionado, você disse o seguinte em sua pergunta:

First I am using APC so PHP is in control of it's own processes, not FastCGI.

A menos que você esteja usando o mod_fastcgi (e não o mod_fcgid), e a menos que você tenha seguido etapas similares às citadas alguns parágrafos acima, a APC está consumindo recursos sem efeito. Como tal, você pode querer desativar o APC.

Resumo da Solução

Tome uma das três medidas a seguir:

  1. Defina a variável de ambiente PHP_FCGI_MAX_REQUESTS para zero. (Introduz o potencial de vazamentos de memória em scripts PHP para crescer fora de controle).
  2. Defina FcgidMaxRequestsPerProcess como um valor menor ou igual a PHP_FCGI_MAX_REQUESTS, mas maior que zero.
  3. Abandone o Fast-CGI em favor de uma alternativa comparável, como suPHP ou antigo CGI + SuExec.
por 26.10.2012 / 19:32
1

Eu li em algum lugar (lidando com o lighttpd, não com o apache) que o php não pode lidar com mais de 500 solicitações por algum motivo. O 501º pedido será bombardeado por qualquer motivo.

Desculpe, eu não tenho mais informações do que isso, mas vale a pena tentar.

tl; dr tente definir PHP_FCGI_MAX_REQUESTS para 500 e ver se o problema desaparece.

Encontrou a informação, aplica-se ao Lighttpd e não sei se se aplica ao apache ou não.

Teste-o e adoraria saber se isto é apenas um problema com o lighttpd ou se é um problema geral.

Why is my PHP application returning an error 500 from time to time?

"Esse problema parece derivar de um problema pouco conhecido com PHP: PHP pára de aceitar novas conexões FastCGI depois de manipular 500 solicitações; infelizmente, há uma condição de corrida em potencial durante o código de limpeza do PHP no qual o PHP pode ser encerrado, mas ainda tem o soquete aberto, então lighty pode enviar o pedido número 501 para o PHP e tê-lo "aceito", mas o PHP parece simplesmente sair, causando um retorno de 500 do lighty.

Para limitar esta ocorrência, defina PHP_FCGI_MAX_REQUESTS para 500. "

- link

    
por 16.02.2012 / 22:48
0

Obrigado pela sua resposta. Eu tenho todo o erro do PHP indo para um arquivo de log. Eu recebo alguns avisos, mas sem erros. Devo admitir que não escrevi este código. Por enquanto eu redirecionei todos os 500 erros para o index.php, usando uma regra '.htaccess'. Eu devo estar faltando alguma coisa embora. Isso não devia estar acontecendo. O único palpite que tenho é que, uma vez que o 'PHP_FCGI_MAX_REQUESTS' alcança o máximo, php mata o filho e isso confunde o FastCGI. No entanto, se eu entendi corretamente, o PHP tem um processo pai que deve ser o único que o FastCGI fala, então eu não tenho certeza que é isso ... Aqui está o meu script de wrapper:

#!/bin/bash
# Shell Script To Run PHP5 using mod_fastcgi under Apache 2.x
# Tested under Red Hat Enterprise Linux / CentOS 5.x
### Set PATH ###
PHP_CGI='/usr/bin/php-cgi -d apc.shm_size=60M'
PHP_FCGI_CHILDREN=25
PHP_FCGI_MAX_REQUESTS=1000
### no editing below ###
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS
exec $PHP_CGI

Esse é um servidor de muito alto volume, e é por isso que o PHP_FCGI_CHILDREN está tão alto.

Obrigado novamente Ben

    
por 08.01.2011 / 01:15