Caso tenha instalado o apache_1.3.41 recentemente com mod_perl-1.30 e perl-5.10 você provavelmente(certamente) estará tendo problemas com Segmentation fault no servidor pai. Digo “certamente” porque o release do mod_perl que corrige esse problema com perl 5.10 jamais foi lançado, está parado no Subversion desde Julho de 2007!
Quando completei o upgrade de rotina nos servidores e verifiquei a lista de Segmentation faults, minha primeira suspeita era encima do DBD::mysql > 4.006. Como já tinha apanhado bastante desse problema em Maio de 2008, fúi direto à solução de abaixar o DBD::mysql para uma versão de 2007. Eis que desta vez não funcionou, e lá se foram mais algumas horas na terra do gdb e do Google para descobrir o problema.
Sintoma
[Mon Mar 16 15:39:32 2009] [notice] child pid 24679 exit signal Segmentation fault (11), possible coredump in /usr/local/apache/coredump/
[Mon Mar 16 15:39:34 2009] [notice] child pid 24678 exit signal Segmentation fault (11), possible coredump in /usr/local/apache/coredump/
[Mon Mar 16 15:39:36 2009] [notice] child pid 24673 exit signal Segmentation fault (11), possible coredump in /usr/local/apache/coredump/
[Mon Mar 16 15:40:00 2009] [notice] child pid 24672 exit signal Segmentation fault (11), possible coredump in /usr/local/apache/coredump/
[Mon Mar 16 15:40:02 2009] [notice] child pid 24668 exit signal Segmentation fault (11), possible coredump in /usr/local/apache/coredump/
Nota: o usuário final não percebe nada, pois o core dump acontece após o atendimento do pedido, conforme verificamos com o gdb :
[root@hendrix coredump]# /usr/local/apache/coredump/
[root@hendrix coredump]# gdb /usr/local/apache/bin/httpd core.23794
GNU gdb Red Hat Linux (6.6-45.fc8rh)
Copyright (C) 2006 Free Software Foundation, Inc.
[ .... ]
Core was generated by `/usr/local/apache/bin/httpd -f /usr/local/apache/conf/httpd.conf’.
Program terminated with signal 11, Segmentation fault.
#0 0x084df82c in Perl_av_fill ()
(gdb) where
#0 0x084df82c in Perl_av_fill ()
#1 0×08387682 in perl_shutdown ()
#2 0x0838789a in perl_child_exit ()
#3 0x083a49b8 in ap_kill_cleanup ()
#4 0x083a3291 in ap_init_alloc ()
#5 0x083a3305 in ap_clear_pool ()
#6 0x083b1ecb in ap_call_close_connection_hook ()
#7 0x083b3f57 in sig_coredump ()
#8
#9 0×40000416 in __kernel_vsyscall ()
#10 0x009cba28 in accept () from /lib/libc.so.6
#11 0x083b570a in child_main ()
#12 0x083b5d6b in make_child ()
#13 0x083b6159 in perform_idle_server_maintenance ()
#14 0x083b67e8 in standalone_main ()
#15 0x083b6e93 in main ()
Ou seja, mesmo sem entrar nos detalhes de Perl_av_fill() vemos que a falta ocorreu após diversas “rotinas de limpeza”( *shutdown() *exit() e *cleanup()). Não sabemos ao certo se esse processo do httpd cumpriu sua missão ou foi interrompido precocemente, ou seja, pode estar causando problemas de performance no site abrindo um novo processo httpd a cada Segmentation fault.
Solução
A solução é simples, porém chama a atenção pelo fato de um bug resolvido em meados de 2007 ainda aparecer no ultimo release do mod_perl 1: o mod_perl-1.31 nunca foi lançado, porém a revisão 555908 do mod_perl-1.30 soluciona o problema. Parece que ninguém mais está usando Apache 1.3 a julgar pela idade desse patch.
Baixe primeiro o patch do mod_perl.c aqui. Logo baixe o patch do mod_perl.h aqui.
Vá até a árvore do mod_perl-1.30:
cd mod_perl-1.30/
cd src/modules/perl/
patch -p7 < mod_perl.patch # para aplicar o patch de mod_perl.c (mude mod_perl.patch para o nome que gravou o .patch acima)
patch -p7 < mod_perl_h.patch # para aplicar o patch de mod_perl.h ( novamente adeque o nome do .patch)
cd ../../../
perl Makefile.PL # etc, parametros completos p/ construir o Apache
make
makeinstall
E pronto! Adeus Segmentation faults.
A seguinte discussão deu a solução do problema. Quem explica é Rafael Garcia-Suarez, cuja explicação logo é endossada por Steve Hay, desenvolvedor do mod_perl.
Atualização 17/3 – Se precisar de mod_perl-1.3 e Apache 1.3.* não use Perl 5.10
A versão 5.10 do Perl traz inúmeras melhorias, infelizmente após 24 horas de testes concluí que realmente o apache_1.3.41 + mod_perl-1.30 não estão em grau de produção para funcionar com Perl 5.10. Os segfaults acabaram, mas surgiram diversos novos problemas. Talvez tenham abandonado o desenvolvimento dessas versões, visto que a série 1.3 do Apache não é mais oficialmente suportada(é apenas mantida). Ocorriam problemas difíceis de diagnosticar, por exemplo: ao atingir MaxRequestsPerChild o servidor filho deveria exit(0) e permitir ao pai criar um novo httpd. Acontece que, estranhamente, isso não ocorria. O httpd pai ficava congelado e os filhos apenas aceitavam conexões sem processá-las, não passavam ao próximo handler, tampouco retornavam ao pai. Para o cliente o navegador apenas mostrava eternamente “carregando”…. Poderiam haver incontáveis causas para isso: semaphores que nunca eram liberados(race condition), o patch aplicado acima no cleanup do mod_perl, etc. Infelizmente a necessidade de concluir o trabalho, e a falta de tempo, me impediram de chegar até a raiz do problema – apenas precisava resolver logo! Então partí pro perl-5.8.9 – é preciso compilar o perl, instalar, e depois fazer tudo de novo com o Apache para ele linkar com esta versão do perl. Terminada mais essa jornada, rodei o Apache benchmark (/usr/local/apache/bin/ab) com 10 conexões simultâneas, 1.000.000 requisições – tudo nos conformes, nenhum core dump ou servidor congelado.