Ao implementar a observabilidade de sistemas, é importante começar com uma análise detalhada dos dados da aplicação, mas a infraestrutura, com o tempo, também exige uma atenção profunda. Embora muitos sistemas de observabilidade modernos, como o OpenTelemetry, sejam amplamente usados para monitorar o desempenho de aplicações e serviços, o mesmo não se aplica à infraestrutura. A observabilidade de infraestrutura, embora crucial, tende a ser mais técnica e complexa, necessitando de abordagens e ferramentas específicas para monitorar, analisar e resolver problemas com eficácia.

No caso das aplicações, o uso de SQL de rastreamento (trace SQL) para análise de dados complexos tem se mostrado mais eficiente do que as consultas métricas tradicionais. Utilizando o SQL de rastreamento, é possível gerar resultados mais precisos e detalhados, que fornecem uma visão completa do estado e das agregações de uma aplicação simples. Isso se torna ainda mais importante quando se enfrenta problemas de propagação incorreta de spans dentro de transações, onde a consulta direta ao rastreamento pode indicar exatamente onde o erro está ocorrendo, permitindo um diagnóstico mais preciso.

Com o rastreamento SQL, a visualização das transações individuais e a obtenção de estatísticas precisas sobre o tempo médio de resolução de problemas (MTTR) tornam-se mais acessíveis. Isso facilita não apenas a análise de transações, mas também a avaliação da maturidade da observabilidade em uma organização. Essa abordagem permite uma análise contínua e baseada em dados reais, o que é essencial para um bom gerenciamento da infraestrutura.

Embora muitas soluções de observabilidade, como OpenTelemetry, ofereçam vantagens consideráveis, elas também apresentam limitações. Uma dessas limitações é que, apesar de serem eficientes para monitorar a aplicação, elas não oferecem a mesma profundidade ao lidar com a infraestrutura. Para resolver problemas complexos de TI, especialmente em ambientes legados, é necessário combinar ferramentas e técnicas variadas, sem preconceitos ou hesitações, para modernizar a infraestrutura o mais rápido possível.

A observabilidade da infraestrutura, por sua vez, trata de sistemas muito maiores e mais complexos. Um problema de desempenho em um serviço individual pode ser muito mais simples de identificar e corrigir do que um gargalo em uma rede ou em um servidor em larga escala. Melhorar o uso de recursos, como a utilização de CPU, pode resultar em grandes economias, especialmente quando aplicadas em toda a infraestrutura de um centro de dados. Por exemplo, uma pequena redução na latência ou um pequeno aumento na eficiência do uso de recursos pode gerar economias significativas, não apenas para um serviço, mas para toda a operação.

Embora os sistemas de monitoramento de infraestrutura possam ser complexos, ferramentas como o ftrace, strace e eBPF oferecem maneiras eficazes de realizar a análise. O ftrace, por exemplo, fornece informações detalhadas sobre o comportamento do kernel, como interrupções e agendamento de tarefas. Já o strace permite verificar a sequência de chamadas de sistema, sendo útil para detectar comportamentos anômalos em aplicações. Ferramentas como o eBPF, mais recentes e com menos overhead, oferecem perfis detalhados sobre o desempenho do sistema, sendo adequadas para o ambiente de produção.

A chave para a eficácia na observabilidade da infraestrutura está em entender a relação entre as camadas do sistema. Cada camada de serviço em uma arquitetura de infraestrutura pode influenciar as outras, e um erro em uma delas pode impactar diretamente o desempenho geral. Por isso, é essencial ter uma visão clara de como as camadas interagem e como os erros podem ser isolados para determinar a verdadeira causa raiz. No entanto, muitas vezes os problemas não se limitam a uma única camada, e a verdadeira origem pode ser mais profunda, exigindo uma investigação minuciosa.

Além das ferramentas mencionadas, a implementação de uma abordagem prática e cuidadosa ao utilizar o rastreamento e as consultas específicas ajudará a identificar e solucionar rapidamente os problemas de infraestrutura. A separação entre equipes de desenvolvimento e infraestrutura, com uma forte colaboração entre elas e os SREs, é fundamental para garantir que falhas sejam corretamente diagnosticadas e resolvidas. Inicialmente, a observabilidade de aplicações deve ser priorizada, pois isso pode resolver boa parte dos problemas sem recorrer à infraestrutura. Mas, quando necessário, a observabilidade da infraestrutura deve ser usada para aprofundar a análise e encontrar as causas raízes.

A observabilidade eficiente é essencial para uma gestão moderna da TI, ajudando as organizações a otimizar seus recursos, minimizar custos e melhorar a confiabilidade geral dos sistemas. Entender as nuances da infraestrutura e saber quando utilizar ferramentas de rastreamento complexas, como o SQL de rastreamento e as utilidades de kernel, permite que as empresas respondam rapidamente a falhas e mantenham seus sistemas operando com eficiência máxima.

Como Analisar e Visualizar Estruturas de Chamada em Sistemas Complexos

A análise de dados em sistemas distribuídos e microserviços é uma das maiores dificuldades enfrentadas pelos desenvolvedores e engenheiros de sistemas. À medida que as aplicações se tornam mais complexas, a capacidade de monitorar e entender o comportamento dos serviços dentro do ecossistema se torna essencial para a identificação de gargalos e a otimização do desempenho. Uma das formas mais eficazes de realizar essa análise é utilizando gráficos que representem as dependências entre os serviços e os tempos de execução, fornecendo uma visão clara da latência, da duração das operações e dos pontos críticos do sistema.

A partir da análise da árvore de chamadas "upstream" (subida) e da criação de um gráfico "downstream" (descida), podemos ter uma visão mais profunda das relações e dos efeitos colaterais das operações em um sistema. A consulta para obter as relações de upstream e downstream é essencial para visualizar o fluxo de dados e entender como um serviço se comporta em um contexto mais amplo. Abaixo está um exemplo básico de como uma consulta pode ser realizada para filtrar os dados por hora do dia e contar o número de rastros coletados durante um período de tempo filtrado. Ao filtrar por intervalos de tempo, podemos analisar como o tráfego é distribuído ao longo do dia, ajudando a identificar os momentos de maior ou menor demanda:

sql
SELECT count(*) as nbr_traces
FROM ps_trace.span s WHERE $__timeFilter(s.start_time) AND s.parent_span_id IS NULL -- apenas spans raiz

Essa consulta permite contar o número de rastros em intervalos de dez segundos, um método eficiente para entender a taxa de transferência de um sistema. Como cada rastro pode ter múltiplos spans, o filtro por spans raiz (parent_span_id IS NULL) garante que apenas os rastros principais sejam contados, facilitando a análise da carga no sistema em momentos específicos.

Além de contar os rastros, é importante observar a latência ao longo do tempo. Um histograma de latência é uma ferramenta útil para isso, pois mostra a distribuição da latência das requisições em diferentes momentos. A consulta abaixo cria um histograma para latências com percentis de 95%, permitindo visualizar como a latência muda ao longo do tempo e identificar picos de lentidão:

sql
SELECT time_bucket('10 seconds', s.start_time) as time,
approx_percentile(0.95, percentile_agg(s.duration_ms)) as duration_p95 FROM ps_trace.span s WHERE $__timeFilter(s.start_time) AND s.parent_span_id IS NULL GROUP BY time ORDER BY time

Além do histograma, um gráfico de pizza (pie chart) de durações pode ser extremamente útil para entender qual operação ou serviço dentro do sistema está consumindo mais tempo. A duração de cada span inclui o tempo gasto na operação em si e em suas spans filhas, então a criação de um gráfico de pizza onde cada fatia representa a contribuição de uma operação ao tempo total do sistema ajuda a identificar os maiores "culpados" em termos de consumo de tempo:

sql
SELECT s.service_name || ' ' || s.span_name as operation, sum(s.duration_ms coalesce(( SELECT sum(k.duration_ms) FROM ps_trace.span k WHERE k.trace_id = s.trace_id AND k.parent_span_id = s.span_id AND $__timeFilter(k.start_time) ), 0)) as total_exec_ms FROM ps_trace.span s WHERE $__timeFilter(s.start_time) GROUP BY s.service_name, s.span_name

Outro ponto crucial é a visualização das dependências dos serviços, tanto upstream quanto downstream. À medida que o sistema cresce, entender essas dependências torna-se fundamental para diagnosticar problemas de desempenho e falhas. Usando Grafana e outras ferramentas de visualização, podemos criar mapas de serviço que ajudam a entender como os serviços se conectam uns aos outros. A técnica de recursão pode ser utilizada para encontrar spans "upstream", ou seja, todos os spans que chamam diretamente ou indiretamente um dado span. Essa visualização pode ser feita por meio de uma consulta recursiva, como o exemplo abaixo, onde se busca uma visão detalhada da relação de chamadas entre os serviços:

sql
WITH RECURSIVE x AS ( SELECT s.trace_id, s.span_id, s.parent_span_id, s.service_name, s.span_name FROM ps_trace.span s WHERE $__timeFilter(s.start_time) AND s.service_name = '$service' AND s.span_name = '$span_name' UNION ALL SELECT p.trace_id, p.span_id, p.parent_span_id, p.service_name, p.span_name FROM ps_trace.span p INNER JOIN x ON (p.trace_id = x.trace_id AND p.span_id = x.parent_span_id) WHERE $__timeFilter(p.start_time) )
SELECT DISTINCT concat(x.service_name, '|', x.span_name) as id,
x.service_name
as title, x.span_name as "subTitle" FROM x

Ao mapear essas dependências e visualizá-las em uma interface gráfica, o entendimento da estrutura do sistema se torna mais claro. Isso facilita a identificação de gargalos e a análise de falhas em tempo real, ajudando os desenvolvedores a realizar otimizações mais eficazes.

Com a visualização das dependências upstream e downstream, pode-se também analisar o impacto de cada operação na latência do sistema. Por exemplo, ao observar a variabilidade da latência ao longo do tempo, é possível identificar operações que estão introduzindo lentidão e, com isso, focar os esforços de otimização nas áreas mais críticas. Uma consulta para observar essa variabilidade pode ser estruturada da seguinte forma:

sql
SELECT time_bucket('10 seconds', s.start_time) as time,
s.duration_ms FROM ps_trace.span s WHERE $__timeFilter(s.start_time) AND s.parent_span_id IS NULL

Essa consulta irá gerar uma linha do tempo da latência, permitindo ao analista perceber se há variações significativas durante o período monitorado. Quando a latência varia muito, é importante investigar quais operações estão mais suscetíveis a esses picos, ajudando na otimização de performance.

Por fim, a análise das dependências de upstream e downstream não é apenas uma questão técnica, mas também estratégica. Ela permite que as equipes de desenvolvimento compreendam não só as falhas, mas também os pontos de impacto no desempenho geral do sistema. A habilidade de visualizar essas dependências em tempo real e em grande escala pode ser o diferencial entre um serviço de baixa performance e uma arquitetura de microserviços bem ajustada. Portanto, entender as nuances dessas relações e usar as ferramentas de monitoramento adequadas, como Grafana e consultas SQL específicas, é fundamental para uma gestão eficiente de sistemas complexos.

Por que os projetos de AIOps falham ao identificar causas reais de falhas?

A verdadeira utilidade do AIOps não reside apenas em alertar sobre anomalias, mas em fornecer uma análise causal precisa e propor soluções viáveis. Quando falamos de causa raiz, o AIOps deve ir além da superfície dos sintomas. No exemplo de um sistema com estado de threads prolongadamente em RUNNABLE, aumentar o número de threads não é a resposta correta. Embora pareça uma solução intuitiva, isso apenas mascara o problema real, que está no tempo excessivo de processamento de certas chamadas downstream. A solução apropriada passa por encurtar o timeout a montante para quatro segundos e otimizar métodos downstream para responder em até um segundo. Essa abordagem libera threads para que possam retornar ao estado WAITING e serem reutilizadas eficientemente.

A precisão no diagnóstico é fundamental. Um AIOps que atribui a latência ao upstream, ou que sugere o aumento do thread pool como solução genérica, está falhando. A resposta correta não está em alocar mais recursos cegamente, mas em entender como o código está se comportando — se há falhas lógicas, bugs ou gargalos estruturais. Ferramentas de profiling devem ser utilizadas para identificar os métodos problemáticos, e configurações de rede, como parâmetros do kernel, devem ser ajustadas conforme necessário.

Um outro caso elucidativo envolve o crescimento de memória na geração antiga do heap JVM, levando a várias coletas de lixo completas (Full GCs) e, consequentemente, à degradação do desempenho matinal. O AIOps, neste caso, simplesmente alerta para a frequência de GCs, mas não contextualiza o problema. Ele não distingue entre coletas parciais e completas, nem correlaciona o aumento de uso de memória com um deployment feito dois dias antes. O que se espera é que o AIOps aponte o deployment como causa primária, identificando um bug na instrumentação do GA360 como o agente causador da alocação excessiva de memória. Garbage collection, por si só, é um efeito — não a origem do problema.

Confundir causa e efeito é uma falha recorrente nos projetos de AIOps. Eles tendem a relatar o que está visivelmente errado, mas não por que aquilo ocorre. A consequência é que as equipes de SRE recebem alertas descontextualizados, tomam decisões baseadas em sintomas e não eliminam as causas reais. É esse descompasso que leva tantos projetos de AIOps ao fracasso.

A mesma lógica se aplica à operação de servidores como o nginx, onde o desempenho depende de um conjunto complexo de parâmetros. Cada processo worker é mono-threaded, mas utiliza IO não bloqueante e uma arquitetura orientada a eventos para processar várias requisições simultaneamente. A eficiência depende do uso correto de epoll (em vez de select), do dimensionamento adequado de processos workers, e do ajuste fino de parâmetros como worker_connections, keepalive_timeouts e buffers de cliente. As falhas ocorrem não por ausência de alertas, mas pela incapacidade do AIOps de indicar exatamente onde o problema está — por exemplo, quando arquivos temporários sobrecarregam o disco ou quando conexões upstream não são mantidas de forma eficiente.

A compressão gzip de respostas HTTP pode reduzir significativamente o tráfego de rede, impactando diretamente o desempenho em ambientes móveis e os custos de infraestrutura. Mas o AIOps raramente relaciona lentidão na resposta com ausência de compressão ou configurações ineficientes de keepalive. Ele também não aponta quando IO de arquivos se torna o gargalo, especialmente em servidores que lidam com grandes volumes de upload.

Muitos AIOps continuam funcionando como sistemas de alarme sofisticados, sem capacidade real de entendimento causal. Eles ignoram o contexto dos deployments, não correlacionam eventos no tempo, e não entendem a arquitetura subjacente dos sistemas. Isso os torna incapazes de responder com clareza e precisão às necessidades reais das equipes de confiabilidade.

A compreensão profunda da lógica dos sistemas e do comportamento assíncrono da infraestrutura é essencial. Além disso, é imprescindível o alinhamento temporal entre eventos e alertas. A análise de causa não pode ser dedutiva baseada apenas no sintoma imediato. O AIOps precisa correlacionar histórico de deploys, mudanças de configuração e perfis de desempenho em tempo real para entregar insights que sejam realmente acionáveis. Sem essa capacida