Analytics

29 ago, 2016

uMirrorMaker: Replicador robusto Kafka da engenharia da Uber

Publicidade

Pipeline de analytics da Uber

Na Uber, usamos o Apache Kafka como um barramento de mensagens para conectar diferentes partes do ecossistema. Nós coletamos logs do sistema e de aplicativos, bem como dados de eventos dos aplicativos do passageiro e do motorista. Em seguida, tornamos esses dados disponíveis para uma variedade de consumos por meio do Kafka.

uber-1

Os dados fluem através de pipelines Kafka para alimentar muitos dos casos de uso de análise da Uber à direita.

Dados em Kafka alimentam ambos os pipelines em tempo real e de lote. O dados antigos são para atividades como métricas de negócios, depuração, alertas e dashboards. Os dados do pipeline de lote são mais exploratórios, tais como ETL no Apache Hadoop e HP Vertica.

Neste artigo, nós descrevemos uMirrorMaker, uma solução open source da Uber para replicar dados do Apache Kafka de forma robusta e confiável. Esse sistema estende o projeto original do MirrorMaker do Kafka e se concentra em altíssima confiabilidade, perda zero de dados e facilidade de operação. Em produção desde novembro de 2015, uMirrorMaker é uma peça-chave da infraestrutura de multi data center da Uber.

O que é um Mirror Maker, e por que precisamos de um?

Dado o uso em larga escala do Kafka dentro da Uber, acabamos utilizando vários clusters em diferentes data centers. Para uma série de casos de uso, precisamos olhar para a visão global desses dados. Por exemplo, a fim de calcular as métricas de negócios relacionados com viagens, é preciso reunir informações de todos os data centers e analisá-las em um só lugar. Para conseguir isso, temos historicamente utilizado a ferramenta open source MirrorMaker fornecida com o pacote do Kafka para replicar dados entre os data centers, como mostrado abaixo.

uber-2

O pipeline de dados da Uber espelha dados em múltiplos data centers.

MirrorMaker (como parte do Kafka 0.8.2) em si é bastante simples. Ele usa um alto nível de consumidor Kafka para buscar os dados do cluster de origem e, em seguida, alimenta esses dados em um produtor Kafka para despejar no cluster de destino.

Limitações do MirrorMaker do Kafka na Uber

Embora a nossa configuração inicial do MirrorMaker seja suficiente, logo tivemos problemas de escalabilidade. Como o número de tópicos e a taxa de dados (bytes/segundo) cresceram, começamos uma ver entrega atrasada de dados ou a perda completa dos dados que entram no cluster agregado, resultando em problemas de produção e reduzindo a qualidade dos dados. Alguns dos principais problemas com a ferramenta MirrorMaker existente (a partir da 0.8.2) para os casos de uso específicos da Uber estão listados abaixo:

  • Reequilíbrio caro. Como mencionado anteriormente, cada trabalhador MirrorMaker usa um consumidor de alto nível. Esses consumidores muitas vezes passam por um processo de reequilíbrio. Eles negociam entre si para decidir quem fica com a propriedade da partição tópico (feito via Apache Zookeeper). Esse processo pode tomar um longo tempo; temos observado cerca de 5 a 10 minutos de inatividade em determinadas situações. Isso é um problema, uma vez que viola a nossa garantia de latência de ponta a ponta. Além disso, os consumidores podem desistir depois de 32 tentativas de reequilíbrio e ficarem presos para sempre. Infelizmente, vimos isso acontecer em primeira mão algumas vezes. Após cada tentativa de reequilíbrio, vimos um padrão de tráfego semelhante:

uber-3

MirrorMaker do Kafka produz problemas de inatividade quando os consumidores tentam reequilibrar.

Após a inatividade durante o reequilíbrio, MirrorMaker teve um grande acúmulo de dados que teve que acompanhar. Isso resultou num pico de tráfego no cluster de destino e, subsequentemente, em todos os consumidores downstream, levando a interrupções de produção e aumento da latência ponta a ponta.

  • Dificuldade em adicionar tópicos. Na Uber, devemos especificar uma whitelist de tópicos dentro de nossa ferramenta de espelhamento para controlar a quantidade de fluxos de dados através do link WAN. Com o MirrorMaker do Kafka, essa whitelist estava completamente estática, e foi necessário reiniciar o cluster MirrorMaker para adicionar novos tópicos. Reiniciar é caro, uma vez que obriga os consumidores de alto nível a reequilibrar. Isso se tornou um pesadelo operacional!
  • Possível perda de dados. O velho MirrorMaker teve um problema – que parece ter sido corrigido na versão mais recente – com commit automático compensado que poderia ter resultado na perda de dados. O consumidor de alto nível automaticamente comitou os deslocamentos para as mensagens transferidas. Se uma falha ocorresse antes que o MirrorMaker pudesse verificar se ele realmente escreveu as mensagens para o cluster de destino, então essas mensagens seriam perdidas.
  • Problemas com sincronização de metadados. Nós também esbarramos em um problema operacional quando a configuração de caminho foi atualizada. Para adicionar ou excluir tópicos da whitelist, listamos todos os nomes de tópico no final do arquivo de configuração, que foi lido durante a inicialização do MirrorMaker. Algumas vezes, a configuração falhou na atualização de um dos nodes. Isso derrubou todo o cluster, uma vez que os vários trabalhadores MirrorMaker não concordaram com a lista de tópicos a ser replicada.

Por que desenvolvemos o uMirrorMaker

Foram considerados as seguintes alternativas para solucionar os problemas acima mencionados:

a – Dividir em vários clusters MirrorMaker. A maioria dos problemas listados acima resultou do processo de reequilíbrio do consumidor de alto nível. Uma maneira de reduzir o seu impacto é restringir o número de partições tópico replicadas por um cluster MirrorMaker. Assim, terminaríamos com vários clusters MirrorMaker, cada um replicando um subconjunto dos tópicos a serem agregados.

Prós:

– Incluir novos tópicos é fácil. Basta criar um novo cluster.

– Reiniciar cluster do MirrorMaker acontece rapidamente.

Contras:

– É mais um pesadelo operacional: temos de implantar e manter vários clusters.

b – Usar Apache Samza para replicação. Uma vez que o problema é com o consumidor de alto nível (a partir da versão  0.8.2), uma solução é usar o Kafka SimpleConsumer e adicionar as peças faltantes da eleição do líder e atribuição da partição. Apache Samza, um framework de processamento de fluxo, já atribui estaticamente partições para os trabalhadores. Podemos então simplesmente utilizar um trabalho Samza para replicar e agregar dados para o destino.

Prós:

– É altamente estável e confiável.

– É fácil de manter. Podemos replicar um monte de tópicos usando um trabalho.

– Reiniciar o trabalho tem um impacto mínimo sobre o tráfego da replicação.

Contras:

– Ainda é muito estático. Nós precisamos reiniciar o trabalho para adicionar e/ou eliminar tópicos.

– Temos de reiniciar o trabalho para adicionar mais trabalhadores (a partir do Samza 0.9).

– A expansão de tópicos precisa ser explicitamente tratada.

c – Usar um consumidor Kafka baseado no Apache Helix. Em última análise, decidimos usar um consumidor Kafka baseado em Helix. Nesse caso, estamos usando Apache Helix para atribuir partições para os trabalhadores, e cada trabalhador usa o SimpleConsumer para replicar os dados.

Prós:

– Adicionar e excluir tópicos é muito fácil.

– Adicionar e excluir nodes ao cluster MirrorMaker é muito fácil.

– Nós nunca precisamos reiniciar o cluster por uma razão operacional (apenas para atualizações).

– É altamente confiável e estável.

Contras:

– Isso introduz uma dependência no Helix. (isso é ok, já que o próprio Helix é muito estável e podemos usar um cluster Helix para vários clusters MirrorMaker.)

uMirrorMaker Overview

uber-4

Kafka MirrorMaker produz problemas de inatividade quando os consumidores tentam reequilibrar.

Vários componentes do uMirrorMaker funcionam de maneiras diferentes em direção à confiabilidade e estabilidade:

1 – O controlador Helix uMirrorMaker, na verdade, um cluster de nodes, tem várias responsabilidades:

  • Distribuir e atribuir partições de tópicos para cada processo de trabalho
  • Manipular a adição/exclusão de tópicos/partições
  • Manipular a adição/exclusão de trabalhadores uMirrorMaker
  • Detectar falhas de nodes e redistribuir essas partições tópico específicas

O controlador usa Zookeeper para realizar todas essas tarefas. Ele também expõe uma API REST simples, a fim de adicionar/remover/modificar tópicos a serem espelhados.

2 – Um trabalhador uMirrorMaker, semelhante a um processo de trabalho no recurso de espelhamento do Kafka, replica um determinado conjunto de partições tópico a partir do cluster de origem para o cluster de destino. Em vez de um processo de reequilíbrio, o controlador uMirrorMaker determina a atribuição do uMirrorMaker. Além disso, em vez de usar o consumidor de alto nível do Kafka, usamos uma versão simplificada chamada DynamicKafkaConsumer.

3 – Um agente Helix para cada trabalhador uMirrorMaker é notificado sempre que há uma alteração (adição/exclusão de partições tópico). Por sua vez, ele notifica o DynamicKafkaConsumer para adicionar/remover partições tópico.

4 – Uma instância DynamicKafkaConsumer, que é uma modificação do consumidor de alto nível, existe em cada trabalhador uMirrorMaker. Ela remove a parte do reequilíbrio e adiciona um mecanismo para adicionar/excluir partições tópico em tempo real.

Por exemplo, digamos que queremos adicionar um novo tópico a um cluster uMirrorMaker existente. O fluxo de eventos é o seguinte:

  • Administrador Kafka adiciona o novo tema para o controlador usando o seguinte comando:

uber-5

  • O controlador uMirrorMaker descobre o número de partições para testTopic e mapeia partições tópico para os trabalhadores ativos. Em seguida, ele atualiza os metadados do Zookeeper para refletir esse mapeamento.
  • Cada agente Helix correspondente recebe uma chamada de retorno com a notificação da adição dessas partições tópico. Por sua vez, esse agente invoca a função addFetcherForPartitions do DynamicKafkaConsumer.
  • O DynamicKafkaConsumer posteriormente registra essas novas partições, encontra os corretores líderes correspondentes, e os adiciona para buscar os tópicos para iniciar o espelhamento de dados.

Para mais detalhes sobre a implementação, consulte o wiki do projeto uMirrorMaker.

Impacto na estabilidade global

Desde o lançamento inicial do uMirrorMaker em produção na Uber, cerca de oito meses atrás, nós não vimos um único problema de produção com ele (em contraste com uma falha de algum tipo quase todas as semanas antes da sua implementação). O gráfico abaixo ilustra o cenário de adicionar novos tópicos à whitelist na ferramenta de espelhamento em produção. O primeiro gráfico mostra o total das partições tópico pertencentes a cada trabalhador uMirrorMaker. Essa contagem aumenta para cada novo tópico a ser adicionado.

uber-6

O segundo gráfico mostra o tráfego uMirrorMaker correspondente fluindo para o cluster de destino. Não há nenhum período de inatividade ou picos de carga, como no antigo Kafka MirrorMaker:

uber-7

uMirrorMaker mantém operação estável na presença de alterações.

Em geral, as vantagens de uMirrorMaker incluem:

  • Estabilidade: Reequilíbrio agora só acontece durante a inicialização e quando um node é adicionado ou excluído. Além disso, isso afeta apenas um subconjunto das partições tópico, em vez de causar uma completa inatividade como antes.
  • Escalabilidade mais fácil: Adicionar um novo node a um cluster existente é agora muito mais simples. Como a atribuição de partição é agora estática, podemos mover de forma inteligente apenas um subconjunto das partições para o novo node. Outras partições tópico permanecem inalteradas.
  • Operação mais fácil: Uma nova ferramenta de espelhamento na Uber suporta whitelists dinâmicas. Nós agora não precisamos reiniciar o cluster ao adicionar/apagar/expandir tópicos Kafka.
  • Zero perda de dados: uMirrorMaker garante a perda zero de dados, uma vez que comita checkpoints somente após os dados terem sido persistidos no cluster de destino.

Desde o início, uMirrorMaker tem sido uma adição valiosa para a missão da equipe da plataforma de streaming de conectar diferentes partes do ecossistema de Engenharia da Uber em conjunto, através de mensagens e modelo de publicação-assinatura (usando Kafka). Como parte dessa missão, estamos construindo uma nova plataforma de analytics para calcular métricas de negócio no topo do fluxo de dados. Parece interessante? Veja nossas aberturas de dados de infraestrutura em tempo real na página de carreira da Uber se você estiver interessado em participar do próximo capítulo desta história.

***

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