Back-End

29 mar, 2018

Apresentando QALM, o framework de gerenciamento de carga de QoS da Uber

Publicidade

Grande parte dos negócios da Uber envolve conectar pessoas a pessoas, tornando a confiabilidade de nossa plataforma de clientes crucial para o nosso sucesso. A plataforma de clientes suporta tudo, desde caronas e Uber Eats, até Uber Freight e Uber for Business.

Nossa equipe de plataformas possui quatro serviços com milhares de hosts, atendendo a um pico de tráfego de até 300 mil solicitações por segundo, com mais de 450 serviços internos.

Qualquer sistema dessa complexidade provavelmente sofrerá interrupções, especialmente um que tenha crescido tão rapidamente. Analisando as interrupções ocorridas ao longo de um período de seis meses, descobrimos que 28% poderiam ter sido mitigados ou evitados por meio da degradação graciosa.

Os três tipos mais frequentes de falhas que observamos foram devido a:

  • Alterações no padrão de solicitação de entrada, incluindo sobrecarga e agentes ruins.
  • Esgotamento de recursos, como CPU, memória, io_loop ou recursos de rede.
  • Falhas de dependência, incluindo infraestrutura, armazenamento de dados e serviços downstream.

Para gerenciar proativamente nossas cargas de tráfego com base na criticidade das solicitações, criamos o QoS Aware Load Management (QALM), um framework dinâmico de rejeição de cargas para solicitações recebidas com base na criticidade.

Quando o serviço se degrada devido à sobrecarga de tráfego, esgotamento de recursos ou falha de dependência, o QALM prioriza os recursos do servidor para solicitações mais críticas e elimina as menos críticas. Nosso objetivo com o QALM é reduzir a frequência e a gravidade de eventuais interrupções ou incidentes, levando a experiências de usuário mais confiáveis em nossos negócios.

Arquitetura QALM

Originalmente, escrevemos o QALM como uma biblioteca Go, integrando-o à camada de aplicação de um dos nossos serviços de maior volume. O framework apresenta detecção de sobrecarga inteligente, registro de criticidade e isolamento de endpoint para atender ao requisito de qualidade de serviço (QoS).

A detecção inteligente de sobrecarga permite que o QALM reserve recursos para solicitações críticas durante instâncias de degradação do serviço, enquanto o isolamento no nível do endpoint pode proteger endpoints específicos contra picos de tráfego.

Detecção Inteligente de sobrecarga

Um framework de limitação de taxa de entrada estática, que limita as solicitações em um limite definido, tem muitas restrições para nossa plataforma. Embora o limite estático precise ser atualizado sempre que nossa capacidade de serviço for alterada, o acordo de nível de serviço (SLA) e a diferença de capacidade entre os endpoints complicarão a configuração.

Um detector dinâmico de sobrecarga oferece mais flexibilidade e melhora a eficiência do hardware, especialmente em um serviço complexo como o nosso. Com o QALM, implementamos um detector de sobrecarga inspirado no algoritmo CoDel.

Um buffer de solicitação leve (implementado por goroutine e canais) é adicionado para cada endpoint ativado para monitorar a latência entre quando as solicitações são recebidas do caller e o processamento começa no handler. Cada fila monitora a latência mínima dentro de uma janela de tempo variável, acionando uma condição de sobrecarga se a latência ultrapassar um limite configurado.

No QALM, nosso detector de sobrecarga calcula a latência da solicitação na fila do buffer para detectar a sobrecarga.

Isolamento de endpoint

Para ativar o isolamento do endpoint, o QALM cria filas separadas com base em sua configuração. Cada fila tem seu próprio detector de sobrecarga, portanto, quando a degradação ocorre em um nó de endpoint, o QALM só irá reduzir sua carga desse endpoint, sem afetar os outros.

O QALM isola endpoints, de tal forma que se EP1 sofre degradação, o EP2 ainda funciona normalmente.

Solicitar criticidade

Um dos recursos mais importantes introduzidos pelo QALM é a solicitação de criticidade, o que garante a QoS durante a degradação. O QALM define quatro níveis de criticidade com base nos requisitos de negócios da Uber:

  1. Principais solicitações de infraestrutura: nunca descartadas.
  2. Principais solicitações de fluxo de viagem: nunca descartadas.
  3. Usuário que enfrenta solicitações de recursos: pode ser descartado quando o sistema estiver sobrecarregado.
  4. Tráfego interno, como solicitações de teste: maior possibilidade de descarte quando o sistema estiver sobrecarregado.

Como mostrado na Figura 2, quando o EP1 está sofrendo degradação, somente as solicitações não-críticas do Consumer1 são descartadas, enquanto as solicitações críticas do Consumer2 ainda são bem-sucedidas.

O QALM suporta arquivos de configuração locais e uma simples interface gráfica de usuário online (GUI) integrada por meio do sistema de gerenciamento de serviços da Uber. O serviço da GUI utiliza dados de jaeger tracing para preencher previamente os callers de endpoint e a criticidade padrão. Com a sincronização periódica da configuração, as atualizações da GUI entram em vigor em alguns minutos.

Proprietários de serviço podem usar a UI do QALM para atualizar a criticidade para pares endpoint-callers

Experimentos de carregamento de testes

Realizamos vários testes de carga usando um dos nossos serviços de produção crítica para quantificar como o QALM melhorou a degradação graciosa e o reconhecimento de criticidade. A integração melhorou significativamente a latência da solicitação de sucesso e descartou corretamente as solicitações não-críticas durante o período de sobrecarga.

Degradação graciosa

Nós fizemos teste de estresse de um endpoint com seis mil solicitações por segundo (RPS). Sem o QALM, a latência piorou ao longo do tempo, chegando a 20 segundos. Na prática, a maioria dos serviços expira após uma latência tão longa.

A latência da solicitação P99 sofre um aumento não-linear de aproximadamente 20 segundos sem a integração do QALM.

Executar o teste de carga com a detecção de sobrecarga dinâmica ativada nos dá resultados impressionantes. O QALM melhora significativamente a degradação graciosa, mantendo a latência de P99 abaixo de 400 milissegundos, descartando solicitações não-críticas (20% do total). Vimos uma melhoria de 98% na latência de solicitações de sucesso em comparação com os testes de carga sem a integração do QALM. 

A integração do QALM melhorou a latência da solicitação de sucesso do P99 em aproximadamente 400 milissegundos durante o período de sobrecarga.

Consciência da criticidade

Durante um período em que o sistema fica sobrecarregado com solicitações, o QALM elimina solicitações não-críticas, preservando as que nós designamos como críticas. Para este teste, configuramos dois callers com criticidades diferentes (documento: crítico e de armazenamento de documentos: não crítico), fazendo com que eles atingissem o mesmo endpoint a uma taxa de aproximadamente 2.300 RPS cada.

Quando o QALM detectou sobrecarga do sistema, ele descartou algumas das solicitações de migração de documentos, de modo que todas as solicitações de documentos designadas como críticas, foram bem-sucedidas.

O QALM identificou corretamente solicitações não-críticas do armazenamento de documentos, reduzindo aproximadamente 50% delas durante o período de sobrecarga.

Da camada de aplicação à camada RPC

Depois que construímos e testamos o QALM, quatro serviços centrais de produção dentro do nosso grupo o integraram e imediatamente obtiveram melhorias significativas de confiabilidade. Agora que sabíamos que a solução funcionava para nossos serviços-piloto, voltamos a concentrar nossas energias em determinar como outras equipes também poderiam usar o QALM.

A partir de várias adoções de serviço do QALM, descobrimos que a integração de alterações de código e configuração, abrandou o processo. Ao considerar como poderíamos disponibilizar o QALM para outros grupos dentro da Uber, nos concentramos em três valores:

  • O derramamento de carga deve ser um recurso interno de todos os serviços.
  • O QALM deve ser fácil de configurar.
  • Os proprietários do serviço não devem se preocupar em misturar o derramamento de carga com o código da lógica de negócios.

Felizmente, a Uber investe em muitos projetos de eficiência de desenvolvedores. Um desses projetos é o YARPC, uma plataforma open source de chamada de procedimento remoto (RPC) para serviços Go. O YARPC possui um middleware flexível e abrangente para lidar com solicitações de entrada e saída.

Nós reescrevemos o QALM como middleware de entrada, para que ele pudesse ser facilmente conectado a um serviço YARPC existente. Além disso, criamos um módulo QALM para o framework do serviço de injeção de dependência UberFx.

Com essa abordagem, os proprietários de serviços não precisam fazer alterações de código ao implementar o QALM e podem ativar a redução de carga por meio de uma configuração simples. Usando o YARPC e o UberFx, reduzimos o tempo de implementação do QALM de alguns dias, para menos de dois minutos.

Este gráfico mostra o middleware de entrada do QALM conectado à camada YARPC, portanto, os handlers de serviço não precisam fazer alterações em seu código.

Embora a transferência do QALM para a camada de aplicação facilitasse a implementação, precisávamos ter certeza de que ela ainda funcionaria de maneira eficiente. Como o QALM cria buffers separados para cada nó de endpoint, isso inevitavelmente causará alguma sobrecarga da CPU.

Para entender o impacto do QALM, usamos o perfil da CPU em uma execução de teste com cinco endpoints em um único host, a 100 RPS cada. Comparando essa configuração a uma sem QALM, tivemos apenas um pequeno aumento na sobrecarga da CPU, de aproximadamente 3%.

Esse gráfico mostra o baixo uso de CPU do QALM de aproximadamente 3% de sobrecarga.

Usando o QALM em produção na Uber

Para garantir que nosso novo plugin QALM YARPC esteja pronto para integração com a Uber Engineering, lançamos um programa beta fechado com outra equipe em um grupo diferente. Aproveitamos esse programa beta como uma oportunidade para melhorar nossa documentação técnica e suporte para a integração.

Escolhemos a equipe que oferece suporte para o Uber Visa para esse programa porque seu serviço tem um requisito de confiabilidade muito específico: isolamento no nível do endpoint. Um endpoint crítico do serviço, que permite que os usuários finais solicitem um cartão de crédito, precisa ser isolado de outros picos de tráfego de endpoint não-críticos.

Nossos testes de carga se concentraram no isolamento do nível do endpoint, usando estes parâmetros:

  • ~10 RPS para o endpoint, aplicado por 30 minutos
  • >1.200 RPS de pico para o endpoint não-crítico getProvidedCards
Sem o QALM, todas as solicitações de aplicação começaram a expirar após getProvidedCards atingir 1.200 RPS.
Com o QALM ativado, a aplicação ainda pode atender a solicitações, mesmo quando o getProvidedCard tiver atingido 1.800 RPS. Apenas duas solicitações expiraram durante 30 minutos de teste de carga.

Com o QALM fornecendo isolamento de nível de endpoint para o Uber Visa, observamos um aumento de 50% na tolerância à confiabilidade para picos de tráfego.

Pontos importantes

Começamos a desenvolver o QALM especificamente para a nossa equipe, e quando vimos como isso melhora a confiabilidade do serviço, sabíamos que ele poderia beneficiar as equipes da Uber Engineering. A partir das nossas experiências desenvolvendo e integrando o QALM, aprendemos algumas lições:

  • Os recursos de confiabilidade não devem ser misturados com a lógica de negócios. Os proprietários de serviços devem poder conectá-lo ou desativá-lo facilmente, conforme necessário. Construir o QALM na camada RPC tornou a adoção muito fácil.
  • Métricas falam mais alto que palavras. Quantificar a melhoria da confiabilidade torna o valor do QALM de fácil compreensão pelos proprietários do serviço. Com testes de carga de desempenho completos, podemos apresentar um caso convincente de aprimoramento de confiabilidade.
  • A documentação é importante, especialmente para autoatendimento. Fornecemos um wiki abrangente, painel de monitoramento, instruções de teste de carga e um modelo de alerta para ajudar os proprietários de serviços a entenderem o processo.
  • A colaboração é muito importante quando você está contribuindo para a camada RPC. Temos trabalhado com várias equipes neste projeto e, de forma proativa, fornecemos atualizações para as partes interessadas.

Seguindo em frente

Continuamos a melhorar o QALM para tornar mais fácil para as equipes implementarem e aumentarem ainda mais a confiabilidade. Especificamente, pretendemos:

  • Criar um fluxo automatizado para os proprietários de serviços reduzirem a configuração manual ao conduzir testes de carga e configurar alertas para simplificar o processo de integração.
  • Aumentar o limite de alerta para evitar trabalho não-crítico para nossos engenheiros de plantão. Integrar a detecção de anomalias com o QALM também fornecerá um limite de alerta mais preciso.
Nosso lema para o projeto QALM.

Se construir o próximo nível de plataforma do cliente para apoiar o crescimento sustentável da Uber interessa a você, junte-se a nós.

Assine a newsletter para acompanhar as mais recentes inovações da Uber Engineering.

Agradecimentos

O QALM foi construído pela Customer Platform Foundation Team – Scott Yao, Ping Jin, Feng Wang, Xin Peng. Gostaríamos também de agradecer a Kris Kowal da equipe de RPC por sua colaboração neste projeto. Por fim, o QALM não poderia ter sido construído sem o apoio de nossos gerentes de engenharia Deepti Chheda, Chintan Shah e Yan Zhang.

***

Este artigo é do Uber Engineering. Ele foi escrito por Scott Yao e Ping Jin. A tradução foi feita pela Redação iMasters com autorização. Você pode conferir o original em: https://eng.uber.com/qalm/