O daemon de log registra as métricas de desempenho do sistema e as armazena em um repositório. Em seguida, o proxy busca esses dados e os armazena no Redis, além de ser um exportador Prometheus, permitindo a coleta dessas métricas via a rota /metrics, como é feito no Prometheus tradicional. A principal vantagem do PCP, em comparação com exportadores como o node exporter, é sua flexibilidade. O PCP facilita a inclusão de novas funcionalidades e a visualização de métricas de baixo nível, como dados do kernel, através do Grafana.
Ao utilizar o PCP, a adição de novas métricas é simples e pode ser feita no nível do kernel. No caso do node exporter, embora forneça um grande número de métricas, muitas delas podem ser desnecessárias para o usuário e não podem ser customizadas facilmente. O PCP, por outro lado, possibilita a criação de métricas mais específicas e relevantes, otimizadas para a aplicação em questão. Além disso, ele oferece a capacidade de integrar essas métricas a ferramentas como o Grafana, através do uso de plugins como o Grafana PCP.
O painel do PCP no Grafana permite a análise de métricas em tempo real e históricas, utilizando fontes de dados como o PCP Vector e o PCP Redis. O uso de bpftrace com o PCP é um exemplo de como integrar scripts personalizados para a coleta de métricas e visualização de dados específicos, como a latência de filas de execução ou a atividade de processos TCP. O grande diferencial do PCP é a facilidade com que é possível escrever pequenos scripts bpftrace e integrá-los ao painel de visualização, o que proporciona uma visão detalhada e customizável do comportamento do sistema.
Ao configurar o PCP, a instalação dos módulos e a integração com o Grafana podem ser feitas de maneira relativamente simples. No ambiente Linux, a instalação do BCC e do bpftrace é realizada de forma contínua, como demonstrado nos comandos de instalação e na verificação das métricas instaladas. A utilização de ferramentas como o pmrep e pminfo permite ao usuário verificar as métricas em tempo real, bem como configurá-las para monitoramento contínuo e alertas automáticos.
Para visualizar as métricas no Grafana, é necessário configurar a fonte de dados PCP bpftrace, inserir os scripts no painel do Grafana e configurar consultas para exibir as métricas desejadas. Por exemplo, é possível utilizar um script simples para contar o número de processos criados por segundo e exibir esses dados em tempo real, permitindo uma análise detalhada do desempenho do sistema.
Ao integrar bpftrace e PCP, o usuário tem à disposição um poderoso conjunto de ferramentas para análise e otimização de desempenho. Essa integração oferece flexibilidade para medir e visualizar métricas de uma maneira que não seria possível com soluções tradicionais de monitoramento. A capacidade de personalizar as métricas e a facilidade de integração com o Grafana fazem do PCP uma escolha vantajosa para quem deseja ter controle total sobre o monitoramento de seu sistema.
A principal vantagem do uso do PCP em comparação com outras ferramentas como o node exporter e o Prometheus é a flexibilidade e a capacidade de personalizar métricas no nível do kernel. O uso de bpftrace dentro do PCP permite ao usuário escrever scripts específicos para medir aspectos de desempenho extremamente detalhados, adaptando-se às necessidades específicas de sua aplicação.
Além disso, a integração com o Grafana, através de plugins e fontes de dados como PCP Vector e PCP Redis, proporciona uma interface visual poderosa, que facilita a interpretação das métricas e a identificação de problemas de desempenho em tempo real. A visualização histórica e em tempo real das métricas também contribui para uma análise contínua e para a otimização de processos.
Endtext
Como o Chaos Engineering Pode Impactar a Latência e Retransmissões em Kubernetes
No mundo dos sistemas distribuídos, como Kubernetes, é essencial garantir que os aplicativos sejam resilientes e possam se recuperar de falhas de rede. O Chaos Engineering, ou Engenharia do Caos, é uma prática fundamental para testar essas resiliências ao introduzir falhas controladas. Uma das formas de testar a robustez da infraestrutura Kubernetes é através da simulação de perdas de pacotes de rede e aumento da latência, o que pode ajudar a entender o comportamento do sistema sob condições adversas.
O Chaos Mesh, uma ferramenta popular de Chaos Engineering para Kubernetes, pode ser configurado para introduzir falhas em níveis muito específicos, como perdas de pacotes em pods individuais. Este processo é extremamente útil para identificar pontos de falha na rede e observar como o sistema se comporta em condições de estresse. A latência aumentada é uma das métricas mais importantes a se observar durante esses testes. Ao configurar o tc dentro de containers Kubernetes, é possível adicionar latência diretamente à interface de rede, por exemplo, com o comando:
Este comando insere um atraso de 1 segundo em todo o tráfego da rede do pod, permitindo monitorar o impacto na latência da aplicação em tempo real. Quando analisado no painel de métricas do Grafana, o tempo de resposta do sistema geralmente mostra uma queda no número de requisições processadas e um aumento nas latências.
A propagação da latência, no entanto, pode ser observada não apenas nos microserviços de frontend, mas também no backend. À medida que a latência no frontend aumenta, os microserviços do backend começam a propagar essa latência, o que pode resultar em falhas em cascata, especialmente se os recursos atribuídos a esses microserviços não forem suficientes para suportar a carga de trabalho adicional. Em alguns casos, quando a carga excede os limites de recursos, o sistema pode reiniciar ou desativar serviços para restaurar a estabilidade.
A simples observação do percentil 99 de latência nos microserviços de frontend não é suficiente para uma análise de causa raiz completa. Embora as taxas de erro no frontend possam ser indicativas de problemas, a latência mais elevada muitas vezes é um problema sistêmico. As métricas fornecem uma boa visão geral, mas o rastreamento detalhado de traces específicos pode ser a chave para identificar precisamente onde a latência começa a afetar o sistema.
A ferramenta Chaos Mesh, além de simular perda de pacotes e latência, oferece recursos para manipulação de parâmetros de rede como largura de banda, ordenação de pacotes e limitação de taxa. Essas funcionalidades são cruciais para testar como o sistema lida com diferentes cenários de falhas de rede, mas é importante lembrar que a rede não é a única causa potencial de problemas de latência. Dispositivos de rede mal configurados, como firewalls, switches e balanceadores de carga, podem introduzir retransmissões inesperadas, o que agrava a latência e prejudica a performance do sistema.
Quando ocorrem retransmissões de pacotes, a análise de pacotes com ferramentas como tcpdump e wireshark torna-se essencial. O wireshark, por exemplo, permite filtrar os pacotes por sessão, facilitando a identificação de problemas específicos dentro de um fluxo de comunicação. A análise de retransmissões pode revelar a causa de falhas, como perda de pacotes ou falhas na negociação de conexão.
Retransmissões, em particular, podem ocorrer por vários motivos. Além de problemas na própria rede, configurações incorretas em firewalls e switches podem gerar pacotes duplicados ou fora de ordem, levando a um aumento no tempo de resposta. O protocolo TCP, que controla as retransmissões por meio dos números SEQ (sequência) e ACK (reconhecimento), desempenha um papel crucial na identificação da origem desses problemas. Quando um pacote é retransmitido, os números SEQ e ACK ajudam a determinar se o pacote foi realmente perdido ou se ocorreu alguma falha na rede.
A análise de retransmissões é facilitada pela habilidade do wireshark de mostrar o fluxo completo de pacotes dentro de uma conexão TCP. Usando o recurso "Follow TCP Stream", é possível observar todo o processo de transmissão, desde a troca inicial de pacotes SYN até a resposta final do servidor. Esse nível de detalhe ajuda a identificar problemas como pacotes RST (reset), que podem surgir inesperadamente durante a comunicação.
Além disso, é essencial compreender que, ao monitorar a latência e as retransmissões, é preciso não apenas verificar a rede, mas também a infraestrutura subjacente, como a CPU, a memória e a I/O dos servidores envolvidos. A latência pode ser causada por limitações nos recursos da máquina ou por um congestionamento de tráfego no caminho de rede.
Em uma configuração ideal, ao ocorrer um problema de latência, é fundamental realizar uma análise profunda de todos os componentes da rede e da infraestrutura para entender qual parte do sistema está causando o gargalo. Isso inclui não apenas a análise de pacotes de rede, mas também a verificação das métricas de desempenho dos sistemas envolvidos, seja no lado do servidor ou do cliente.
Por fim, é importante que o Chaos Engineering seja usado como uma prática contínua e não apenas como uma técnica pontual. A introdução controlada de falhas não deve ser vista apenas como uma maneira de verificar a resiliência do sistema, mas como um processo contínuo de otimização da infraestrutura para que ela seja capaz de se adaptar e se recuperar de falhas inesperadas. Ao entender os padrões de latência e retransmissões, as equipes podem melhorar as configurações da rede e da aplicação para garantir uma maior disponibilidade e desempenho, mesmo nas condições mais desafiadoras.
Por que sistemas falham mesmo quando serviços são reiniciados?
Falhas em sistemas distribuídos frequentemente persistem mesmo após a reinicialização de serviços comuns. Isso ocorre porque, ainda que um serviço específico seja reiniciado com sucesso, os efeitos da falha já se propagaram para outros componentes do sistema. A falha inicial pode ter causado configurações corrompidas ou estados de erro persistentes que influenciam negativamente os serviços dependentes, perpetuando a instabilidade.
Em conexões de rede, o estado TIME-WAIT aparece do lado que encerra o socket, e embora o hardware moderno suporte altos volumes de tráfego, desconexões em massa podem esgotar as portas locais disponíveis. Além disso, o uso excessivo de recursos pode levar ao esgotamento de memória. Já o estado CLOSE-WAIT indica conexões zumbis, normalmente causadas por falhas no encerramento correto do socket pelo cliente ou configurações incorretas.
Timeouts de HTTP Keepalive e TCP Keepalive são essenciais para reutilização de conexões, o que reduz a latência eliminando a necessidade de abrir e fechar conexões repetidamente. No entanto, o gerenciamento desses timeouts requer precisão: timeouts curtos demais reduzem a resiliência do sistema, enquanto timeouts excessivamente longos aumentam a latência e dificultam a detecção de falhas. Idealmente, o timeout de conexão deve ser configurado com no mínimo três segundos e o de leitura em pelo menos 300 milissegundos.
Cada socket consome um descritor de arquivo. Quando o número de sockets simultâneos cresce, os limites de descritores também se tornam um gargalo. Da mesma forma, pools de threads mal dimensionados afetam diretamente a latência e a vazão do sistema. Muitos pools podem esgotar os recursos e gerar trocas de contexto dispendiosas, enquanto poucos pools deixam requisições acumulando-se em filas, aumentando a latência.
O comportamento de switches, roteadores e balanceadores de carga recém-configurados exige testes rigorosos. A introdução de novos equipamentos de rede pode causar falhas catastróficas se não for bem validada. A latência do sistema não se limita apenas ao tempo de CPU: a latência de I/O é igualmente crítica. Contudo, enquanto os tipos de carga da CPU são mais previsíveis e uniformes, as operações de I/O variam amplamente e podem competir pelos mesmos recursos, especialmente em clusters distribuídos.
Clusters modernos utilizam I/O intensivamente para tarefas como mesclagem de blocos, reequilíbrio, quorum, replicação, uso de WALs e políticas de cache. Embora cada operação de I/O isolada seja compreensível, o diagnóstico torna-se desafiador quando múltiplas operações disputam recursos simultaneamente. Nesses ambientes, falhas são mais difíceis de isolar do que em arquiteturas de microsserviços. Assim, ter engenheiros com conhecimento profundo em recursos de sistema e nos detalhes da arquitetura de cluster específica é fundamental.
Chamadas bloqueantes, como em frameworks do tipo Spring MVC, tendem a ser mais previsíveis do que chamadas não bloqueantes. O desenvolvimento de chamadas não bloqueantes é mais complexo e suscetível a esgotamento de recursos, pois facilita a criação de múltiplas threads, o que pode sobrecarregar o sistema. Além disso, a carga processada por chamadas não bloqueantes pode se propagar mais facilmente, afetando serviços a jusante. Identificar problemas em chamadas não bloqueantes usando apenas métricas e rastreamentos é difícil. É necessário um nível mais profundo de observabilidade, por meio de logs e perfis de sistema.
O uso inadequado de timeouts pode resultar em efeitos adversos inesperados, como a derrubada completa do sistema. Em um exemplo comum, operações como flush de memória para disco e mesclagem de blocos de arquivos são muito mais intensivas em I/O do que em CPU. A frequência e vazão dessas operações devem ser monitoradas cuidadosamente. Frequência baixa pode levar a picos de utilização de I/O, enquanto frequência alta impõe sobrecarga ao escalonamento de threads, comprometendo o desempenho geral.
Ao utilizar processos de compactação — como mesclar, comprimir e ordenar dados — é possível melhorar significativamente a vazão do disco. Contudo, se essas tarefas forem adiadas ou mal executadas, ocorre aumento abrupto de utilização de I/O e CPU, com interrupções inesperadas e latência elevada. Parâmetros do kernel relacionados ao escalonador de I/O devem ser ajustados conforme o tipo de carga que o sistema suporta.
Em muitos casos, a observabilidade oferecida por ferramentas comerciais ou pelo OpenTelemetry não fornece rastreamento detalhado no nível das threads. Quando múlt
Como Analisar Perfis de Performance em Microserviços: Flame Graphs e Outros Métodos
Quando se trata de diagnosticar problemas de desempenho em aplicações, especialmente em arquiteturas de microserviços, o uso de perfis de código torna-se uma ferramenta essencial. No entanto, não se deve cometer o erro de executar múltiplos dumps de threads de forma indiscriminada. Embora eles possam fornecer informações úteis, a repetição excessiva pode resultar em sobrecarga e em uma análise de dados pouco eficaz. Por sua vez, a utilização de flame graphs surge como uma abordagem visual poderosa, capaz de sintetizar de forma clara o desempenho de diversos recursos de uma aplicação, permitindo a identificação rápida de problemas.
Perfis de código são recursos que apresentam o comportamento de uma aplicação durante a execução, com foco em diferentes métricas como duração, frequência e uso de recursos. No entanto, a granularidade e complexidade dos perfis podem variar de acordo com a linguagem de programação utilizada. Por exemplo, perfis podem ser capazes de identificar condições de corrida em Go, mas essa funcionalidade pode não estar disponível em Java. Além disso, enquanto perfis tradicionais oferecem uma visão detalhada e específica sobre a linguagem de desenvolvimento, perfis contínuos apresentam limitações significativas em termos de funcionalidade, tornando a análise em ambientes de microserviços mais desafiadora e a curva de aprendizado mais acentuada.
Com os perfis tradicionais, por exemplo, podemos obter informações valiosas sobre a duração do uso da CPU e da memória. A duração da CPU é um fator crítico para entender o desempenho de uma aplicação. Ela representa o tempo que o processador está efetivamente executando um bloco de código. Mas, muitas vezes, a duração real de um método é maior que o tempo de CPU, indicando que o código está aguardando por algum processo, como a sincronização de threads ou bloqueios, o que pode criar gargalos no sistema. Por outro lado, quando o tempo real de execução é próximo do tempo de CPU, significa que o método é intensivo em CPU e deve ser otimizado para evitar sobrecarga do processador.
Além do uso da CPU, o gerenciamento de memória também é crucial. O uso do heap, por exemplo, refere-se à quantidade de memória alocada para a aplicação no momento da coleta do perfil. É importante notar que o heap inclui tanto a memória alocada quanto aquela que foi liberada, mas não está mais em uso. Profiling do heap ajuda a identificar potenciais ineficiências, como vazamentos de memória ou alocações excessivas, que podem sobrecarregar o coletor de lixo e prejudicar o desempenho da aplicação.
A representação gráfica desses dados, por meio de flame graphs, é uma das maneiras mais eficientes de visualizar o comportamento do código. Em um flame graph, cada "flama" representa uma função ou método, e sua largura indica o tempo de CPU utilizado por esse bloco de código. As flamas mais largas são, portanto, as que consumiram mais recursos. A análise das flamas no gráfico ajuda a identificar quais métodos estão impactando o desempenho e onde as otimizações devem ser focadas. Para ler um flame graph, é importante começar pelas flamas mais largas e, a partir daí, investigar os métodos que mais consomem tempo.
Ao analisar um flame graph, a profundidade da pilha é representada no eixo Y, enquanto o eixo X mostra a frequência dos samples. A análise começa pelo método de topo, aquele com o maior consumo de recursos, e se desloca para baixo, a medida que se examinam as relações entre os métodos. Esse tipo de gráfico é útil para detectar pontos de estrangulamento no desempenho e otimizar a execução de código. Embora os flame graphs sejam eficientes para representar grandes volumes de dados de forma compacta e acessível, eles não conseguem, por si só, identificar todos os problemas potenciais, especialmente em relação a percentis altos, como o 99º, que podem ser determinantes em determinadas situações.
Além de flame graphs, os perfis de código em microserviços podem ser usados de diversas outras maneiras para identificar e melhorar a performance da aplicação. Através de métricas como o tempo de CPU e o uso de memória, é possível comparar o comportamento de uma versão da aplicação com outra. A coleta contínua de perfis pode ser útil para monitorar mudanças e garantir que as otimizações realmente estejam trazendo benefícios. A identificação de métodos que consomem muitos recursos e sua subsequente otimização pode levar a melhorias significativas no desempenho geral da aplicação.
É importante também considerar as limitações do ambiente em que se está trabalhando. Em sistemas complexos de microserviços, com múltiplos componentes e linguagens de programação distintas, o gerenciamento de perfis pode ser um processo demorado e ineficiente. A análise de dados coletados por perfis deve ser feita com cuidado, já que as diferentes tecnologias suportam granularidades variadas, tornando a comparação entre elas um desafio. Além disso, é preciso lembrar que o profiling é uma ferramenta que necessita de constante refinamento. Não basta apenas coletar dados, é necessário interpretar os resultados e realizar ajustes baseados neles.
A análise de perfis é um processo iterativo. Quando se lida com grandes quantidades de dados e sistemas distribuídos, é fundamental manter um ciclo de análise e ajuste contínuo. Os flame graphs, juntamente com perfis de CPU e memória, fornecem uma excelente base para entender os pontos fracos da aplicação, mas o acompanhamento constante e as melhorias periódicas são essenciais para garantir que o desempenho esteja sempre otimizado.
Como Usar Perfis para Análise de Desempenho e Depuração em Ambientes Kubernetes
Para lidar com problemas relacionados a recursos, uma abordagem eficaz envolve o uso de perfis. A configuração do exemplo utiliza o Pyroscope Helm Chart, que implementa o servidor Pyroscope e cria os papéis de RBAC necessários. O comando helm repo add pyroscope-io https://pyroscope-io.github.io/helm-chart permite adicionar o repositório do Helm, e helm install demo pyroscope-io/pyroscope -f values.yaml aplica a configuração definida no arquivo values.yaml. Esse método aplica as configurações de maneira eficiente para a coleta de métricas de desempenho.
O Pyroscope utiliza o mesmo mecanismo de busca do Prometheus e oferece suporte à descoberta de serviços do Kubernetes. Para este exemplo, utilizamos o aplicativo Jaeger HotROD, habilitando o endpoint interno pprof do Go. O Pyroscope pode extrair perfis diretamente desse endpoint. Para garantir a coleta de perfis de CPU e memória, as etiquetas do pod são configuradas de maneira específica em manifests.yaml, com parâmetros como pyroscope.io/scrape: "true", pyroscope.io/profile-cpu-enabled: "true" e pyroscope.io/profile-mem-enabled: "true". Em seguida, o comando kubectl apply -f manifests.yaml é utilizado para criar a aplicação.
Uma vez que o HotROD é iniciado corretamente, o perfil começa a ser ingerido automaticamente. Para garantir o bom funcionamento, é necessário incluir o código abaixo para habilitar o endpoint pprof:
Além disso, o pacote pprof pode registrar outros pontos de extremidade para monitoramento detalhado. Essa configuração permite acessar métricas e diagnósticos em tempo real, facilitando a identificação de problemas.
A depuração remota é uma prática essencial para diagnosticar falhas de maneira eficiente, especialmente quando se lida com agentes de observabilidade e containers. A depuração remota permite analisar variáveis e entender o comportamento do código de forma detalhada, sem a necessidade de interromper a execução do serviço. Ferramentas como VSCode, IntelliJ, JDWP (Java) e Delve (Go) são amplamente usadas para depuração remota. A depuração pode ser aplicada também em ambientes Docker ou Kubernetes, onde é possível configurar agentes para interagir com o código de forma não invasiva.
No entanto, é importante observar que a depuração remota possui algumas limitações. A configuração requer acesso administrativo aos servidores, o que restringe a quem pode iniciar uma sessão de depuração em ambientes de produção. Além disso, existe o risco de exposição de dados sensíveis, como tokens e senhas, durante o processo de depuração. A latência também pode ser um fator limitante, especialmente em servidores em nuvem ou ambientes distribuídos. Embora a depuração remota ofereça uma análise profunda, ela não é a melhor solução para todos os cenários, especialmente em ambientes altamente dinâmicos como o Kubernetes.
Outra abordagem que complementa a depuração remota é a depuração ao vivo (live debugging), que usa a instrumentação de bytecode de maneira dinâmica para coletar dados sem a necessidade de reiniciar a aplicação. Isso permite o monitoramento contínuo e a coleta de logs, métricas e traços distribuídos durante o funcionamento do aplicativo. Porém, a depuração ao vivo também pode ser limitada, especialmente em ambientes de produção.
Além disso, os eventos desempenham um papel fundamental na observabilidade moderna, complementando o rastreamento e as métricas. Ao contrário do RUM (Real User Monitoring), que lida apenas com cabeçalhos e não tem visibilidade no corpo das mensagens, os eventos capturam tanto os cabeçalhos quanto os corpos das mensagens. Essa abordagem permite uma análise mais detalhada e contextual, essencial para entender os fluxos de negócios. É especialmente útil para monitorar processos complexos, como a gestão de pedidos ou transações financeiras, onde os eventos podem ser agregados para fornecer uma visão clara do comportamento do usuário ou da operação.
Os dados de eventos fluem em três fases principais: captura, processamento e análise. A captura envolve a coleta de dados de eventos de APIs externas ou do próprio código. O processamento refere-se à transformação desses dados em informações úteis, aplicando regras para filtrar e enriquecer os dados. A análise final permite extrair insights valiosos, conectando dados de observabilidade com dados de negócios.
Para maximizar a utilidade desses eventos, é importante configurar corretamente os fluxos de dados e a instrumentação para garantir que todos os aspectos do sistema sejam monitorados de maneira eficaz.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский