Durante minha vida profissional pude observar muitas análises ruins quando se está tentando determinar a causa raiz de um problema. O x da questão usualmente não é a qualidade técnica do profissional, mas sim a metodologia adotada detalhar a situação para se criar uma linha de eventos válida, somada a uma frequentemente falta de paciência em varrer os logs e analisar com calma as evidências.
Pensando nisso eu escrevi um pequeno passo a passo para uma identificação de causa raia que fiz em uma instância do DB2 que uso para meus testes, onde sem querer esbarrei em um bug do DB2. Espero que sirva como um bom exemplo de análise, independente do produto que você trabalha.
Cenário: em meu ambiente de laboratório eu notei que uma instância do DB2 recorrentemente parava de funcionar na madrugada, sendo necessário um db2start para coloca-la operacional.
Como fiz a análise...
1. Partindo de um momento perto do horário em que o serviço foi interrompido analisa-se o diaglog, onde encontro uma entrada muito importante:
2014-03-26-00.43.45.477605-180 I38149015A601 LEVEL: Error
PID : 9475 TID : 4383345469712 PROC : db2sysc 0
INSTANCE: db2inst1 NODE : 000 DB : HCOREDB
APPHDL : 0-10765 APPID: *LOCAL.db2inst1.140326052243
AUTHID : DB2INST1 HOSTNAME: db2luti
EDUID : 5674 EDUNAME: db2agent (HCOREDB) 0
FUNCTION: DB2 UDB, base sys utilities, sqleagnt_sigsegvh, probe:1
MESSAGE : Error in agent servicing application with coor_node:
DATA #1 : Hexdump, 2 bytes
0x000003FC9380996C : 0000
2. Em seguida começamos a ver diversas entradas no diretório do FODC (First Ocurrence Data Capture). Analisando o diretório FODC temos N diretórios com o timestamp do trap, o de nosso interesse é FODC_Trap_2014-03-26-00.43.45.300571_0000.
3. Neste diretório temos diversos artefatos que foram gerados, mas para essa análise o que nos interessa é o arquivo com trap, que é um snapshot do estado do DB2 quando o stack dump foi capturado (*.trap.txt).
a. Neste caso foi gerado o 9475.5674.000.trap.txt;
b. Notem o PID e EDUID destacados no diaglog, o nome do arquivo do trap é iniciado pelo process ID do db2sysc no Linux e o EDU ID do agente;
4. O arquivo do trap tem diversas informações, entre elas a stack que fica um pouco chata de ler por conta dos nomes gerados pelo compilador. Então para analisar o arquivo e limpar o nome dos métodos, peçam ajuda ao c++filt:
cat 9475.5674.000.trap.txt | c++filt | less
a. Signal #11 Indica um erro inesperado (9 é o SIGKILL, 2 é o SIGINT, etc..;)
Signal #11 (SIGSEGV): si_addr is 0x000003FC2640A000, si_code is 0x00000002 (SEGV_ACCERR:Invalid permissions for mapped object.)
b. A entrada <POFDisassembly> (POF = Point Of Failure) é o método que estava sendo executado quando o problema aconteceu.
<POFDisassembly>
sqldHashZValue32(int, sqlz_value**, sqld_sortkey**) + 0x0116 (/home/db2inst1/sqllib/lib64/libdb2e.so.1)
c. Isso já dá um ótimo filtro de pesquisa no Google ou Bing, tentem: db2 10.1 “sqldHashZValue32”
i. De cara a primeira saída é interessante: http://www-01.ibm.com/support/docview.wss?uid=swg1IC92798 (IC92798: RUNNING MULTIPLE CONCURRENT SAMPLED DETAILED INDEX RUNSTATS MIGHT CAUSE A SERVER ABEND OR INACCURATE INDEX STATISTICS)
d. Na APAR temos o detalhamento do problema e stack trace de interesse:
sqloEDUCodeTrapHandler
sqldHashZValue32
sqlis_touch_page
sqliProcessColStats
sqlischs
sqlistat
sqldIndexStats
sqlrLocalRunstats
e. Para garantir que se trata do mesmo problema, vamos comparar a stack no arquivo de trap:
0x000003FFFAAC4888 sqloEDUCodeTrapHandler + 0x0250 (/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FC93809DF0 address: 0x3fc93809df0
0x000003FFF8BB97D6 sqldHashZValue32(int, sqlz_value**, sqld_sortkey**) + 0x0116
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFBFC8A92 sqlis_touch_page(unsigned long, schs_cluster_data*) + 0x00ca
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFBFB0C46 address: 0x000003FFFBFB0C46 ; dladdress: 0x000003FFF74C9000 ; offset in lib: 0x0000000004AE7C46 ;
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFBFB5B32 sqliProcessColStats(schs_data*, SQLI_CB*, unsigned int*) + 0x052e
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFBFB7314 sqlischs(SQLI_CB*, SQLD_ISTAT*, SQLD_CSTAT*, SQLD_TSTAT*, schs_data*, int) + 0x0e4c (/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFC143CF2 sqlistat(sqeAgent*, SQLD_CCB*, unsigned int, SQLD_IXCB*, SQLD_ISTAT*, SQLD_CSTAT*, SQLD_TSTAT*) + 0x100e
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFF8CBA094 sqldIndexStats(sqeAgent*, unsigned short, unsigned short, unsigned char, unsigned short, int, unsigned int, SQLD
_ISTAT*, SQLD_TSTAT*, char*, int, char*, int, unsigned int, bool&) + 0x0b58
(/home/db2inst1/sqllib/lib64/libdb2e.so.1)
0x000003FFFAF28004 sqlrLocalRunstats(sqlrr_cb*, sqlrrstring*, sqlrrstring*, sqlrrstring*, ….
f. Coincidência? A APAR diz que o problema foi corrigido no fix pack 3, e qual a nossa situação.
Ø db2level
db2inst1@db2luti:/db2/db2inst1/diaglog> db2level
DB21085I This instance or install (instance name, where applicable: "db2inst1") uses "64" bits and DB2 code release "SQL10012" with level identifier "0203010E".
Informational tokens are "DB2 v10.1.0.2", "s121127", "IP23396", and Fix Pack "2".
g. Analisando a CRONTAB do servidor db2luti temos um agendamento marcado para executar todos os dias exatamente 00:43h. Que bate exatamente com o timestamp do diaglog (00.43.45.477605).
43 00 * * * /home/db2inst1/scripts/runstats.ksh hcoredb
43 00 * * * /home/db2inst1/scripts/runstats.ksh hcoredb1
43 00 * * * /home/db2inst1/scripts/runstats.ksh hcoredb2
43 00 * * * /home/db2inst1/scripts/runstats.ksh hcoredb3
43 00 * * * /home/db2inst1/scripts/runstats.ksh hcoredb4
Conclusão
O agendamento que eu criei para testar variações da rotina de runstats é executada em cinco bancos de dados no mesmo horário, o que nos coloca no cenário do bug. Como paliativo podemos alterar o agendamento, mas a solução definitiva é aplicar o Fix Pack 3 do DB2.
Claro que a análise em si levou mais tempo, pois foi necessário varrer em maior detalhe o diaglog, correlacionar eventos, analisar a APAR, entre outros. É esse cuidado que muitos não têm e como resultado são feitas análise incorretas, onde já vi sugestão de se aplicar fix em que a mensagem de erro é igual, mas com uma stack totalmente diferente, o que significa não se tratar do mesmo problema.
Para quem está procurando material de referência, infelizmente não tenho um link específico, mas participei de um bom seminário em 2013 no IDUG em Barcelona (http://www.idug.org/emea2013) chamado “DB2 LUW Problem Determination and Troubleshooting Workshop”, com o Pavel Sustr e Samir Kapoor. Eles estarão presentes no IDUG 2014 em Phoenix (que acontecerá agora me Maio), então se estiverem por lá eu recomendo participar deste workshop de um dia.
Espero que o exemplo seja útil, não para esse caso em si, mas para ilustrar um pouco a prática na análise de problemas. Espero postar aqui mais casos de análise.
Abraços,
sr. Nimbus Serviços em Tecnologia - www.srnimbus.com.br
Nenhum comentário:
Postar um comentário