Grafana + Prometheus

Visualizando as Métricas de Nossa API — Artigo 11

John Fercher
8 min readJul 17, 2023

Postman collection, código do artigo, diff com o artigo 9.

Sumário: Desenvolvimento de APIs em Go

Próximo Artigo: Domain-Driven Design (Parte I) — Subdomínios, Linguagem Ubíqua e Modelo de Domínio

Artigo Anterior: Go + Observabilidade — Métricas com o Prometheus

Introdução

Após a integração bem-sucedida com o Prometheus mencionada no artigo anterior, agora podemos iniciar a criação de gráficos e dashboards mais bem elaborados para facilitar a análise e compreensão dos eventos em nossa API. Para essa finalidade, faremos uso do Grafana.

O Grafana é uma plataforma de visualização de dados de código aberto, amplamente utilizado para monitorar e analisar métricas, logs e outras informações em tempo real. Ele fornece uma interface gráfica personalizável que permite criar dashboards interativos e informativos.

Com o Grafana, é possível conectar-se a uma variedade de fontes de dados, incluindo bancos de dados, sistemas de monitoramento e serviços em nuvem, para coletar informações e exibi-las visualmente. Ele suporta uma ampla gama de opções de armazenamento de dados, como o Prometheus, InfluxDB, Graphite, Elasticsearch e muitos outros. Nesse artigo vamos focar na integração com o Prometheus somente.

Os dashboards do Grafana podem conter gráficos, tabelas, medidores, mapas e outros tipos de visualizações, que podem ser personalizados e organizados de acordo com as necessidades de cada caso. Além disso, é possível definir alertas com base em condições específicas e receber notificações quando ocorrerem eventos importantes.

Tipos de Métricas

Na integração feita com o Prometheus no artigo anterior, apenas utilizamos métricas do tipo Counter e Histogram, porém isso não significa que sejam os únicos tipos disponíveis. O Prometheus suporta 4 tipos de métricas, que são os seguintes:

  1. Counters: São métricas que aumentam ou diminuem ao longo do tempo, mas nunca diminuem abaixo de zero. Eles representam a contagem cumulativa de algum evento ou o número de ocorrências de uma determinada ação. Exemplos incluem o número de solicitações HTTP recebidas ou o número de erros ocorridos.
  2. Histograms: São usados para calcular a distribuição de valores em uma determinada faixa. Os histogramas dividem os valores em buckets e contam quantos valores se enquadram em cada bucket. Eles permitem análises estatísticas mais detalhadas, como a média, mediana e percentis de uma distribuição de valores. Histogramas são úteis para analisar latência de solicitações, tempos de resposta e outras métricas com distribuição.
  3. Summaries: São semelhantes aos histogramas, mas fornecem uma forma mais eficiente de calcular quantis (quantiles). Em vez de dividir os valores em buckets fixos, os sumários utilizam amostras quantizadas para estimar os quantis desejados. Isso os torna mais adequados para cálculos de percentis e outras estatísticas resumidas em tempo real.
  4. Gauges: São métricas que representam valores que podem aumentar ou diminuir, mas não têm uma relação acumulativa. Eles indicam o valor atual de alguma propriedade ou estado, como a quantidade de memória livre, o número de conexões ativas ou a temperatura atual de um dispositivo.

Além dos quatro tipos de métricas disponíveis para utilizarmos, também temos a opção de usar labels para segmentar os dados. No geral, nesse artigo e no anterior estamos utilizando principalmente Counters e Histograms com um conjunto de labels. Essa combinação já é bastante eficaz para extrair a maioria das métricas do dia a dia e nos permitiu criar o dashboard apresentado no artigo anterior:

A integração entre o Prometheus e o Grafana é bastante simples, como será demonstrado a seguir.

Integrando Prometheus e Grafana

Para habilitar a comunicação entre esses dois serviços, precisamos seguir apenas dois passos. Primeiramente, devemos adicionar o serviço do Grafana ao docker-compose. Essa é a única alteração necessária em relação ao artigo anterior.

Observe que configuramos o Grafana para usar a rede (metrics) definida anteriormente. Também definimos a variável de ambiente GF_SECURITY_ADMIN_PASSWORD como (admin). Dessa forma, podemos acessar a plataforma web por meio de localhost:3000, utilizando usuário e senha (admin:admin).

Ao acessar a plataforma, você pode configurar uma conexão de banco de dados com o Prometheus. Essa conexão será usada para criar os gráficos.

Observe que estamos utilizando a URL (prometheus:9090), que é o nome do container que é iniciado através do docker-compose, juntamente com a porta definida. Com esses poucos passos, já é possível criar gráficos acessando os dados do Prometheus.

Criando Gráficos

Vamos iniciar o processo de criação de nossos dashboards, para isso precisamos clicar em “Create your first dashboard” na plataforma web.

Os painéis (dashboards) têm a finalidade de agrupar gráficos, sendo uma boa prática utilizá-los para reunir informações semelhantes, por isso vale a pena criar vários dashboards diferentes para analisar pontos específicos de uma aplicação ou cenário. Uma vez que um painel é criado, podemos começar a adicionar nossos gráficos, sendo que no Grafana é utilizada a nomenclatura de visualização. Para adicionar uma visualização, basta clicar em add no topo do dashboard.

Ao adicionar uma visualization, você tem algumas possibilidades para escolher.

Neste artigo, iremos realizar a medição de várias informações dos endpoints, tais como: taxa de requisições, latência e erros. Além disso, vamos utilizar a segregação por labels para melhorar a usabilidade e tornar as coisas mais claras. Para isso, iremos nos concentrar no uso das opções: séries temporais (time series), status (stat) e gráfico de pizza (pie chart).

Séries Temporais

O primeiro tipo de gráfico que iremos adicionar são as séries temporais. Nesse caso, abordaremos a criação de dois gráficos desse tipo: um com base em uma métrica do tipo Counter e outro com base em uma métrica do tipo Histogram.

A primeira métrica trabalhada será (endpoint_request_counter), que é uma métrica global da nossa aplicação utilizada para monitorar a quantidade de requisições recebidas em nossa API. Como essa métrica é global, vamos adicionar um filtro com base na label (endpoint), o que nos permitirá analisar cada endpoint separadamente.

Série Temporal de Requests Per Second

Com o filtro por endpoint definido, adicionamos uma operação para calcular a variação desse valor com base em um período de 1 minuto (Changes). Esse valor será exibido no eixo Y do gráfico em relação ao tempo. Por fim, aplicamos o cálculo da média (Avg) desse valor no endpoint, pois desejamos criar um gráfico de média de requisições por segundo (RPS).

Para adicionar um gráfico de série temporal a uma métrica do tipo Histograma, não há muita diferença. Basicamente, selecionamos a métrica definida no artigo anterior (endpoint_request_latency_bucket), que usamos para monitorar a latência da nossa aplicação, e adicionamos o mesmo filtro com base na label (endpoint).

Série Temporal de Latência Média

Nesse cenário, como desejamos monitorar a latência média e estamos lidando com uma métrica do tipo Histograma, iremos utilizar a função (Rate). Por fim, será aplicada a mesma função de média (Avg) que utilizamos na outra série temporal.

As séries temporais são úteis para analisar o comportamento de algo ao longo do tempo, facilitando a visualização de picos e vales com base na métrica em questão. Isso geralmente pode indicar quando algo está errado. Por exemplo, quando um endpoint está recebendo um alto volume de requisições, apresentando longos tempos de resposta ou retornando muitos erros. Essas informações são valiosas para realizar uma análise detalhada e encontrar a causa raiz de vários tipos de problemas.

Status

Quando é necessário monitorar os valores atuais de determinados indicadores da sua aplicação, utilizamos os gráficos de estatísticas (stats). Esses gráficos são essencialmente semelhantes às séries temporais, com a diferença de que alteramos o período de visualização para a última amostragem. Portanto, a consulta é praticamente a mesma, apenas alteramos os valores das funções Changes/Rate para 5 minutos em vez de 1 minuto. Isso nos fornece uma janela de amostragem maior, uma vez que nem sempre o último minuto de uma aplicação possui informações suficientes para a plotagem adequada.

Média de RPS nos últimos 5 minutos.
Soma dos erros nos últimos 5 minutos.
Latência média dos últimos 5 minutos.

Listando Ocorrências

A última visualização que iremos utilizar será a do gráfico de pizza, que será usado para listar a quantidade dos eventos mais recentes na aplicação. Nesse caso, uma das aplicações básicas é a segmentação de informações em relação aos erros que ocorrem em nossa aplicação.

Nesse exemplo, estamos filtrando todas as requisições da métrica (endpoint_request_counter) que possuem a label (failed:true), indicando que ocorreu algum erro no processamento. Aplicamos o filtro do endpoint, que já foi utilizado em todos os outros exemplos, e em seguida aplicamos a função (Changes). Por último, utilizamos o agregador (Sum) com base na label (response_code).

Dessa maneira conseguimos criar o gráfico de pizza que soma todos os response_codes no caso de erros. Também é possível criar gráficos pizza com base em outros conjuntos de labels que se repente, como error_code e etc.

Conclusões e Próximas Etapas

Neste artigo, foi apresentado o processo de integração do Prometheus com o Grafana, que se deu por meio do docker-compose e pela plataforma web do Grafana. Além disso, foram abordadas a criação de um painel (dashboard) e a inclusão de diferentes tipos de gráficos, que podem ser utilizados em diversos cenários.

Apesar de termos abordado alguns aspectos da plataforma Grafana, ainda deixamos de fora diversas funcionalidades. No futuro, iremos explorar mais sobre o Grafana. Além disso, ainda precisamos abordar os pilares de Logs e Tracing em relação à observabilidade, isso será feito no futuro.

No próximo episódio da série, começaremos a explorar o Domain-Driven Design e como utilizar muitos conceitos dessa abordagem para construir um ambiente de microsserviços. Vamos criar um ecossistema fictício de microsserviços para solucionar um problema específico e, com base nesse ecossistema, abordaremos conceitos como comunicação entre microsserviços, tópicos de resiliência, distributed tracing, entre outros.

Referências

--

--

John Fercher
John Fercher

Written by John Fercher

Tech lead at @MercadoLibre, gamer, master of science and open source contributor. More about: johnfercher.com