Métricas são a forma que você consegue observar o estado atual do sistema. Existem infinitas coisas para se medir num sistema, então o difícil é separar o que eu realmente devo medir das coisas que eu posso medir — lembrando que elas são a janela para um início de debug.
No livro de SRE do Google são citadas 4 métricas básicas (golden signals): latência, trâfego, erros e saturação. Em cada sistema, essas métricas são coisas distintas. O importante é pensar no que importa para os usuários: latência de 20s é ruim para servir uma página, mas pode ser ótima para o processamento de um vídeo.
Pense no seu sistema e no que importa para ele, meça isso. Adicione outras métricas para facilitar o debug e entender o comportamento: métricas de caches, métricas para acessos a outros sistemas, métricas de banco de dados, métricas de conexões. Evite usar essas métricas específicas para alertas, elas servem para o debug. A saúde do sistema deve ser vista nas quatro principais, crie alertas em cima delas.
Conheça as métricas de sua aplicação: como ela se comporta ao longo do dia; qual o pico de acessos que já serviu; qual o crescimento dos acessos/dos dados. Saber o comportamento padrão permite identificar de forma rápida um problema. Às vezes o desvio da linha base é pequeno, talvez não gere um alarme, mas pode despertar a curiosidade da pessoa que está acostumada a olhar aqueles valores.
Se você adicionar métricas demais pode acabar sobrecarregando a aplicação e gastar mais tempo de CPU com elas do que com o serviço em si.
Observabilidade tem que fazer parte da cultura dos times, assim como segurança e qualidade. A thread do tweet abaixo fala justamente sobre isso.
The Good
Existem diversos tipos de sistemas, de métricas de aplicação à métricas de comportamento dos usuários. Cada um tem caraterísticas diferentes, volumes de dados diferentes, e muitos usos distintos (às vezes de uma mesma métrica), mas todos os sistemas podem ser classificados em duas grandes categorias: push ou pull. Isto é, alguns sistemas vão até as aplicações buscar métricas (pull), outros recebem a métrica (push).
Exemplo mais comum de sistema que utiliza pull: Prometheus
Exemplo mais comum de sistema que utiliza push: Newrelic, Datadog
Um sistema de métricas nada mais é do que um banco de dados com facilidade de gerar agregações temporais, afinal, queremos ver como as coisas se comportam ao longo do tempo. Um modelo mental bastante simples é o da figura abaixo, onde temos várias entradas para cada momento de tempo e dentro desta estrutura estão guardados metadados sobre a métrica (qual a instância, qual a rota, etc) e o valor que foi lido (ou recebido). Com isso podemos fazer agregações como "qual foi a taxa de requisições por minuto da rota '/'" e apresentar um gráfico com esses valores.
Cardinalidade merece um tópico à parte, mas vou tentar ser breve sobre. Cardinalidade fala da quantidade de variações que uma mesma métrica pode ter. Usando uma requisição http como exemplo podemos ter: rota, status, user agent, headers, hosts, etc. Cada termo pode receber diversos valores, alguns podem receber valores que não controlamos — isso dá margem para ataques de negação de serviço, não da aplicação que recebe as requisições mas do sistema de métricas. Se temos tantas variações, e fazemos a combinação (na real é o produto cartesiano) entre todas as variações possíveis temos uma cardinalidade enorme. Alguns sistemas de métrica não foram planejados para suportar isso. Portanto é necessário sempre saber se o sistema em questão atende aos requisitos de cardinalidade que a sua métrica precisa. Aqui vale resaltar que você também deve pensar se todas as variações são necessárias para a sua aplicação.
Alertas são essenciais em qualquer sistema de monitoração. É através deles que vamos mobilizar os times para atuarem. Como não queremos mobilizar pessoas por alarmes falsos, temos que entender porque um alerta está gerando falsos positivos, isto é, alarmando quando não deveria. Quando temos muitos falsos positivos temos a tendência de ignorar todos os alertas, pois assumimos que são sempre os mesmos, mas eventualmente será um alerta real que ficará esquecido por mais tempo do que deveria. Mais tempo com problemas, gera impacto com os usuários e definitivamente não queremos que o nosso sistema de alerta vire trending topics no Twitter.
O time precisa ter conhecimento de como medir e o que medir, afinal são as pessoas mais capazes de entender o que o sistema faz. Um time de observabilidade vai auxiliar mantendo o sistema de métricas e dando dicas de como utilizar as ferramentas. Em um time de frontend é bastante provável que a stack de observabilidade não atenda aos requisitos de volume de métricas e de cardinalidade, mas um sistema de injestão de métricas para Big Data consiga absorver sem problemas o volume necessário. Por isso, a necessidade do time saber o que quer medir e qual a finalidade dessa medição.
Para quem quiser se aprofundar em alertas recomendo fortemente o livro Site Reliability Engineering.
The Bad
Métricas geram muitas discussões e observabilidade é um campo de constante melhorias. Ficar atento ao que as empresas grandes estão fazendo e o que surge na comunidade é fundamental. Dito isso, é comum nos depararmos com as seguintes frases e vou dar meus 5 centavos sobre elas.
"Ah, mas aqui nós usamos o XPTO" — troque XPTO por Newrelic, Datadog, Prometheus, etc. As métricas não dependem do sistemas escolhido, entenda o que cada um desses sistemas oferece. Newrelic e Datadog oferecem instrumentação automágica, adicionam vários hooks em várias partes do teu software para conseguir medir. Verifique se as métricas realmente te atendem, não é por ser automágico que você terá as melhores métricas para o sistema.
"Adotamos o apdex para todas nossas apps" se todas as aplicações possuem um volume alto de acesso, ótimo. Apdex vai dar um cheiro do que está acontecendo. Mas aquela aplicação que recebe pouco tráfego vai estar sempre alarmando, ou aquela que demora para responder porque realmente está processando um grande volume de dados. Métricas são dos times e eles que vão saber o que importa, se for para normalizar algum métrica, normalize as quatro básicas e deixe os times definirem seus SLOs.
"Correlation does not imply causation" - Correlação não implica em causalidade. Leve isso para vida! Só por quê você viu uma métrica não infira que ela é a causa. Para fazer essa inferência levante mais dados, outras métricas, logs, etc. com tudo isso, crie uma hipótese da causa e teste! Sim, nós usamos o método científico para entender o que acontece nos sistemas.
The Ugly ou The good?
Se você gosta de matemática essa parte será The Good novamente, caso contrário provavelmente The Ugly. Mas vou tentar deixar da forma mais simples possível, afinal métricas são pura matemática e estatística. E aqui não quero dizer que é requisito saber muita matemática para trabalhar com TI, mas ter algumas noções básicas ajuda bastante.
Métricas precisam ser agregáveis, isto é, posso reuni-las dentro de uma janela de tempo e conseguir fazer operações matemáticas. Por exemplo, um contador de chamadas de uma rota HTTP é agregável, podemos somar todos os valores das diversas instâncias dentro de uma janela de tempo e dizer que atendemos 300 req/min.
Agora imagine que a aplicação entregue uma métrica que é o tempo médio de requisição dos últimos 30s. Dá para agregar essa métrica? Até dá e tu poderias ter uma média do tempo médio entre instâncias, mas não faz sentido tentar agregar o tempo máximo; afinal será o tempo máximo do tempo médio das requisições, não é um valor que tenha utilidade prática. Fazer média de médias é aceitável, inferir outras coisas em cima de médias começa a ser uma zona perigosa. Por isso, para tempos o ideal é utilizarmos histogramas, que são agregáveis e explicam melhor o que acontece com as requisições do que uma média.
Histogramas nada mais são do que diversos contadores, cada um responsável por um pequeno intervalo de tempo (ou do que você quiser, usei tempo por que é fácil de imaginar). Mas para entender um histograma vamos falar sobre probabilidade e estatística, começando com a curva normal, ou gaussiana, aquela que tem formato de um sino. Vou usar os exemplos como variáveis contínuas, ao invés das discretas que temos nos sistemas de métricas, só para ficar mais fácil de desenhar. Na imagem abaixo vemos a curva normal, com as marcas da média e dos desvios padrão. Ao lado temos alguns outros exemplos de distribuições que lembram uma curva normal — o tipo de análise que precisamos entender se aplica a toda a família de curvas.
O que precisamos entender como funciona, e levar para todas as métricas de latência, é que se só olharmos para a média provavelmente estamos errando feio. Nenhum sistema se comporta exatamente igual à uma gaussiana, então a média não vai estar ali no centro da figura, mas pode estar mais no início, ou final da curva. Para termos um entendimento comum entre todos, medimos a área que está abaixo da curva em alguns intervalos de interesse como 50% da área, ou 75%, ou 90%, 99%. O ponto onde termina essa área é o valor do percentil 50, percentil 75, percentil 90 e percentil 99.
E o que isso significa para a latência? Significa que quando pegamos a latência 90% de todas as requisições que o sistema recebeu, tivemos uma latência de 100ms. Só 10% dos usuários tiveram uma latência maior, o que é ótimo. Se quisermos ser mais exigentes podemos olhar o P99 onde vemos a latência que levou para atender 99% das requisições, isto é só 1% dos usuários pode ter sofrido com latências maiores do que o valor P99. Evite entrar na paranoia de querer garantir algo para 99,9999% das requisições, os custos para adicionar um 9 a mais vão se tornando proibitivos e não existe chegar a 100%.