A equipe de engenheiros do Uber lançou sua plataforma de métricas M3, que tem sido usada internamente há alguns anos, como Open Source. A plataforma foi construída para substituir seu sistema baseado em Graphite, e então fornecer gerenciamento de cluster, agregações, coleta de dados, gerenciamento de armazenamento, um banco de dados de séries temporais distribuído (TSDB) e um mecanismo de consulta com sua própria linguagem M3QL.
O sistema anterior de coleta de métricas e monitoramento era baseado no Graphite, apoiado por um cluster fragmentado (sharded) de Carbon, usando o Nagios para alertas e o Grafana para dashboards. Os problemas incluíam pouca resiliência e clusterização, alto custo operacional para expandir o cluster de Carbon, e a falta de replicação que fez cada nó ser um ponto de falha. O M3 - o novo sistema de métricas - nasceu dessas deficiências. Além da escalabilidade e consultas globais entre datacenters, as metas para o novo sistema foram a capacidade de marcar métricas, e manter a compatibilidade retroativa com os serviços que emitem métricas nos formatos StatsD e Graphite. Rob Skillington, engenheiro de software no Uber, descreve a arquitetura do M3 em um artigo. Atualmente o M3 armazena 6.6 bilhões de séries temporais, agrega 500 milhões de métricas por segundo, e armazena 20 milhões de métricas por segundo.
A versão inicial do M3 tinha componentes Open Sources como statsite para agregação, Cassandra para o armazenamento, e Elasticsearch para a indexação. Cada componente foi gradualmente substituído por uma implementação interna devido ao aumento da sobrecarga operacional e à demanda por novas funcionalidades. Devido à ampla utilização do Prometheus em várias equipes do Uber, o M3 foi construído para integrar-se com o Prometheus como um backend de armazenamento remoto.
A integração com o Prometheus é feita através do componente sidecar que escreve na instância de M3DB regional e distribui as queries "para os coordenadores inter-regionais os quais coordena a leitura a partir da instância regional do M3DB (o mecanismo de armazenamento)". Este modelo é similar a forma como o Thanos funciona, uma extensão para o Prometheus que fornece a cross-cluster federation, armazenamento ilimitado e consultas globais em clusters. No entanto a equipe do Uber escolheu não usar o Thanos por vários motivos, principalmente pela alta latência para métricas que não estão armazenadas localmente. O Thanos extrai e armazena em cache os dados de métricas do AWS S3 que vinha com uma latência associada, bem como o uso adicional de disco para cache, que eram inviáveis para o Uber devido aos seus requisitos de latência e à grande quantidade de dados.
O mecanismo de busca do M3 fornece uma exibição global e única de todas as métricas sem necessitar de replicação de dados entre as regiões. As métricas são escritas na instância regional do M3DB e a replicação é local para uma região. As consultas vão para ambas: a instância regional, bem como para o coordenador em uma região remota onde as métricas estão armazenadas. Os resultados são agregados localmente, e o processamento futuro é planejado para que qualquer consulta de agregação ocorra nas coordenações remotas.
O M3 permite que os usuários especifiquem o período de retenção e a granularidade por métrica para o armazenamento, como o Carbon faz. O mecanismo de armazenamento do M3 replica cada métrica em três réplicas em uma região. Para reduzir o uso de disco, os dados são compactados usando um algoritmo de compressão personalizado. A maioria das base de dados de séries temporais possuem um recurso de compactação em que os blocos de dados menores são reescritos em blocos maiores, e reestruturados para melhorar o desempenho das consultas. O M3DB evita compactações sempre que possível, para maximizar a utilização dos recursos do host permitindo mais escritas simultâneas e fornecendo latência constante de escrita/leitura.
Skilligton diz no artigo que "o M3DB apenas compacta dados baseados em tempo quando é absolutamente necessário, tal como dados de preenchimento - metadados ou quando faz sentido combinar arquivos de índice de janela de tempo". As métricas são reduzidas usando um modelo de streaming em que a redução da amostragem acontece quando as métricas entram.
A linguagem de consulta própria do M3 - M3QL - é usada internamente no Uber devido aos recursos que não estão disponíveis no PromQL. Existem limites para a cardinalidade de métricas que podem ser manipuladas, que diz respeito mais em termos de consulta do que de armazenamento. O armazenamento do M3 também otimiza o tempo de acesso utilizando filtros Bloom e índices em arquivos mapeados em memória. Um filtro Bloom é usado para determinar se algo pode existir em um conjunto, e no M3 é usado para determinar se uma série que é consultada precisa ser trazida do disco. O time está trabalhando em adicionar suporte para rodar o M3 no Kubernetes.
O M3 é escrito em Go e está disponível no GitHub.