blog do Zé

22/7 de 2010

Como visualizar quais Virtual Hosts o Apache está atendendo no momento

Categoria: Linux,Perl,UNIX — jfonseca @ 12:19 am

Caso você administre um servidor Apache com dezenas ou centenas de Virtual Hosts, possivelmente já terá se deparado com picos de visitação que, normalmente, testam os limites do servidor. Caso possua apenas um site hospedado por servidor, esqueça o resto deste artigo. No entanto, na grande maioria dos ambientes de hospedagem, um servidor dedicado terá inúmeros hosts virtuais configurados, e é praticamente impossível saber, desconhecendo a origem do pico de visitação, qual é o responsável pela sobrecarga.

Para resolver este problema criei o seguinte script Perl que, combinado ao tcpdump, analisa o tráfego de rede atual, extraindo os cabeçalhos “Host:” e contando quantas vezes cada Host surge no tráfego capturado. Um handler do sinal SIGALRM imprime ao STDOUT as estatísticas atuais a cada 5 segundos, em ordem decrescente de demanda.

Assim, é possível ver, em tempo real, qual Virtual Host está gerando a maior demanda no servidor naquele instante.

Copie o seguinte script e salve como tcpd_host_filter.pl

#!/usr/bin/perl

# http://zefonseca.com/blogs/ze/

use strict;
use warnings;

our %hosts = ();
our $match_count = 0;

$SIG{ALRM} = \&dump_stats;

alarm(5);

while (<>) {
        if ( m{Host\:\s+(\S+)}gms ) {
                $hosts{$1}++;
                $match_count++;
        }
}

sub dump_stats {
        print "\n\nACTIVE HOSTS\n";
        foreach my $host ( reverse sort { $hosts{$a} <=> $hosts{$b} } keys %hosts ) {
                my $ratio = $hosts{$host} / $match_count;
                printf "%-5d %-32s %.2f %% \n", $hosts{$host}, $host, $ratio*100;
        }
        alarm(5);
}

Torne o script executavel:

chmod 755 tcpd_host_filter.pl

Agora rode o tcpdump com as opções -s 65535, que determina o tamanho máximo de captura, e -w – que escreve todo o conteúdo do pacote capturado à saída padrão.

tcpdump -s 65535 -w - | ./tcpd_host_filter.pl

O script lerá a captura em tempo real, no entanto só imprimirá as estatísticas a cada 5 segundos, para evitar uma inundação de dados na tela.

Exemplo de saída:

ACTIVE HOSTS
120   site1.com             30.61 %
116   site2.com                            29.59 %
74    zefonseca.com                    18.88 %
29    site3.com                        7.40 %
9     site4.com                 2.30 %
8     site5.com               2.04 %
7     site6.com                 1.79 %
7     site7.com                 1.79 %
[ ... ]

 

13/11 de 2009

Novo site Perl.org lançado

Categoria: Perl,Programação — jfonseca @ 11:53 pm

Camelo do PerlFoi lançado hoje o novo site oficial da linguagem Perl, Perl.org – ficou muito mais fácil de usar, repare que praticamente tudo que possa precisar sobre Perl está na primeira página: documentação, tutoriais, módulos, eventos e muito mais.

Confira!


 

8/11 de 2009

Apache:::Session travando aleatoriamente

Categoria: Perl — jfonseca @ 9:28 pm

O Apache::Session parece ter algum problema com o Lock::MySQL onde. Ocasionalmente, levará até 1 hora aguardando o GET_LOCK do MySQL.

A solução que encontrei não me parece ideal, no entanto solucionou meu problema.

Edite o Lock::MySQL:
vi /usr/lib/perl5/site_perl/5.10.0/Apache/Session/Lock/MySQL.pm
(Substitua 5.10.0 pela sua versão do Perl.)

Na linha 55 (ou cercanias), você encontrará algo parecido com:
my $sth = $self->{dbh}->prepare_cached(q{SELECT GET_LOCK(?, 3600)}, {}, 1);

Modifique o timeout de 3600 segundos(1 hora) para um segundo e voilà, seu Apache::Session não travará mais quando utilizar MySQL para locking.

Utilize este hack apenas em ambiente de desenvolvimento. Não aplique esta modificação em ambiente de produção caso não tenha certeza absoluta do que está fazendo.


 

31/10 de 2009

Acompanhe o clima e várias partes dos EUA em animações feitas em linguagem Perl

Categoria: Perl — jfonseca @ 11:42 pm

Conheça o Marquito’s Weather, um site escrito em Perl que fornece gráficos, mapas e textos de avisos sobre o clima em diversas regiões dos Estados Unidos. Infelizmente não parece ter dados da América do Sul, fica mais como curiosidade para programadores.

O sistema de avisos em texto utilizado por navegantes é realmente interessante, confira ao fundo da página.

Exemplo:

Expires:No;;450138
ABNT20 KNHC 010100
TWOAT
TROPICAL WEATHER OUTLOOK...CORRECTED
NWS TPC/NATIONAL HURRICANE CENTER MIAMI FL
800 PM EDT SAT OCT 31 2009
FOR THE NORTH ATLANTIC...CARIBBEAN SEA AND THE GULF OF MEXICO...
CORRECTED TO ADD REFERENCE TO HIGH SEAS FORECAST
A NON-TROPICAL GALE CENTER IS LOCATED ABOUT 850 MILES EAST-SOUTHEAST
OF BERMUDA. THIS LOW COULD SLOWLY ACQUIRE SOME SUBTROPICAL
CHARACTERISTICS AS IT BEGINS TO MOVE NORTHWESTWARD AND THEN
NORTHWARD OVER THE NEXT COUPLE OF DAYS. THERE IS A LOW CHANCE...
LESS THAN 30 PERCENT...OF THIS SYSTEM BECOMING A SUBTROPICAL CYCLONE
DURING THE NEXT 48 HOURS. FOR ADDITIONAL INFORMATION ON THIS
SYSTEM...REFER TO HIGH SEAS FORECASTS ISSUED BY THE NATIONAL
WEATHER SERVICE UNDER AWIPS HEADER NFDHSFAT1 AND WMO HEADER FZNT01
KWBC.
ELSEWHERE...TROPICAL OR SUBTROPICAL CYCLONE FORMATION IS NOT
EXPECTED DURING THE NEXT 48 HOURS.
$$
FORECASTER BRENNAN

Confira o clima em Houston, Texas por exemplo.

Visite aqui: Marquito’s Weather


 

18/5 de 2009

Programando o Twitter em Perl com Zen::Twitter

Categoria: Perl,Programação,Twitter — jfonseca @ 12:24 pm

Há alguns dias finalmente cliquei no link “API” que está no fim de praticamente todas as telas do Twitter. Descobrí que programar o Twitter é tão simples quanto usá-lo! Eis que a estratégia de ultra-simplicidade do portal se repete na API de web services(REST) do Twitter:
- O esquema de autenticação é o mais antigo da Web, via Basic Auth. Em resumo, Basic Auth é um campo no cabeçalho que concatena usuário:senha, codificados com Base64 para evitar caracteres reservados ao HTTP.
- As chamadas são GET, POST ou DELETE. Normalmente as consultas a dados usam GET e as atualizações POST – provavelmente porque o POST não tem limite de tamanho nos dados enviados, ao contrário do GET.
- Diferente de web services “pesados” como SOAP, cada URI é ligado a apenas um método/função. Então para ver os últimos 20 “Twits”(?) em todo o Twitter, você pode verificar, inclusive, via navegador. Clique aqui para ver um exemplo em XML simples.

Comecei a implementar algumas chamadas em modulos Perl individuais, e quando menos percebí já estava criando objetos para o Usuario(Zen::Twitter::User), para atualizações de usuários(Zen::Twitter::UserStatus), modulos para cada grupo de funções relacionadas, e por aí vai. Empacotei tudo no Zen Twitter Tools e acrescentei scripts de demonstração para cada função da biblioteca Zen::Twitter.

2009-05-18 – Versão 0.10 da biblioteca Zen::Twitter

Esta versão suporta os seguintes módulos:

  • Search
  • Timeline
  • Status
  • User
  • Direct Message
  • Friendship
  • Social Graph
  • Account
  • Favorite
  • Notification
  • Block
  • Help

Cada serviço está descrito, detalhadamente, no Wiki de documentação Twitter.

Gerência de Conta Twitter
account_rate_limit_status.pl – Verificar quantos créditos de API ainda tem restantes por horário, e horário da próxima zeragem
account_update_delivery_device.pl – Atualiza dispositivo móvel onde deseja receber notificações.
account_update_profile_color.pl – Atualiza cores do seu perfil.
account_update_profile.pl – Atualiza dados do seu perfil como email, localização, URL, etc
account_verify_credentials.pl – Testa os dados em credentials.xml(veja documentação para obter detalhes)

Gerência de Bloqueios
block_blocking.pl – Listar usuários que você atualmente bloqueia.
block_create.pl – Bloquear um usuário
block_destroy.pl – Desbloquear um usuário
block_exists.pl – Verifica se você está atualmente bloqueando um usuário.
block_ids.pl – Lista todos os IDs de usuários que você está bloqueando

Mensagens Diretas
direct_message_destroy.pl – Apagar uma mensagem direta
direct_message_send.pl – Envia uma mensagem direta
direct_messages.pl – Listar mensagens diretas na caixa de entrada
direct_messages_sent.pl – Listar mensagens diretas enviadas

Gerência de Favoritos
favorite_create.pl – Adicionar um status a seus favoritos
favorite_destroy.pl – Remover um status de seus favoritos
favorites.pl – Listar seus favoritos

Amigos e Seguidores
followers_not_friends.pl – Lista quais seguidores você ainda não segue
friendship_create.pl – Seguir um usuário / Follow
friendship_destroy.pl – Deixar de seguir um usuário
friendship_exists.pl – Verifica se usuario_a segue o usuario_b
friends_not_followers.pl – Lista quais amigos você segue que não te seguem ainda.
friends_timeline.pl – Últimos 20 status/atualizações de seus amigos.
mentions.pl – Últimas 20 menções a @você
public_timeline.pl – As últimas 20 atualizações em todo o Twitter, atualizadas a cada 60 segundos.

Notificações Móveis
notification_follow.pl – Passar a receber notificações moveis quando um usuário atualizar status.
notification_leave.pl – Deixar de receber notificações moveis quando um usuario atualizar seu status.

Buscas
search.pl – Interface de linha de comando para o sistema de buscas do Twitter. Exemplo: perl search.pl dire straits

Grafo Social
socialgraph.pl – Contagem simples de amigos e seguidores.

Status
status_destroy.pl – Apaga uma de suas atualizações
status_show.pl – Mostra o status de um usuário.
status_update.pl – Atualiza seu status(esta é a função principal do Twitter).

Ajuda
test.pl – Testa comunicação com servidores do Twitter. Apenas envia um pedido nulo e recebe um OK.

Usuários
user_timeline.pl – Recebe as atualizações de um usuário em ordem cronológica, é como visitar em http://twitter.com/USUARIO
user.pl – Mostra o status atual(ultima atualização) e dados gerais de um usuário específico.

Exemplos de Scripts
Cada função da biblioteca possui um script relacionado para demonstrar sua utilização, assim você pode modificá-los e criar suas próprias aplicações. Os scripts de demonstração também podem ser usados para gerenciar sua conta. Todas as funções que exigem usuário/senha utilizarão a configuração presente em credentials.xml. Edite esse arquivo e inclua seus dados de acesso para obter acesso a toda a funcionalidade do Twitter.

Não implementado na v. 0.10
- Tendências de buscas, visto que só possuem versões JSON o que não é muito útil em Perl
- Upload de imagem para o perfil e imagem de fundo do perfil.
- Função de “sign off”(sair do sistema). Em ambiente de linha de comando não temos por que apagar cookies e session.

Como Baixar o Zen Twitter Tools: zen-twitter-tools-0.10.tar.gz

A documentação dos módulos serve apenas para orientar seu uso, não é, de maneira alguma, documentação com o padrão de qualidade do CPAN. Acho que a funcionalidade do Twitter é simples o suficiente para que a biblioteca seja usada sem problemas.


 

16/3 de 2009

Solucionando Segmentation fault no Apache 1.3.41 + mod_perl-1.30 e perl-5.10

Categoria: Dicas para Webmasters,Linux,Perl — jfonseca @ 8:36 pm

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.


 

17/2 de 2009

Tabela periódica de operadores Perl 6

Categoria: Perl — jfonseca @ 10:31 am

A seção de programação do Reddit.com costuma ser a mais útil entre os sites de notícias sociais. Todos os dias procuro algo novo e interessante para aprender por lá.

Eis que hoje me deparei com uma verdadeira pérola: uma tabela periódica dos operadores Perl 6, inspirada numa palestra ministrada por Larry Wall(criador da linguagem).

Tabela periódica de operadores Perl 6

Tabela periódica de operadores Perl 6

É uma verdadeira obra de arte, clique aqui para conferir.


 

27/5 de 2008

Perl: Cuidado ao atualizar o DBD::mysql para versão 4.007

Categoria: Dicas para Webmasters,Perl — jfonseca @ 1:51 pm

Tem 25 horas que estou tentando descobrir por que o servidor Apache decidiu gerar falhas de segmentação e derrubar o serviço aparentemente sem motivos. Ontem, na maior tranquilidade, atualizei a minha biblioteca CPAN, rodei a rotina de sempre:
# cpan
cpan> install Bundle::CPAN
cpan> install Bundle::LWP
cpan> install DBI
cpan> install DBD::mysql
cpan> install Apache::SessionX

E por aí vai….são 20 módulos que atualizo sempre.

O que me passou desapercebido foi o upgrade do driver MySQL do 4.006 para 4.007. O próprio número de versão, lá na casa dos milésimos, indica uma versão de atualização simples, que não deveria causar maiores transtornos. Eu não poderia estar mais errado.

Logo que atualizei, reiniciei o Apache para reler as bibliotecas do Perl. Como atualizei centenas de módulos(nos Bundle::CPAN e Bundle::LWP), não desconfiei do DBD::mysql de início.

Verificava o log do httpd pai, e, desde ontem de manhã, eis o que encontrava:
[Tue May 27 06:01:16 2008] [notice] child pid 14013 exit signal Segmentation fault (11)
[Tue May 27 06:01:47 2008] [notice] child pid 13698 exit signal Segmentation fault (11)
[Tue May 27 06:02:04 2008] [notice] child pid 13678 exit signal Segmentation fault (11)
[Tue May 27 06:56:07 2008] [notice] child pid 13999 exit signal Segmentation fault (11)
[Tue May 27 06:57:28 2008] [notice] child pid 14000 exit signal Segmentation fault (11)
[Tue May 27 06:58:10 2008] [notice] child pid 14004 exit signal Segmentation fault (11)
[Tue May 27 06:59:48 2008] [notice] child pid 14008 exit signal Segmentation fault (11)
[Tue May 27 07:00:17 2008] [notice] child pid 14002 exit signal Segmentation fault (11)

Esses aí já são de hoje, à partir de 6 AM…. (Vida de programador não é mole…mais uma noite virada….)

Então comecei a luta pra encontrar a biblioteca que causava o SEGFAULT. Baixei o MySQL novo e compilei, em seguida recompilei o Apache com mod_perl 1.29 para buscar a nova versão de libmysqlclient.so.16 ao invés de .so.15, reinstalei o DBD::mysql para linkar com a nova versão, porém as falhas de segmentação continuavam. Volto tudo atrás, retorno ao MySQL 5.0.51a e reinstalo as bibliotecas. Recompilo o PHP para linkar com as .so.15 e também o DBD::mysql. Só nisso se foram 40 minutos, e a cada erro me custava quase uma hora.

Em seguida baixei o Apache 1.3.41, recompilei e nada de solucionar….
Recompilei o Apache com e sem o mod_gzip.c e nada…
Instalei o Apache com e sem o PHP 5.2.4 e nada….
Recompilei com e sem o mod_ssl e nada…
Atualizei as versões das bibliotecas linkadas ao PHP, Freetype, GD….nada…

Começou a bater o desespero….nunca tinha visto um caso desses. Cismei que era sistema de arquivos corrompido, me deu frio na barriga de pensar em atualizar a libc com apenas acesso SSH remoto….um erro e já era. Não arrisquei. Dei um reboot e torcí pra não ser problema de disco….

Coloquei um ping para monitorar quando o servidor voltasse à vida….em alguns instantes tenho o retorno:

64 bytes from ……

Maravilha…o reboot funcionou. Verifico os logs do Apache e os Segmentation Fault continuam lá….

Já eram 5 AM quando decidí começar tudo do zero, a lógica diz que se eu não errar nada no caminho então a pane é de hardware. Não deu pra consertar do modo rápido, então vamos pela força bruta!

Aumentei o nível de debug do Apache sem qualquer resultado, até que cheguei à conclusão que seria inevitável enfiar a mão na massa e ir atrás do stack trace do httpd até achar a chamada que estava acessando memória não autorizada. Lá vamos nós….

Primeiro precisamos compilar o Apache com os símbolos para debug. Só há vantagem em tirar os símbolos de binários compilados se você quiser ocultar o sistema de engenheiros reversos ou tornar o binário alguns bytes menor. No caso do Apache não estamos preocupados com isso, e hoje em dia esbanjamos discos rígidos de 1 Terabyte. Então precisamos adicionar a flag -g ao gcc e recompilar tudo….

# cd apache_1.3.41
# vi configure
Vá até as cercanias da linha 282:
:282
Antes da linha “for var in CFLAGS LDFLAGS LIBS INCLUDES DEPS; do”
Adicione
CFLAGS=-g

Rode o
# ./configure

No meu caso eu utilizo o Makefile.PL do mod_perl assim:

# cd ../mod_perl-1.29/
# perl Makefile.PL USE_APACI=1 APACHE_SRC=../apache_1.3.41/src DO_HTTPD=1 USE_APACI=1 EVERYTHING=1 APACI_ARGS=’–prefix=/usr/local/apache/ –activate-module=src/modules/php5/libphp5.a –enable-module=so –enable-module=ssl –enable-module=rewrite’

Compilar:
# make
# make install

OK, 2 minutos depois e temos um novo httpd em /usr/local/apache/bin/httpd

Agora que temos um httpd recheado de símbolos, vamos dizer ao Apache onde jogar os core dumps.

Edite o seu httpd.conf:
# vi /usr/local/apache/conf/httpd.conf

Adicione :
# 2008-05-27 problema com segmentation fault
CoreDumpDirectory /usr/local/apache/coredump/

Salve(no vi é com :wq!) e reinicie o Apache

# /usr/local/apache/bin/apachectl restart

( Veja a linha antes de CoreDumpDirectory, a deixei lá de propósito. É sempre bom comentar as alterações para, no futuro, você lembrar que nesse dia você apanhou um bocado ;) . Falando sério: hoje você lembra por que editou o httpd.conf, mas daqui a 6 meses você talvez fique na dúvida de por que a diretiva de core dumps está alí. Por via das dúvidas, comente seus arquivos de configuração. Eu utilizo sempre o mesmo formato de datas aaaa-mm-dd para poder fazer buscas no futuro por anos ou meses aproximados. )

Agora aguarde o servidor cair! No meu caso foi quase instantâneo. Vou até o diretório de core dumps e não encontro qualquer arquivo core apesar das falhas repetidas do servidor…. São os efeitos da falta de sono, esquecí de permitir os core dumps aumentando o ulimit -c. Como ulimit -c 0 os core dumps ficam desligados….

# ulimit -c 10240

Damos um ulimit de 10 MBytes para tamanho máximo de arquivos core. Agora reiniciamos o Apache, e não demora encontro lá os arquivos core.nnnn. Vamos examinar o core.1035 para ver onde foi a pane:

# gdb ../bin/httpd -c core.1035
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”…

[... um apanhado de saída, até chegar em ....]

Program terminated with signal 11, Segmentation fault.
[New process 1045]
#0 0x084b739c in Perl_av_undef ()

OK, o que será que houve em Perl_av_undef() ??? Esse tempo todo desconfiando do MySQL e o culpado era o núcleo do Perl ???!

A julgar pelo nome, Perl_av_undef() parece ser uma rotina de limpeza(undef) de arrays(AV = Array Value). Sem mais chutes pesquiso no Google e descubro que não se trata de um bug do Perl e sim de uma limitação imposta pelo sistema através do ulimit. Quando o Perl tenta limpar uma estrutura de dados complexa, arrays de arrayrefs contendo referências a objetos ou hashrefs, por exemplo, ele pode gerar uma grande quantidade de chamadas recursivas. A recursividade é uma ferramenta poderosa, mas que às vezes deve ser substituída por outras técnicas para poupar a pilha. A recursividade é quase sempre uma saída elegante, porém nem sempre a mais eficiente. A cada chamada o Perl empilha mais valores na stack, eventualmente estourando a pilha e causando uma Segmentation Fault(sinal 11). Quem derruba o programa é o próprio kernel, e isso não é um bug, é uma característica de sistemas que impedem processos de levarem a máquina toda consigo no caso de perda de controle.

Então vamos verificar o tamanho atual da pilha. Vamos aproveitar e verificar outros valores-limite para sabermos em que chão estamos pisando.

#ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 16253
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 16253
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Temos uma pilha de 10 MBytes, o que nem sempre é suficiente. Vamos exagerar um pouco para testar nossa tese, se aumentarmos para 100 MBytes teremos a chance de ver se os core dumps deixam de acontecer.

# ulimit -s 102400

Verificamos se deu certo com:

# ulimit -s
102400

OK, temos 100 MB autorizados pro Perl fazer a festa na pilha. Vamos reiniciar o Apache e ver se funciona.

# /usr/local/apache/bin/apachectl stop
# /usr/local/apache/bin/apachectl start

Prefiro o stop e start explícitos quando estou testando, para eliminar a possibilidade de alguma memória permanecer alocada do processo anterior. Pode ser só paranóia, mas vamos adiante. Temos que aguardar alguns instantes para testar a estabilidade do novo ambiente que demos ao Apache.

OK, após 5 minutos verifico que os Segmentation Faults continuam acontecendo…só que, conforme veremos, desta vez o culpado não é mais o Perl_av_undef()

Vamos examinar um dos novos arquivo core.nnnn para tentar descobrir quem é o culpado desta vez.

# gdb /usr/local/apache/bin/httpd -c core.1047
[... cortado ...]
Program terminated with signal 11, Segmentation fault.
[New process 1047]
#0 0x00b9e46b in mysql_ping () from /usr/local/mysql//lib/mysql/libmysqlclient.so.15

Opa! mysql_ping() ….estamos voltando ao principal suspeito, desde o início o servidor caía perto de alguma chamada ao MySQL no código Perl. Vamos ver o que ocorre logo antes do mysql_ping() usando o comando where do gdb.

(gdb) where
#0 0x00b9e46b in mysql_ping () from /usr/local/mysql//lib/mysql/libmysqlclient.so.15
#1 0x004d99f2 in XS_DBD__mysql__db_ping (cv=0x94d2680) at mysql.xs:519
#2 0x001edbf4 in XS_DBI_dispatch () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/DBI/DBI.so
#3 0x084bfa43 in Perl_pp_entersub ()
#4 0x084be32e in Perl_runops_standard ()
#5 0x084ba15d in Perl_call_sv ()
#6 0x0043ae8f in EMBPERL2_CallStoredCV () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#7 0x00453cf0 in embperl_Execute () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#8 0x0045a008 in ProviderEpRun_GetContentIndex () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#9 0x0045891a in Cache_GetContentIndex () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#10 0x00434a63 in ProcessFile () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#11 0x004355da in embperl_RunRequest () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#12 0x00435b8c in embperl_ExecuteRequest () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#13 0x0043233f in XS_Embperl__Req_ExecuteRequest () from /usr/lib/perl5/site_perl/5.10.0/i686-linux/auto/Embperl/Embperl.so
#14 0x084bfa43 in Perl_pp_entersub ()
#15 0x084be32e in Perl_runops_standard ()
#16 0x084ba15d in Perl_call_sv ()
#17 0x08371d3b in perl_call_handler (sv=0x96a8d20, r=0x9541c14, args=0×0) at mod_perl.c:1668
#18 0x083723f9 in perl_run_stacked_handlers (hook=0x85ef03b “PerlHandler”, r=0x9541c14, handlers=0x96a8cb0)
at mod_perl.c:1381
#19 0×08373861 in perl_handler (r=0x9541c14) at mod_perl.c:904
#20 0×08395497 in ap_invoke_handler (r=0x9541c14) at http_config.c:476
#21 0x083acd2f in process_request_internal (r=0x9541c14) at http_request.c:1299
#22 0x083ad1a0 in ap_internal_redirect (new_uri=0x951427c “/index.html”, r=0x9512ae4)
at http_request.c:1440
#23 0x00386fe4 in mod_gzip_redir1_handler () from /usr/local/apache/modules/mod_gzip.so
#24 0×00385219 in mod_gzip_handler () from /usr/local/apache/modules/mod_gzip.so
#25 0×08395497 in ap_invoke_handler (r=0x9512ae4) at http_config.c:476
#26 0x083acd2f in process_request_internal (r=0x9512ae4) at http_request.c:1299
#27 0x083acd8c in ap_process_request (r=0x9512ae4) at http_request.c:1315
#28 0x083a2ef6 in child_main (child_num_arg=12) at http_main.c:4971
#29 0x083a3227 in make_child (s=0x87be05c, slot=12, now=1211894763) at http_main.c:5150
#30 0x083a32c2 in startup_children (number_to_start=23) at http_main.c:5178
#31 0x083a3a66 in standalone_main (argc=3, argv=0xbfe95934) at http_main.c:5525
#32 0x083a434f in main (argc=3, argv=0xbfe95934) at http_main.c:5883

Lendo de baixo pra cima, o where nos dá um trace de pilha completo desde a função main() até o mysql_ping().

Sem mais demora, jogo a consulta no Google e o resultado é que mais alguém acaba de ter o mesmo problema há apenas 1 semana!

E o culpado é???? O DBD::mysql v. 4.007, que foi um dos primeiros módulos que atualizamos no servidor de produção ainda ontem! Confira o report do bug MySQL clicando aqui.

Solução: regredir para a versão 4.006. Como fazer isso se o CPAN sempre busca a última versão? É simples.

Vá até a página do DBD::mysql no endereço http://search.cpan.org/dist/DBD-mysql/.

Na caixa “Other Releases” escolha a versão anterior(4.006) e clique em Goto.

Quando a página recarregar, o link Download apontará para a versão escolhida. Baixe-a, extraia com

# tar xzvf DBD-mysql-4.006.tar.gz
# cd DBD-mysql-4.006
# perl Makefile.PL
# make
# make install
Reinicie o Apache para ler o DBD::mysql antigo
# /usr/local/apache/bin/apachectl restart

E, pelo menos até o momento, os problemas de segmentação acabaram.

Conclusões

1) Os módulos de um servidor que se propõe a ser padrão industrial tem que ser melhor testados. O bug é crasso, é primário. O módulo tenta executar um mysql_ping() e derruba o processo todo. A MySQL, recém comprada pela Sun, vai ter que efetuar um controle de qualidade mais eficiente.

2) O apache 1.3 está sendo lentamente abandonado, porém ele poderia ter um sistema de gerenciamento de erros mais “civilizado”. Ninguém tem o luxo de passar 20 horas no GNU Debugger verificando stack traces, recompilando programas gigantescos e tentando montar quebra-cabeças.

3) Não confie cegamente em updates. Efetue um update de cada vez e teste o sistema novamente. Se eu tivesse testado o sistema após o update do DBD::mysql, ao invés de atualizar o CPAN todo, eu saberia que o culpado era o DBD::mysql. Nunca tinha tido problemas com um módulo do CPAN, por isso deduzí logo se tratar de algum conflito de bibliotecas compartilhadas.

4) Aumente a pilha para processos que irão rodar durante longos períodos. Apenas 10 MB de pilha para servidores Apache, MySQL ou Oracle é muito pouco. Vimos que o DBD::mysql não era o único culpado pelos Segmentation Faults do Apache. Aumentei o ulimit da pilha para 204800 KBytes(200 Megas) para garantir.

5) Problemas entrelaçados, como a stack pequena e o bug do MySQL combinados, podem causar muita confusão. Quem imaginaria que os 2 ocorreriam ao mesmo tempo e se manifestariam da mesma forma?! As mensagens no log são idênticas, não há diferença. Se não tivesse me dado o trabalho de compilar o Apache com símbolos e estudado o stack trace no gdb, eu pensaria que os primeiros core eram problema do MySQL. Aliás, durante boa parte da resolução do problema eu achava que as bibliotecas MySQL eram as únicas culpadas.

Já faz 1 hora e 30 minutos que restabelecí o serviço e não vejo qualquer SEGFAULT registrado. Agora vem a parte difícil, explicar pra minha chefe tudo isso…..


 

23/4 de 2008

Resumo justo, isento e imparcial das principais linguagens de programação

Categoria: Perl — jfonseca @ 4:04 am

Todo programador sonha em criar uma linguagem de programação, e muitos assim o fazem. Algumas linguagens se mostram expressivas, práticas e, portanto, úteis. Essas linguagens se chamam Perl.

A seguinte tabela lógica(de verdades) resume o que há em termos de linguagens no mercado hoje.

Linguagem de Programação = Perl
C = pai do Perl, veterano de 65535 guerras(0 derrotas)
Máquina Virtual = Mustang 1966 conversível
C++ = C cheio de encrenca
(leia mais…)


 

18/1 de 2008

Aniversário : Vinte anos da linguagem Perl!

Categoria: Perl — jfonseca @ 10:49 pm

Larry Wall, criador da linguagem PerlHá 20 anos, Larry Wall dava ao mundo sua maior contribuicão em software : nascia a linguagem Perl. Quem programa sistemas Unix sabe que há um certo senso de comunidade nesse ramo. Os programadores Unix se unem em torno de projetos, mesmo que isso não lhes renda um centavo de lucro. O sistema operacional Linux, o servidor Apache(e outros projetos da fundacão Apache) e vários outros projetos nasceram desse grupo de hackers(no sentido correto da palavra hacker).

Larry Wall é mais que um hacker comúm vindo do mundo Unix.

Especialista em linguística e exímio programador, Wall decidiu pegar todas aquelas pequenas ferramentas de manipulacão de texto que ele utilizava no ambiente Unix e recriá-las organizadamente para terminar um trabalho de geracão de relatórios que lhe foi delegado por seu patrão na época.

O resultado foi um sistema para automatizar a saída de centenas, milhares de páginas listradas de relatórios em barulhentas impressoras matriciais. Para isso era preciso fixar as colunas, extrair e tabular os dados de alguma fonte, preparar o formato e jogar a saída no dispositivo correto. O resultado foi a Linguagem Prática de Extracão e Relatórios, no inglês PERL.

Diz a lenda que Larry Wall trabalhou no projeto Guerra nas Estrelas do governo de Ronald Reagan. Tenho certeza que o software desse projeto era impecável, porém não podemos dizer o mesmo do resto do SDI(o nome formal do Guerra nas Estrelas era “Strategic Defense Initiative”) visto que Reagan jogou fora trilhões de dólares e o sistema é incapaz de interceptar um mosquito de Febre Amarela. Esse tipo de projeto era onde havía bom dinheiro para programadores nos EUA nos anos 1980. Os melhores programadores da época eram ligados à area militar seja pelo trabalho com criptografía e área-fim do Pentágono ou para desenvolvimento de sistemas administrativos. Segundo diversos especialistas, era assim também na URSS.

Enfim, foi nesse contexto que nasceu a linguagem Perl. O espírito da comunidade Unix foi preservado, e configura a maior vantagem dessa linguagem sobre tantas outras. As bibliotecas Perl são todas abertas e disponíveis para qualquer desenvolvedor. São centenas de milhares de módulos que fazem de tudo o que você imaginar.

Nos Estados Unidos há mais de uma usina nuclear que utiliza Perl em seus sistemas de controle, o Yahoo e o Google utilizam Perl em diversos sistemas de grande porte, os livros de Perl aparecem entre os mais vendidos de informática de vez em quando na Amazon e por aí vai. Tudo isso comecou há 20 anos com o trabalho de um generoso programador que doou sua contribuicão ao mundo.


  Proxima Pagina »