OpenTelemetry e os Desafios dos Intervalos de Longa Duração

OpenTelemetry e os Desafios dos Intervalos de Longa Duração

O OpenTelemetry (OTel) tomou o cenário da observabilidade de assalto, e por um bom motivo! Em algum momento da última década, o mundo do software silenciosamente começou a ver os protocolos como padrões, evoluindo-os abertamente e adotando o código aberto orientado pela comunidade.

Aproveitando esse momento, o OTel rapidamente se tornou o segundo projeto de maior velocidade no ecossistema CNCF . Com foco na neutralidade do fornecedor e na interoperabilidade da linguagem, permitindo que os engenheiros se concentrem em entender seus sistemas em vez de depurar seus depuradores, o sucesso do OTel parece quase óbvio em retrospecto.

Dito isso, apesar de toda a energia em torno do OpenTelemetry , nem sempre é uma experiência sem atrito. Há algumas coisas que podem ser realmente desafiadoras de abordar nos modelos mentais e suposições do OpenTelemetry. Um desses enormes obstáculos a serem abordados no mundo real são os intervalos de longa duração.

Longo... Correndo? O quê? Períodos de execução longa!

Bem, OK, vou voltar um pouco e explicar algumas coisas. O cenário OTel pode ser avassalador no começo, pois tem muitos conceitos para saber antes de começar. Quando as pessoas falam sobre OpenTelemetry, geralmente estão falando sobre rastreamento distribuído. Embora eu vá focar apenas nas partes relevantes, aqui está uma visão geral completa, se você estiver interessado.

Ao depurar um sistema, sua primeira pergunta normalmente é algo como "Que ação aconteceu?" No entanto, uma ação da perspectiva do usuário final se traduz em várias da perspectiva do sistema. Para reconciliar isso, a OTel tem o conceito de um intervalo, que é uma ação da perspectiva do usuário final. Dentro desse intervalo, você tem mais intervalos que representam todas as ações da perspectiva do sistema. Nós chamamos o "intervalo que representa o ponto de vista do usuário" de um rastreamento ... normalmente.

No entanto, a parte relevante de um span para nós é o fato de que ele contém algumas coisas: um ID, um ID de rastreamento, um horário de início e um horário de término. Quando você envia seu pequeno pacote de alegria para seu backend de observabilidade, ele vem com todas as quatro informações (e os dados reais também). Mas isso significa que os spans têm uma duração, o que tem algumas implicações profundas.

Acontece também que, na prática, muitas ferramentas realmente não querem que o comprimento de um vão seja maior que... bem, não muito longo.

Por que as ferramentas se importam com isso?

Há algumas grandes razões! Uma delas é que a especificação da API OTel declara algo muito importante: todos os spans devem ser encerrados, e essa é a responsabilidade do implementador. Além disso, ela declara que se um desenvolvedor esquecer de encerrar o span, a implementação da API pode fazer praticamente qualquer coisa com ele. A especificação do kit de desenvolvimento de software (SDK) fornece processadores de span integrados , mas eles operam apenas em spans finalizados.

Em outras palavras, a perspectiva do usuário é um span, e qualquer span incompleto provavelmente será perdido para sempre. Se o span incompleto for o span raiz, todos os spans internos que foram enviados parecerão órfãos, se o backend puder sequer lidar com eles existentes. Na prática, isso significa que spans raiz que são maiores do que cerca de cinco segundos provavelmente causarão problemas.

Outro motivo pelo qual as ferramentas se importam com isso é a amostragem. Quando você envia baldes de dados de um lugar para outro, é razoável perguntar como você pode representar esses dados melhor e talvez evitar enviar alguns deles. É aí que entra a amostragem.

O serviço de amostragem pega a telemetria e decide se deve ou não enviá-la para o backend (além de alguns ajustes matemáticos sofisticados que fazem tudo funcionar). Legal! Exceto que há um pequeno problema: como ele decide quando algo é relevante para enviar ou não? As decisões de amostragem precisam funcionar em um intervalo completo e, muitas vezes, operam em intervalos de rastreamento inteiros. Isso não funciona se você perder o intervalo raiz!

Então, estranhamente, não apenas os spans incompletos provavelmente são perdidos para sempre, e não apenas os spans com maior probabilidade de serem perdidos são frequentemente os mais valiosos, mas todas as suas otimizações de custo, rede e computação quebram. Ai.

Você já tentou não ter longos períodos?

Uma ótima solução para um problema é consertá-lo, mas uma solução incrível para um problema é não tê-lo! Podemos... simplesmente não ter longos períodos? É um pensamento nobre, mas acontece que encontraremos esse problema independentemente de quão longos sejam nossos períodos. Temos falado sobre longos períodos, mas isso é, na verdade, mais sobre períodos interrompidos e incompletos.

A razão para isso é que spans são basicamente os mesmos que uma transação de banco de dados em termos de seu modelo de dados. Então, sempre que você se depara com uma situação em que precisa enviar transações pela rede entre vários sistemas, você se deparou com um cenário que os especialistas gostam de chamar de "estar em um momento realmente ruim".

Você pode tentar muitas soluções! Aqui estão algumas que as pessoas usaram:

  • Refatore seu código para representar ações em partes menores. Divida uma ação longa em intervalos .
  • Crie menos rastros e carregue mais dados nos intervalos filhos .
  • Finalize manualmente o intervalo raiz antecipadamente.
  • Faça transformações infundadas e incompletas em seus dados para reescrever IDs de intervalo, IDs de rastreamento e links . (Repita comigo: "Juro solenemente que provavelmente evitarei isso na produção.")
  • Desative o ID de rastreamento e utilize links em seu lugar .
  • Certifique-se de que o contexto do seu rastreamento esteja correto e que você não esteja inventando um intervalo raiz por acidente .

Infelizmente, nenhuma delas aborda a questão fundamental: quando dissemos que os intervalos devem ser encerrados e demos uma duração, nós os tornamos transações — e lidar com transações entre sistemas é difícil.

Para piorar a situação, embora você possa pensar que intervalos interrompidos não acontecem com muita frequência, na verdade eles acontecem com bastante frequência:

  • No backend: sempre que um aplicativo reinicia no meio de uma solicitação, ou trava, ou a rede falha, ou …
  • No frontend: sempre que um cliente web navega, fecha ou atualiza uma aba, cancela uma ação, ou o loop de eventos do navegador é interrompido, ou…
  • No celular: tudo isso e muito mais!

No entanto, a sorte favorece os criativos. Agora que sabemos que estamos realmente lidando com um problema de semântica de transação (que por acaso parece um problema de "não ter spans de longa duração"), podemos olhar toda a literatura existente sobre isso. Certamente alguém resolveu isso — ou, uhh, pelo menos tentou?

Soluções criativas para vãos irregulares

Colocando nossos chapéus pensantes e óculos de pesquisa, há uma riqueza de informações envolvendo bancos de dados, fluxos de eventos e transações distribuídas em geral. No entanto, há um pequeno problema: não muito disso se parece com OTel, e é difícil ver como as soluções se aplicam. Mas e se esticássemos um pouco a definição de um intervalo e, dadas as restrições... trapaceássemos um pouquinho? Isso nos permitiria reaproveitar algumas soluções de outras tecnologias com restrições semelhantes, talvez?

Há dois temas recorrentes no tratamento de transações: snapshots e logs de write-ahead. Na verdade, os logs como uma abstração de dados são um dos blocos de construção fundamentais de sistemas distribuídos. Os logs como uma estrutura de dados ordenada somente para anexação acabam sendo a coisa perfeita para construir snapshots em cima, e acontece que os processadores de span no OpenTelemetry SDK podem ser pensados ​​como um log de write-ahead na memória. OK, você tem que apertar os olhos um pouco para pensar nisso assim, mas, na verdade, é.

Incrível! Não só temos um padrão adotado pela indústria para lidar com transações na forma de logs, mas já temos a maioria das peças necessárias para construir snapshots! Snapshots não resolverão todos os nossos problemas, mas é uma melhoria enorme, e torna dados parciais utilizáveis ​​— o que é inestimável para depuração.

Então, como fazemos isso?

Primeiro, precisamos reformular o processo: em vez de enviar intervalos para nosso backend, estamos gravando intervalos em um log e depois replicando-os para o backend de forma consistente.

Então, como fazemos isso?

Boa pergunta! Acontece que a Embrace implementou essa solução e explicou por que eles fizeram isso . Quanto ao como , embora a replicação de log tenha uma gama enorme de soluções possíveis, uma simples requer apenas algumas pequenas mudanças tanto no cliente quanto no servidor.

Primeiro, o cliente precisa enviar os instantâneos dos intervalos em andamento (isso requer um processador e exportador de intervalos personalizados). Em segundo lugar, o backend precisa processar e armazenar esses dados e aguardar que sejam finalizados. Terceiro, se esses intervalos nunca forem finalizados, eles ainda terão que ser massageados em um formato compatível com OTel graciosamente e enviados para o upstream. OK, menti. Não é simples.

Estamos omitindo muitos detalhes aqui.) Isso parece muito trabalho, mas o SDK e o backend da Embrace fazem tudo isso para você, incluindo lidar com os casos em que ocorrem interrupções e os spans não são finalizados. Melhor ainda, os spans são totalmente compatíveis com OTel quando são concluídos, o que significa que não há nada impedindo que essa solução chegue ao OpenTelemetry.

Tracer.getInstance().endSpan()

Uau! Nós cobrimos muito terreno aqui. Primeiro, falamos sobre o que são spans de longa duração, por que os encontramos, por que eles são um problema e como você não pode evitá-los, não importa o quanto você tente. Na verdade, você não só vai encontrá-los, mas qualquer tipo de situação que envolva spans incompletos ou interrompidos está sujeita a muitos dos mesmos modos de falha, que identificamos como um problema de semântica de transação.

Felizmente, descobrimos que a semântica de transações é um problema bem estudado, e conseguimos analisar uma ótima solução e apresentar um esboço de como isso pode funcionar com o OpenTelemetry.

Se você está vindo de uma abordagem tradicional focada em backend para observabilidade, você ficaria surpreso com o quão fundamentalmente diferente é o ambiente móvel. A Embrace tem um útil webinar sob demanda se você quiser saber mais: O que DevOps e SREs precisam saber sobre observabilidade móvel. Há também um guia útil: Superando os principais desafios na observabilidade móvel: Um guia para equipes modernas de DevOps e SRE.

Conteúdo Relacionado

Вернуться к блогу

Комментировать

Обратите внимание, что комментарии проходят одобрение перед публикацией.