Vários Métodos de Debugging no OpenResty

API7.ai

December 16, 2022

OpenResty (NGINX + Lua)

No grupo de comunicação do OpenResty, os desenvolvedores frequentemente fazem esta pergunta: Como depurar no OpenResty? Até onde eu sei, existem algumas ferramentas no OpenResty que suportam depuração com pontos de interrupção, incluindo um plugin no VSCode, mas elas não são amplamente utilizadas até o momento. Incluindo o autor agentzh e alguns contribuidores que conheço, todos usam o mais simples ngx.log e ngx.say para fazer depuração.

Isso não é amigável para a maioria dos iniciantes. Isso significa que os muitos mantenedores principais do OpenResty têm apenas o método primitivo de imprimir logs quando encontram um problema difícil?

Claro que não. No mundo do OpenResty, SystemTap e o gráfico de chamas são as ferramentas padrão para lidar com problemas difíceis e questões de desempenho. Se você tiver uma dúvida sobre isso em uma lista de discussão ou issue, o mantenedor do projeto pedirá que você envie um gráfico de chamas e solicitará uma descrição gráfica em vez de textual.

Nos próximos dois artigos, vou falar com você sobre depuração e o conjunto de ferramentas que o OpenResty criou especificamente para depuração. Hoje vamos começar vendo o que está disponível para depurar programas.

Pontos de interrupção e impressão de logs

Por muito tempo no meu trabalho, eu dependia dos recursos avançados de depuração do IDE (ambiente de desenvolvimento integrado) para rastrear programas, o que parecia natural. Para problemas que podem ser reproduzidos em um ambiente de teste, não importa o quão complexos, tenho confiança de que posso chegar à raiz do problema. A razão é que o bug pode ser reproduzido repetidamente, e a causa pode ser encontrada configurando pontos de interrupção e imprimindo logs. Tudo o que você precisa é de paciência.

Desse ponto de vista, resolver bugs que ocorrem de forma estável em um ambiente de teste é um trabalho físico. A maioria dos bugs que resolvo no meu trabalho se enquadra nessa categoria.

No entanto, observe que há dois pré-requisitos: um ambiente de teste e reprodução estável. A realidade é sempre menos do que ideal. Se o bug só for reproduzido no ambiente de produção, há uma maneira de depurá-lo?

Aqui eu recomendo uma ferramenta - Mozilla RR. Você pode usá-la como um repetidor, gravar o comportamento do programa e depois reproduzi-lo repetidamente. Para ser franco, independentemente do ambiente de produção ou de teste, desde que você possa gravar a "evidência" do bug, ela pode ser usada como "prova em tribunal" para analisar lentamente.

Algoritmo de busca binária e comentários

No entanto, para alguns projetos grandes, por exemplo, o bug pode vir de um dos vários serviços, ou pode haver um problema com a consulta SQL no banco de dados, nesse caso, mesmo que o bug possa ser reproduzido de forma estável, você não pode ter certeza de em qual parte o bug ocorreu. Então, ferramentas de gravação como Mozilla RR falham.

Nesse ponto, você pode se lembrar do clássico "algoritmo de busca binária". Primeiro, comentamos metade da lógica no código, e se o problema persistir, o bug está no código não comentado, então comentamos a metade restante da lógica e continuamos o loop. Dentro de algumas vezes, o problema é reduzido a um tamanho completamente gerenciável.

Essa abordagem pode parecer um pouco burra, mas é eficiente em muitos cenários. Claro, à medida que a tecnologia avança e a complexidade do sistema aumenta, recomendamos usar um padrão como OpenTracing para rastreamento distribuído.

O OpenTracing pode ser incorporado em várias partes do sistema e relatar a cadeia de chamadas e o rastreamento de eventos composto por vários Spans para o servidor através do Trace ID para análise e apresentação gráfica. Isso pode ajudar os desenvolvedores a encontrar muitos problemas ocultos, e os dados históricos serão salvos para que possamos compará-los e visualizá-los a qualquer momento.

Além disso, se o seu sistema for mais complexo, como em um ambiente de microsserviços, então Zipkin, Apache SkyWalking são boas escolhas.

Depuração dinâmica

Os métodos de depuração que descrevi acima são suficientes para resolver a maioria dos problemas. No entanto, se você encontrar uma falha que ocorre apenas ocasionalmente na produção, levará bastante tempo para rastreá-la adicionando logs e rastreamento de eventos.

Anos atrás, eu era responsável por um sistema que ficava sem recursos do banco de dados por volta das 1:00 da manhã todos os dias e causava uma avalanche em todo o sistema. Na época, verificamos as tarefas agendadas no código durante o dia, e à noite, a equipe esperava que o bug fosse reproduzido na empresa, e então verificava o status de execução dos submódulos quando ele era reproduzido. Não encontramos a causa do bug até a terceira noite.

Minha experiência é semelhante ao contexto de vários engenheiros do sistema Solaris que criaram o Dtrace. Na época, os engenheiros do Solaris também passaram dias e noites solucionando um problema estranho de produção, apenas para descobrir que era porque uma configuração estava escrita errada. Mas, ao contrário de mim, os engenheiros do Solaris decidiram evitar esse problema completamente e inventaram o Dtrace, especificamente para depuração dinâmica.

Diferente de ferramentas de depuração estática como GDB, a depuração dinâmica pode depurar serviços online. Todo o processo de depuração é não sensível e não intrusivo para o programa depurado, sem modificar o código, muito menos reiniciar. Para usar uma analogia, a depuração dinâmica é como um raio-X, que pode examinar o corpo do paciente sem a necessidade de coleta de sangue e gastroscopia.

Dtrace foi um dos primeiros frameworks de rastreamento dinâmico, e sua influência levou ao surgimento de ferramentas de depuração dinâmica semelhantes em outros sistemas. Por exemplo, os engenheiros da Red Hat criaram o Systemtap no Linux, que é o que vou falar a seguir.

Systemtap

Systemtap tem sua própria DSL, que pode ser usada para configurar pontos de sonda. Antes de entrarmos em mais detalhes, vamos instalar o Systemtap para ir além do abstrato. Aqui, basta usar o gerenciador de pacotes do sistema para instalar.

sudo apt install systemtap

Vamos ver como é um programa hello world escrito em Systemtap:

# cat hello-world.stp
probe begin
{
  print("hello world!")
  exit()
}

Não parece fácil? Você precisa usar privilégios de sudo para executar.

sudo stap hello-world.stp

Ele imprimirá o hello world!. Na maioria dos cenários, não precisamos escrever nossos próprios scripts stap para fazer a análise, porque o OpenResty já tem muitos scripts stap prontos para fazer a análise regular, e vou apresentá-los a você no próximo artigo. Então, hoje precisamos ter um breve entendimento dos scripts stap.

Depois de alguma prática, voltando ao nosso conceito, o Systemtap funciona convertendo o script stap acima para C e executando o compilador C do sistema para criar o módulo do kernel. Quando o módulo é carregado, ele ativa todos os eventos de sonda conectando-se ao kernel.

Por exemplo, begin será executado no início da sonda, e o correspondente end, então o programa hello world acima também pode ser escrito da seguinte maneira:

probe begin
{
  print("hello ")
  exit()
}

probe end
{
print("world!")

Aqui, eu só dei uma introdução muito superficial ao Systemtap. Frank Ch. Eigler, o autor do Systemtap, escreveu um e-book Systemtap tutorial que introduz o Systemtap em detalhes. Se você quiser aprender mais e entender o Systemtap profundamente, sugiro começar com este livro como o melhor caminho de aprendizado.

Outros frameworks de rastreamento dinâmico

Systemtap não é suficiente para engenheiros de análise de kernel e desempenho.

  1. Systemtap não entra no kernel do sistema por padrão.
  2. Ele funciona de uma maneira que é lento para inicializar e pode ter um impacto no funcionamento normal do sistema.

eBPF (extended BPF) é um novo recurso adicionado ao kernel do Linux nos últimos anos. Comparado ao Systemtap, eBPF tem as vantagens de suporte direto ao kernel, sem falhas e inicialização rápida. Ao mesmo tempo, ele não usa DSL, mas a sintaxe C diretamente, então é muito mais fácil de começar.

Além das soluções de código aberto, o VTune da Intel também é uma das melhores ferramentas. Sua interface intuitiva e apresentação de dados permitem que você analise os gargalos de desempenho sem escrever código.

Gráfico de Chamas

Finalmente, vamos relembrar o gráfico de chamas mencionado no artigo anterior. Como mencionamos anteriormente, os dados gerados por ferramentas como perf e Systemtap podem ser exibidos de forma mais visual usando o gráfico de chamas. O diagrama a seguir é um exemplo de um gráfico de chamas.

gráfico de chamas

No gráfico de chamas, a cor e a tonalidade dos blocos de cor são sem significado, apenas para fazer uma distinção simples entre diferentes blocos de cor. O gráfico de chamas é uma sobreposição dos dados amostrados cada vez, então os dados do usuário são a largura e o comprimento dos blocos.

Para o gráfico de chamas na CPU, a largura do bloco de cor é a porcentagem do tempo de CPU ocupado pela função: quanto mais largo o bloco, maior o dreno de desempenho. Se houver um pico achatado, é aí que está o gargalo de desempenho. O comprimento do bloco de cor, por outro lado, representa a profundidade da chamada da função, com o bloco superior mostrando a função em execução e todos os abaixo sendo chamadores dessa função. Então, a função abaixo é o supertipo da função acima: quanto mais alto o pico, mais profunda é a chamada da função.

Resumo

É essencial saber que mesmo uma técnica não intrusiva como o rastreamento dinâmico não é perfeita. Ele só pode detectar um processo individual específico; em geral, só o ligamos brevemente para usar os dados amostrados durante esse tempo. Então, se você precisar detectar em vários serviços ou por longos períodos, ainda precisará de uma técnica de rastreamento distribuído como opentracing.

Quais ferramentas e técnicas de depuração você usa no seu trabalho regular? Sinta-se à vontade para deixar um comentário e discutir comigo, também convido você a compartilhar este artigo com seus amigos, para que possamos aprender e progredir juntos.