Banco de Dados

15 ago, 2018

M3: plataforma de métricas de grande escala e código aberto da Uber para a Prometheus

Publicidade

Para facilitar o crescimento das operações globais da Uber, precisamos poder armazenar e acessar rapidamente bilhões de métricas em nossos sistemas de back-end a qualquer momento. Como parte de nossa infraestrutura de métricas robusta e escalável, construímos a M3, uma plataforma de métricas que está em uso na Uber há vários anos.

A M3 aloja de maneira confiável, métricas de grande escala em longas janelas de tempo de retenção. Para oferecer a outros na comunidade mais ampla esses benefícios, decidimos abrir o código-fonte da plataforma M3 como um back-end de armazenamento remoto para o Prometheus, uma solução popular de monitoramento e alerta.

Como sua documentação afirma, a escalabilidade e a durabilidade do Prometheus são limitadas por nodes únicos. A plataforma M3 tem como objetivo fornecer um armazenamento multi-inquilino integral, escalável e configurável para as métricas de Prometheus. Como parte desse esforço, lançamos recentemente o M3DB, o back-end de armazenamento escalonável do M3. O M3DB é um armazenamento de série temporal distribuído e um índice reverso com gravações fora de ordem configuráveis.

Além disso, estamos deixando em código aberto o M3 Coordinator, um sidecar de Prometheus que fornece uma interface de consulta e armazenamento global sobre os clusters do M3DB. O M3 Coordinator também realiza downsampling, bem como retenção ad hoc e agregação de métricas usando regras de retenção e rollup. Isso nos permite aplicar retenção e agregações específicas a subconjuntos de métricas dinamicamente com as regras armazenadas no etcd, que são executadas no binário de um node semente do M3DB.

Figura 1: O sidecar do M3 Coordinator é implantado junto com o Prometheus perto de clusters M3DB regionais locais que são replicados em zonas de disponibilidade, executando o etcd no mesmo binário.

Métricas antes do M3

No final de 2014, todos os serviços, infraestrutura e servidores da Uber emitiam métricas para uma pilha de Graphite que as armazenava usando o formato de arquivo Whisper em um cluster Carbon fragmentado. Usamos o Grafana para o painel e o Nagios para alertas, emitindo verificações de limite do Graphite por meio de scripts controlados por fonte.

Embora isso tenha funcionado por algum tempo, a expansão do cluster Carbon exigiu um processo de resharding manual e, devido à falta de replicação, a falha de um único disco do node causou a perda permanente de suas métricas associadas. Em suma, esta solução não foi capaz de atender às nossas necessidades na medida em que a empresa continuou a crescer.

Para garantir a escalabilidade do back-end de métricas da Uber, decidimos criar um sistema que fornecesse ingestão, armazenamento e consulta de métricas tolerantes a falhas como uma plataforma gerenciada. Nossos objetivos eram cinco:

  • Maior confiabilidade e escalabilidade: para garantir que possamos continuar a escalar o negócio sem nos preocuparmos com a perda de disponibilidade ou precisão de alertas e observabilidade.
  • Capacidade de consultas para retornar resultados entre centros de dados: para permitir a visibilidade global de serviços e infraestrutura em todas as regiões.
  • Contrato de nível de serviço de baixa latência: para garantir que os painéis e os alertas forneçam uma latência de consulta confiável que seja interativa e responsiva.
  • Métricas “marcadas” dimensionais de primeira classe: para oferecer o modelo de dados marcados e flexíveis que os rótulos da Prometheus e outros sistemas tornaram popular.
  • Compatibilidade retroativa: para garantir que centenas de serviços legados que emitem métricas StatsD e Graphite continuem funcionando sem interrupção.

Apresentando o M3

Depois de avaliar as alternativas de código aberto à nossa solução existente, descobrimos que nenhuma atenderia às nossas metas de eficiência ou escala de recursos e seria capaz de funcionar como uma plataforma de autoatendimento.

Inicialmente, o M3 utilizou componentes quase inteiramente de código aberto para funções essenciais, como statsite para agregação, Cassandra com Data Tiered Compactation Strategy para armazenamento de séries temporais e ElasticSearch para indexação. Devido à carga operacional, eficiência de custos e um conjunto de recursos cada vez maior, superamos gradualmente cada um deles.

Lançado em 2015, o M3 agora abriga mais de 6,6 bilhões de séries temporais. O M3 agrega 500 milhões de métricas por segundo e persiste 20 milhões de métricas por segundo resultantes para armazenamento globalmente (com M3DB), usando uma gravação de quorum para persistir cada métrica para três réplicas em uma região.

Ele também permite que os engenheiros criem políticas métricas que dizem ao M3 para armazenar certas métricas em retenções mais curtas ou mais longas (dois dias, um mês, seis meses, um ano, três anos, cinco anos, etc), e com uma granularidade específica (um segundo, dez segundos, um minuto, dez minutos, etc).

Isso permite que engenheiros e cientistas de dados armazenem, de forma inteligente, séries temporais em retenções diferentes com escopos excelentes e de granulação grossa, usando a correspondência de tag de métrica (rótulo) para as políticas de armazenamento definidas.

Por exemplo, os engenheiros podem optar por armazenar todas as métricas nas quais a tag de “aplicativo” é “mobile_api” e a tag “endpoint” é “inscrição” para granularidade de 30 dias a 10 segundos e granularidade de cinco anos a uma hora.

A integração com o Prometheus continua sendo uma prioridade cada vez mais importante para os usuários do M3 da Uber, tanto em termos de observabilidade para qualquer aplicativo que exporta métricas Prometheus quanto para monitoramento de sistemas usando node_exporter ou outros exportadores de métricas Prometheus de terceiros.

Historicamente, várias equipes da Uber executavam implantações significativas da Prometheus e, quando a carga operacional das equipes se tornava insustentável, criamos integrações no M3 para Prometheus, permitindo que essas equipes consultassem suas métricas em uma visão global em todos os centros de dados na loja de métricas de longo prazo durável do M3.

Figura 2: O pipeline de ingestão e armazenamento do M3 começa por agregar métricas em políticas definidas e, em seguida, armazená-las e indexá-las nos nodes de armazenamento do cluster do M3DB.

Com base em nossas experiências anteriores executando cargas de trabalho de armazenamento métrico cada vez mais altas, criamos o M3 para:

  • Otimizar todas as partes do pipeline de métricas, oferecendo aos engenheiros o máximo de armazenamento possível para a menor quantidade de gastos com hardware.
  • Garantir que os dados sejam o mais compactados possível para reduzir a área de cobertura do hardware, com um investimento significativo na otimização da compactação TSZ do Gorilla para compactar ainda mais os valores float64, que chamamos de compactação M3TSZ.
  • Manter uma memória enxuta para armazenamento para evitar que a memória se torne um gargalo, já que uma parte significativa de cada ponto de dados pode ser “gravado uma vez, nunca lido”. E, para manter o tempo de acesso rápido, mantemos um filtro Bloom e um índice de resumo por fragmento do bloco de janela de tempo na memória mmap’d, uma vez que permitimos consultas ad-hoc de até 100.000 séries temporais únicas em uma única consulta durante longos períodos de retenção (em alguns casos, abrangendo anos de retenção).
  • Evitar as compactações sempre que possível, incluindo o caminho de downsampling, para aumentar a utilização de recursos do host para mais gravações simultâneas e fornecer latência constante de gravação/leitura.
  • Usar um design nativo para armazenamento de série temporal que não exija atenção operacional vigilante para executar com um volume de gravação alto. (Descobrimos que Cassandra precisava de muita atenção operacional entre outros componentes que estávamos usando anteriormente).

Em seguida, discutimos algumas das maneiras pelas quais o M3 realiza esses objetivos por meio de sua arquitetura.

Figura 3: As consultas retornam métricas de todas as regiões, fazendo proxy das solicitações por meio dos coordenadores das regiões remotas, que leem seus resultados regionais de armazenamento e proxy novamente.

O M3 fornece uma visão global única de todas as métricas, evitando a necessidade de os clientes de upstream navegarem pelo roteamento, aumentando, assim, a simplicidade geral da capacidade de descoberta de métricas. Por exemplo, uma visão centralizada e all-in-one/todas em uma nos permite evitar a instalação de múltiplas fontes de dados Grafana para um único painel.

Além disso, para cargas de trabalho que causam falha em aplicativos entre regiões ou cargas de trabalho compartilhadas em todas as regiões, a visualização global única facilita muito a soma e consulta de métricas em todas as regiões em uma única consulta. Isso permite que os usuários vejam todas as operações de um tipo específico globalmente e analisem uma retenção mais longa para visualizar tendências históricas em um único local.

Para obter essa visualização de painel único sem o custo da replicação entre regiões, as métricas são gravadas no M3 para instâncias M3DB regionais locais. Nesta configuração, a replicação é local para uma região e pode ser configurada para ser isolada pela zona de disponibilidade ou pelo rack. As consultas se espalham pelas instâncias e coordenadores do M3DB da região local em regiões remotas onde as métricas são armazenadas, retornando blocos M3TSZ compactados para séries temporais correspondentes sempre que possível.

Em interações futuras, gostaríamos de projetar o M3 para enviar as agregações de consulta a regiões remotas para executar antes de retornar os resultados, bem como para o node de armazenamento local do M3DB, quando possível. Embora o rastreamento das métricas antes de serem armazenadas seja o ideal, nem todos os padrões de consulta são planejados antecipadamente, e as métricas estão sendo cada vez mais usadas de maneira ad hoc.

Menos compactações

Descobrimos que o Cassandra e outros sistemas de armazenamento que compactam blocos de dados juntos gastam uma grande fração dos recursos do sistema (CPU, memória e disco IO) apenas reescrevendo os dados armazenados. Como tratamos as métricas como imutáveis, não fazia sentido executarmos um sistema que desperdiça tantos recursos em compactação.

O próprio M3DB compacta somente dados baseados em tempo quando absolutamente necessário, como o preenchimento de dados ou quando faz sentido combinar arquivos de índice de janela de tempo juntos.

Essa estratégia de reduzir a necessidade de cargas de trabalho de compactação é generalizada na plataforma. Por exemplo, considere downsampling, que, semelhante às compactações, normalmente requer a leitura prévia de dados escritos e o cálculo de um agregado.

Isso requer a geração de grandes volumes de dados, o que resulta em um grande imposto sobre a rede (que pode ser caro com provedores de nuvem), CPU (para RPC e para serialização/desserialização) e de disco IO. Em vez disso, com o M3 optamos por reduzir downsample no momento da coleta, economizando espaço e recursos no momento da ingestão.

Políticas de armazenamento, retenção e downsampling

Não achamos que os engenheiros precisem gastar muito tempo pensando no ciclo de vida de suas métricas de aplicativos. No entanto, esse comportamento resulta em muita coleta de telemetria que pode não necessariamente precisar ser armazenada por um longo período de tempo.

Como aprendemos com nossa experiência no desenvolvimento do M3, uma estratégia de retenção eficaz mantém todas as métricas em alguns períodos de retenção razoáveis e distintos por padrão e exige que os usuários aceitem o subconjunto de métricas que desejam reter por um período de tempo mais longo.

As políticas de armazenamento de métricas da M3 definem os correspondentes de tag (rótulo) para associar políticas de agregação de retenção e redução de resolução em níveis excelentes ou de granulação grossa. O M3 permite que engenheiros e cientistas de dados definam regras padrão que se aplicam a todas as métricas, por exemplo:

  • Retenção: 2 dias, sem redução da resolução
  • Retenção: 30 dias, diminuídos para uma resolução de um minuto
  • E quaisquer outros

Para métricas mantidas em diferentes retenções ou resoluções para as regras padrão, os usuários podem definir políticas de armazenamento específicas, por meio de uma interface do usuário ou de definições sob controle de origem, para especificamente aceitar determinadas métricas. Por exemplo, um usuário poderia especificar o seguinte tipo de regra de mapeamento, da seguinte maneira:

 – name: Retain all disk_used metrics 
   filter: name:disk_used* device:sd*
   policies:
     – resolution: 10s
       retention:  2d
     – resolution: 1m
       retention:  30d
     – resolution: 1h
       retention:  5y

Os rollups ajudam a reduzir a latência de padrões de acesso a consultas específicas e agregam métricas entre dimensões no tempo da ingestão, em vez do tempo da consulta. O Prometheus usa regras de gravação para acumular métricas. Da mesma forma, o M3 possui regras de rollup que podem ser aplicadas no momento da ingestão, permitindo que políticas de armazenamento de retenção específicas sejam definidas para as métricas acumuladas resultantes.

Primeiros passos com o Prometheus e o M3

Para começar a usar o M3 como uma loja Prometheus escalável, os usuários precisam configurar um cluster do M3DB para armazenar e consultar métricas e instalar o sidecar do Coordinator M3 em suas instâncias do Prometheus – e é isso!

Para saber mais, confira os seguintes guias de documentação.

O M3 Coordinator sidecar do Prometheus escreve para instâncias do M3DB regionais locais e consultas se estendem aos M3 Coordinators inter-regionais que coordenam as leituras de suas instâncias do M3DB regionais locais.

Para cobranças de métricas, talvez seja mais simples continuar usando as regras de gravação da Prometheus e apenas aproveitar as políticas de armazenamento da M3 para selecionar diferentes retenções e políticas de redução de qualidade/downsampling conforme desejado para suas métricas.

No momento, as políticas de retenção de métricas de redução de escala/downsampling e correspondência ocorrem no sidecar do M3 Coordinator, o que significa que os usuários não podem somar/agregar métricas juntas no ingresso em várias instâncias do Prometheus com regras de agregação do M3.

Em vez disso, um usuário só pode acumular métricas de uma única instância do Prometheus. No futuro, gostaríamos de simplificar o processo de execução de um cluster agregador M3 regional para permitir que os usuários criem implementações em várias instâncias do Prometheus e aproveitem a redução da amostragem replicada usando a eleição de líder no topo do etcd.

Isso pode ser preferível a uma configuração típica de alta disponibilidade do Prometheus em que duas instâncias executam ativo-ativo e, consequentemente, gravam duas vezes as amostras para armazenamento de longo prazo (como M3DB).

Ajude-nos

O M3DB e o M3 Coordinator foram construídos como projetos de código aberto desde o início. Por favor, envie pedidos pull, problemas para o monorepo M3 e propostas para o repositório de propostas do M3.

Para melhorar o M3 de código aberto, estamos trabalhando ativamente em algumas coisas:

  • Trazer o M3 Coordinator e o novo índice reverso do M3DB para fora do beta
  • Liberar UI m3ctl para criação mais simples de regras de retenção e agregação de downsampling
  • Adicionar suporte padrão para StatsD e Graphite em M3 de código aberto
  • Solicitar feedback e contribuições da comunidade

Esperamos que você experimente o M3DB para sua infraestrutura de métricas com base no Prometheus e nos dê seu feedback!

Se você estiver interessado em lidar com desafios de infraestrutura em escala, considere se candidatar a um cargo em nossa equipe. Não deixe de visitar a página oficial de código aberto da Uber para obter mais informações sobre o M3 e outros projetos.

Assine nosso newsletter para acompanhar as mais recentes inovações da Engenharia da Uber.

***

Este artigo é do Uber Engineering. Ele foi escrito por Rob Skillington. A tradução foi feita pela Redação iMasters com autorização. Você pode conferir o original em: https://eng.uber.com/m3/