Skip to main content

Introdução à Observabilidade de Aplicações

O que é a Observabilidade de Aplicações?


Observabilidade de Aplicações permite entender um sistema externamente, possibilitando fazer perguntas sobre ele sem precisar conhecer seu funcionamento interno. Além disso, facilita a solução de problemas desconhecidos e imprevistos . A observabilidade ajuda a responder à pergunta: “Por que isso está acontecendo?”

Para fazer perguntas sobre um sistema, é necessário que sua aplicação esteja devidamente instrumentada. Isso significa que o código da aplicação ou algum componente intimamente ligado à aplicação como o Application Server, máquina virtual da linguagem da aplicação ou intepretador de comandos da linguagem devem emitir sinais, como rastreamentos (traces), métricas e logs. Uma aplicação está bem instrumentada quando os desenvolvedores não precisam adicionar mais instrumentação para investigar problemas, pois já possuem todas as informações necessárias.

O Priax, além de possuir mecanismos de instrumentação próprios pode é compatível com mecanismos consagrados do mercado como OpenTelemetry, Jaeger ou Opensearch APM. Todos esses mecanismos são usados para instrumentar o código da aplicação e tornar um sistema observável.

Telemetria, métricas e confiabilidade de Aplicações

Telemetria se refere aos dados emitidos por um sistema e seu comportamento. Esses dados podem ser apresentados na forma de rastreamentos, métricas e logs.

A confiabilidade responde à pergunta: “O serviço está fazendo o que os usuários esperam que ele faça?”. Por exemplo, um sistema pode estar disponível 100% do tempo, mas, se ao clicar em "Adicionar ao Carrinho" para incluir um par de sapatos pretos, o sistema não adicionar sempre os sapatos pretos, ele é considerado não confiável.

Métricas são agregações ao longo do tempo de dados numéricos sobre sua infraestrutura ou aplicação. Exemplos incluem:

  • Taxa de erro do sistema
  • Uso da CPU
  • Taxa de solicitações de um serviço

SLI (Service Level Indicator) é uma medida do comportamento de um serviço. Um bom SLI mede o serviço do ponto de vista dos usuários. Um exemplo de SLI é a velocidade de carregamento de uma página web.

SLO (Service Level Objective) é a forma como a confiabilidade é comunicada dentro da organização ou para outras equipes, vinculando um ou mais SLIs ao valor de negócio.

Entendendo o Rastreamento Distribuído

O rastreamento distribuído permite observar solicitações conforme elas se propagam por sistemas distribuídos e complexos. Ele melhora a visibilidade sobre a saúde de uma aplicação ou sistema e ajuda a depurar comportamentos difíceis de reproduzir localmente.

O rastreamento distribuído é essencial para sistemas distribuídos, que frequentemente apresentam problemas não determinísticos ou complexos demais para serem reproduzidos em um ambiente local.

Para entender o rastreamento distribuído, é importante conhecer seus principais componentes: logs, spans e traces.

Logs

Um log é uma mensagem com carimbo de tempo emitida por serviços ou componentes. Diferente dos rastreamentos, os logs não estão necessariamente associados a uma solicitação ou transação específica. Eles estão presentes em praticamente todo software e foram amplamente utilizados por desenvolvedores e operadores para entender o comportamento dos sistemas.

Exemplo de log:

I, [2021-02-23T13:26:23.505892 #22473]  INFO -- : [6459ffe1-ea53-4044-aaa3-bf902868f730] Started GET "/" for ::1 at 2021-02-23 13:26:23 -0800

No entanto, os logs não são suficientes para rastrear a execução do código, pois geralmente carecem de informações contextuais, como o local de origem da chamada.

Os logs se tornam muito mais úteis quando são incluídos como parte de um span ou quando estão correlacionados a um trace e um span.

Spans

Um span representa uma unidade de trabalho ou uma operação. Ele rastreia operações específicas de uma solicitação, fornecendo uma visão detalhada do que ocorreu durante sua execução.

Um span inclui:

  • Nome
  • Dados temporais
  • Mensagens de log estruturadas
  • Metadados (Atributos) que fornecem mais informações sobre a operação rastreada.

Atributos de Span

Os atributos são metadados associados a um span.

Chave Valor
http.request.method GET
network.protocol.version 1.1
url.path /webshop/articles/4
url.query ?s=1
server.address example.com
server.port 8080
url.scheme https
http.route /webshop/articles/:article_id
http.response.status_code 200
client.address 192.0.2.4
client.socket.address 192.0.2.5 (o cliente passa por um proxy)
user_agent.original Mozilla/5.0 (Windows NT 10.0; Win64; ...)

Rastreamentos Distribuídos

Um rastreamento distribuído (trace) registra os caminhos percorridos por solicitações (feitas por uma aplicação ou usuário final) enquanto atravessam arquiteturas multi-serviço, como aplicações baseadas em microsserviços ou serverless.

Um trace é composto por um ou mais spans:

  • O span raiz representa o início e o fim de uma solicitação.
  • Os spans filhos fornecem um contexto detalhado sobre o que ocorre durante a solicitação.

Sem rastreamento, identificar a causa raiz de problemas de desempenho em sistemas distribuídos pode ser desafiador. O rastreamento simplifica a depuração e facilita o entendimento de sistemas complexos, detalhando o que acontece com uma solicitação enquanto ela se propaga pelo sistema.

Muitos backends de observabilidade visualizam os traces como diagramas de cascata (waterfall diagrams), que demonstram a relação entre spans pai e filhos, representando relações hierárquicas e aninhadas.

Propagação de Contexto

Entenda o conceito que viabiliza o Rastreamento Distribuído.

Com a propagação de contexto, os sinais podem ser correlacionados entre si, independentemente de onde são gerados. Embora não se limite apenas ao rastreamento, a propagação de contexto permite que os rastreamentos construam informações causais sobre um sistema que está distribuído de forma arbitrária entre processos e limites de rede.

Para entender a propagação de contexto, é necessário conhecer dois conceitos principais: contexto e propagação.

Contexto

O contexto é um objeto que contém as informações necessárias para que os serviços emissores e receptores, ou unidades de execução, possam correlacionar um sinal com outro.

Por exemplo: se o serviço A chama o serviço B, um span do serviço A, cujo ID está presente no contexto, será utilizado como span pai para o próximo span criado no serviço B. O ID do rastreamento (trace ID) também será incluído no contexto e utilizado para o próximo span criado no serviço B. Isso significa que esse novo span fará parte do mesmo rastreamento que o span do serviço A.

Propagação

A propagação é o mecanismo responsável por mover o contexto entre serviços e processos. Ela serializa ou desserializa o objeto de contexto e fornece as informações relevantes para que o contexto seja transferido de um serviço para outro.

Geralmente, a propagação é gerenciada automaticamente pelas bibliotecas de instrumentação e é transparente para o usuário. No entanto, caso seja necessário realizar a propagação de contexto manualmente, você pode utilizar a API de Propagadores (Propagators API) de cada biblioteca de instrumentação.

Sinais

Conheça as categorias de telemetria suportadas pelo Priax e bibliotecas de instrumentação compatíveis:

O objetivo de uma biblioteca de instrumentação é coletar, processar e exportar sinais. Sinais são saídas do sistema que descrevem a atividade subjacente do sistema operacional e das aplicações em execução em uma plataforma. Um sinal pode representar algo que você deseja medir em um ponto específico no tempo, como a temperatura ou o uso de memória, ou um evento que percorre os componentes de um sistema distribuído e que você gostaria de rastrear.

Com o Priax você pode agrupar diferentes sinais para observar o funcionamento interno de uma mesma tecnologia sob diferentes perspectivas.

Atualmente, o Priax é capaz de exibir, detalhar, quantificar e detalhar as seguintes categorias de sinais:

  • Rastreamentos (traces)
  • Métricas
  • Logs
  • Baggage

Rastreamentos (Traces)

O caminho de uma solicitação através da sua aplicação.

Os rastreamentos nos dão uma visão geral do que acontece quando uma solicitação é feita a uma aplicação. Seja sua aplicação um monólito com um único banco de dados ou uma complexa malha de serviços, os rastreamentos são essenciais para entender o “caminho” completo que uma solicitação percorre na sua aplicação.

Vamos explorar isso com três unidades de trabalho representadas como Spans (faixas de execução):

Observação
Os exemplos de JSON a seguir não representam um formato específico, especialmente o OTLP/JSON, que é mais detalhado.

1. Span Hello:
{  
  "name": "hello",  
  "context": {  
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",  
    "span_id": "051581bf3cb55c13"  
  },  
  "parent_id": null,  
  "start_time": "2022-04-29T18:52:58.114201Z",  
  "end_time": "2022-04-29T18:52:58.114687Z",  
  "attributes": {  
    "http.route": "some_route1"  
  },  
  "events": [  
    {  
      "name": "Guten Tag!",  
      "timestamp": "2022-04-29T18:52:58.114561Z",  
      "attributes": { "event_attributes": 1 }  
    }  
  ]  
}

 

Este é o span raiz, indicando o início e o fim da operação inteira. Observe que ele tem um campo trace_id, mas não tem parent_id, o que o caracteriza como a raiz do rastreamento.

2. Span hello-greetings:
{
  "name": "hello-greetings",
  "context": {
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
    "span_id": "5fb397be34d26b51"
  },
  "parent_id": "051581bf3cb55c13",
  "start_time": "2022-04-29T18:52:58.114304Z",
  "end_time": "2022-04-29T22:52:58.114561Z",
  "attributes": {
    "http.route": "some_route2"
  },
  "events": [
    {
      "name": "hey there!",
      "timestamp": "2022-04-29T18:52:58.114561Z",
      "attributes": {
        "event_attributes": 1
      }
    },
    {
      "name": "bye now!",
      "timestamp": "2022-04-29T18:52:58.114585Z",
      "attributes": {
        "event_attributes": 1
      }
    }
  ]
}

Este span encapsula tarefas específicas, como exibir saudações, e seu parent_id é o ID do span raiz hello. Ele compartilha o mesmo trace_id, indicando que faz parte do mesmo rastreamento.

3. Span hello-salutations:
{  
  "name": "hello-salutations",  
  "context": {  
    "trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",  
    "span_id": "93564f51e1abe1c2"  
  },  
  "parent_id": "051581bf3cb55c13",  
  "start_time": "2022-04-29T18:52:58.114492Z",  
  "end_time": "2022-04-29T18:52:58.114631Z",  
  "attributes": {  
    "http.route": "some_route3"  
  },  
  "events": [  
    {  
      "name": "hey there!",  
      "timestamp": "2022-04-29T18:52:58.114561Z"  
    }  
  ]  
}

Este span representa a terceira operação neste rastreamento e, assim como o anterior, é um filho do span raiz (hello). Isso também o torna um irmão do span hello-greetings

Esses três blocos de JSON compartilham o mesmo trace_id e utilizam o parent_id para representar a hierarquia. Isso cria o rastreamento completo!

Uma observação importante é que cada Span se assemelha a um log estruturado, com contexto, correlação e hierarquia embutidos. Contudo, esses “logs estruturados” podem vir de diferentes processos, serviços, VMs ou datacenters, permitindo que o rastreamento represente uma visão ponta a ponta de qualquer sistema.

O que é uma Span?

Uma span representa uma unidade de trabalho ou operação e inclui:

  • Nome
  • ID do Span pai (vazio para spans raiz)
  • Timestamps de início e fim
  • Contexto do Span
  • Atributos
  • Eventos
  • Links
  • Status do Span

Exemplo de span:

{
  "name": "/v1/sys/health",
  "context": {
    "trace_id": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
    "span_id": "086e83747d0e381e"
  },
  "parent_id": "",
  "start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
  "end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
  "status_code": "STATUS_CODE_OK",
  "status_message": "",
  "attributes": {
    "net.transport": "IP.TCP",
    "net.peer.ip": "172.17.0.1",
    "net.peer.port": "51820",
    "net.host.ip": "10.177.2.152",
    "net.host.port": "26040",
    "http.method": "GET",
    "http.target": "/v1/sys/health",
    "http.server_name": "mortar-gateway",
    "http.route": "/v1/sys/health",
    "http.user_agent": "Consul Health Check",
    "http.scheme": "http",
    "http.host": "10.177.2.152:26040",
    "http.flavor": "1.1"
  },
  "events": [
    {
      "name": "",
      "message": "OK",
      "timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
    }
  ]
}