Garantindo confiabilidade e escalabilidade na Binance: o papel do gerenciamento de capacidade e do teste automático de carga

Principais tópicos do post:
A Binance aproveita o gerenciamento de capacidade para picos de tráfego não planejados causados por alta volatilidade, garantindo infraestrutura adequada e oportuna e recursos de computação para as demandas comerciais.
Testes de carga da Binance no ambiente de produção (em vez de um ambiente de preparação) para obter benchmarks de serviço precisos. Esse método ajuda a validar se nossa alocação de recursos é adequada para atender a uma carga definida.
Por que a Binance precisa de um processo especializado de gerenciamento de capacidade?
O gerenciamento de capacidade é a base da estabilidade do sistema. Isso envolve o dimensionamento correto de recursos de infraestrutura e aplicativos com as demandas comerciais atuais e futuras com o custo correto. Para ajudar a atingir esse objetivo, criamos ferramentas e pipelines de gerenciamento de capacidade para evitar sobrecarga e ajudar as empresas a fornecer uma experiência de usuário tranquila.
Os mercados de criptomoeda geralmente lidam com períodos de volatilidade mais regulares do que os mercados financeiros tradicionais. Isso significa que o sistema da Binance deve suportar esse aumento de tráfego de tempos em tempos, à medida que os usuários reagem aos movimentos do mercado. Com o gerenciamento de capacidade adequado, mantemos a capacidade adequada para a demanda comercial geral e esses cenários de aumento de tráfego. Esse fator importante é exatamente o que torna os processos de gerenciamento de capacidade da Binance únicos e desafiadores.
Vejamos os fatores que muitas vezes atrapalham o processo e levam a um serviço lento ou indisponível. Primeiro, temos sobrecarga, geralmente causada por um aumento repentino no tráfego. Por exemplo, isso pode resultar de um evento de marketing, uma notificação push ou até mesmo um ataque DDoS (negação de serviço distribuída).
O tráfego intenso e a capacidade insuficiente afetam a funcionalidade do sistema como:
O serviço assume cada vez mais trabalho.
O tempo de resposta aumenta até o ponto em que nenhuma solicitação pode ser respondida dentro do tempo limite do cliente. Essa degradação geralmente ocorre devido à saturação de recursos (CPU, memória, IO, rede, etc.) ou pausas prolongadas do GC no próprio serviço ou em suas dependências.
O resultado é que o serviço não conseguirá processar as solicitações de imediato.
Analisando o processo em detalhes
Agora que discutimos o princípio geral do gerenciamento de capacidade, vamos ver como a Binance aplica isso aos seus negócios. Aqui está uma breve abordagem da arquitetura do nosso sistema de gerenciamento de capacidade com alguns fluxos de trabalho importantes.
Ao buscar dados do banco de dados de gerenciamento de configuração (CMDB), geramos as configurações de infraestrutura e serviços. Os itens nessas configurações são os objetos de gerenciamento de capacidade.
O coletor de métricas busca métricas de capacidade do Prometheus para os dados da camada de negócios e serviço, monitoramento de infraestrutura para métricas da camada de recursos e o sistema de análise de rastreamento de chamada para informações de rastreamento. O coletor de métricas armazena os dados no banco de dados de capacidade (CDB).
O sistema de teste de carga realiza testes de estresse nos serviços e armazena os dados de referência no CDB.
O agregador obtém os dados de capacidade do CDB e os agrega para dimensões diárias e máximas (ATH). Após a agregação, ele grava os dados agregados de volta no CDB.
Ao processar os dados do CDB, a API do backend fornece interfaces para o painel de controle de capacidade, alertas e relatórios, bem como a API REST e os dados de capacidade relacionados para integração.
As partes interessadas obtêm insights sobre a capacidade através do painel de controle de capacidade, alertas e relatórios. Também podem usar outros sistemas relacionados, incluindo o monitoramento dos dados de capacidade dos serviços de obtenção com a API REST fornecida pelo sistema de gerenciamento de capacidade com Swagger.
Estratégia
Nossa estratégia de gerenciamento e planejamento de capacidade depende do processamento orientado por picos. O processamento orientado por picos é a carga de trabalho exercida pelos recursos de um serviço (servidores da web, bancos de dados, etc.) durante o pico de uso.
Aumento do tráfego quando o Fed elevou a taxa em março de 2023
Analisamos os picos periódicos e os usamos para orientar a trajetória da capacidade. Como acontece com qualquer recurso orientado por picos, queremos descobrir quando os picos ocorrem e, em seguida, explorar o que realmente está acontecendo durante esses ciclos.
Outra coisa importante que consideramos junto com a prevenção de sobrecarga é o escalonamento automático. O escalonamento automático lida com a sobrecarga aumentando dinamicamente a capacidade com mais instâncias do serviço. O excesso de tráfego é então distribuído e o tráfego que uma única instância do serviço (ou dependência) manipula permanece gerenciável.
O escalonamento automático é uma opção, mas não consegue lidar sozinho com situações de sobrecarga. Ele geralmente não consegue reagir rápido o suficiente a um aumento repentino no tráfego e só funciona bem quando há um aumento gradual.
Medição
A medição desempenha um papel crucial no trabalho de gerenciamento de capacidade da Binance e a coleta de dados é nossa primeira etapa de medição. Com base nos padrões da Biblioteca de Infraestrutura de Tecnologia da Informação (ITIL), coletamos dados para medição nos subprocessos de gerenciamento de capacidade, isto é:
Recurso. Consumo de recursos de infraestrutura de tecnologia da informação (TI) impulsionado pelo uso de aplicativos/serviços. Concentra-se em métricas internas de desempenho de recursos de computação físicos e virtuais, incluindo a CPU do servidor, memória, armazenamento em disco, largura de barramento de rede, etc.
Serviço. O desempenho no nível do aplicativo, SLA, latência e medidas de taxa de transferência que surgem das atividades comerciais. Concentra-se em métricas externas de desempenho com base em como os usuários percebem o serviço, incluindo latência do serviço, taxa de transferência, picos, etc.
Negócios. Coleta dados que medem as atividades comerciais processadas pelo aplicativo de destino, incluindo ordens, cadastro de usuários, pagamentos, etc.
O gerenciamento de capacidade baseado apenas na utilização de recursos de infraestrutura levará a um planejamento impreciso. Isso ocorre porque pode não representar os volumes reais de negócios e a taxa de transferência que impulsionam nossa capacidade de infraestrutura.
Eventos agendados fornecem um excelente lugar para discutir isso mais a fundo. Participe da campanha Watch Web Summit 2022 na Binance Live para compartilhar até 15.000 BUSD em recompensas Crypto Box. Além dos recursos subjacentes e das métricas da camada de serviço, também precisamos considerar os volumes de negócios. Baseamos o planejamento de capacidade aqui em métricas de negócios, como o número estimado de espectadores de transmissão ao vivo, máximo de solicitações em andamento para uma Crypto Box, latência de ponta a ponta e outros fatores.
Após a coleta de dados, nossos processos de gerenciamento de capacidade agregam e resumem os vários pontos de dados coletados em relação a um direcionador de capacidade específico. O valor agregado de uma métrica é um valor único que pode ser usado em alertas de capacidade, relatórios e outras funções relacionadas à capacidade.
Podemos aplicar vários métodos de agregação de dados a pontos de dados periódicos, como soma, média, mediana, mínimo, máximo, percentil e máxima histórica (ATH).
Nosso método escolhido determina nossos outputs do processo de gerenciamento de capacidade e as decisões resultantes. Selecionamos diferentes métodos com base em diferentes cenários. Por exemplo, usamos o método máximo para serviços críticos e pontos de dados relacionados. Para registrar o tráfego mais alto, usamos o método ATH.
Para diferentes casos de uso, usamos diferentes tipos de granularidade (tamanho em que os campos de dados são divididos) para agregação de dados. Na maioria dos casos, usamos minuto, hora, dia ou ATH.
Com granularidade de minutos, medimos a carga de trabalho de um serviço para alertas de sobrecarga oportunos.
Usamos dados agregados por hora para criar dados diários e agregamos os dados por hora para registrar o pico diário.
Normalmente, usamos dados diários para relatórios de capacidade e aproveitamos os dados ATH para modelagem e planejamento de capacidade.
Uma das principais métricas do gerenciamento de capacidade é o benchmarking de serviço. Isso nos ajuda a medir com precisão o desempenho e a capacidade do serviço. Obtemos o benchmark de serviço com teste de carga e abordaremos isso com mais detalhes posteriormente.
Gerenciamento de capacidade baseado em prioridade
Até agora, vimos como coletamos métricas de capacidade e agregamos dados em diferentes tipos de granularidade. Outra área crítica a ser discutida é a prioridade, que é útil no contexto de alertas e relatórios de capacidade. Depois de classificar os ativos de TI, o uso limitado da infraestrutura e os recursos de computação são priorizados e atribuídos primeiro a serviços e atividades críticas.
Pode haver várias maneiras de definir o serviço e a criticidade da solicitação. Uma referência útil é o Google. No livro SRE (Engenharia de Confiabilidade do Site), são definidos níveis de criticidade como CRITICAL_PLUS, CRITICAL, SHEDDABLE_PLUS etc. Da mesma forma, definimos vários níveis de prioridade, como P0, P1, P2 e assim por diante.
Definimos os níveis de prioridade da seguinte forma:
P0: para os serviços e solicitações mais críticos, aqueles que resultarão em um impacto sério e visível ao usuário se falharem.
P1: para os serviços e solicitações que resultarão em impacto visível ao usuário, mas o impacto é menor que os de P0. Espera-se que os serviços P0 e P1 sejam provisionados com capacidade suficiente.
P2: esta é a prioridade padrão para trabalhos em lote e off-line. Esses serviços e solicitações podem não resultar em um impacto visível ao usuário se estiverem parcialmente indisponíveis.
O que é teste de carga e por que o usamos em um ambiente de produção?
O teste de carga é um processo de teste de software não funcional em que o desempenho de um aplicativo é testado sob uma carga de trabalho específica. Isso ajuda a determinar como o aplicativo se comporta ao ser acessado por vários usuários simultaneamente.
Na Binance, criamos uma solução para nos permitir executar o teste de carga na produção. Normalmente, o teste de carga é executado em um ambiente de preparação, mas não poderíamos usar essa opção com base em nossas metas gerais de gerenciamento de capacidade. O teste de carga em um ambiente de produção nos permitiu:
Coletar um benchmark preciso dos nossos serviços em condições reais de carga.
Aumentar a convicção no sistema e em sua confiabilidade e desempenho.
Identificar obstáculos no sistema antes que eles aconteçam no ambiente de produção.
Habilitar o monitoramento contínuo dos ambientes de produção.
Habilitar o gerenciamento proativo de capacidade com ciclos de teste normalizados que acontecem regularmente.
Você pode ver nossa estrutura de teste de carga com algumas informações importantes abaixo:
A estrutura de microsserviço da Binance tem uma layer base para oferecer suporte ao roteamento de tráfego baseado em configuração e sinalizador, o que é essencial para nossa abordagem TIP.
A ACA (Automated Canary Analysis) é adotada para avaliar a instância que estamos testando. Ela compara as principais métricas coletadas no sistema de monitoramento, para que possamos pausar/encerrar o teste caso ocorra algum problema inesperado para minimizar os impactos para o usuário.
Benchmarks e métricas são coletados durante o teste de carga para gerar insights de dados sobre comportamentos e desempenhos de aplicativos.
As APIs são expostas para compartilhar dados valiosos de desempenho em vários cenários, por exemplo, gerenciamento de capacidade e garantia de qualidade. Isso ajuda a construir um ecossistema aberto.
Criamos fluxos de trabalho de automação para combinar todas as etapas e pontos de controle de uma perspectiva de teste de ponta a ponta. Também fornecemos a flexibilidade de integração com outros sistemas, como o pipeline de CI/CD e o portal de operações.
Nossa abordagem de teste em produção (TIP)
Uma abordagem de teste de desempenho tradicional (executar testes em um ambiente de preparação com tráfego simulado ou espelhado) oferece alguns benefícios. No entanto, a implantação de um ambiente de preparação semelhante à produção tem mais desvantagens em nosso contexto:
Quase dobra o custo da infraestrutura e os esforços de manutenção.
É incrivelmente complexo fazer o trabalho de ponta a ponta na produção, especialmente em um ambiente de microsserviço em larga escala em várias unidades de negócios.
Acrescenta mais privacidade de dados e riscos de segurança, pois, inevitavelmente, podemos precisar duplicar dados na preparação.
O tráfego simulado nunca replicará o que realmente acontece na produção. O benchmark obtido no ambiente de preparação seria impreciso e teria menos valor
O teste na produção, também conhecido como TIP, é uma metodologia de teste shift-right em que novos códigos, recursos e versões são testados no ambiente de produção. O teste de carga em produção que adotamos é altamente benéfico, pois nos ajuda a:
Analisar a estabilidade e robustez do sistema.
Descobrir benchmarks e obstáculos de aplicativos em níveis variados de tráfego, especificações de servidor e parâmetros de aplicativos.
Roteamento baseado em FlowFlag
Nosso roteamento baseado em FlowFlag incorporado na estrutura de base do microsserviço é a base para tornar o TIP possível. Isso funciona para casos específicos, incluindo aplicativos que usam a descoberta de serviço Eureka para distribuição de tráfego.
Conforme ilustrado no diagrama, o servidor do site da Binance como pontos de entrada detecta uma porcentagem do tráfego conforme especificado nas configurações com cabeçalhos FlowFlag, durante o teste de carga. Podemos selecionar um host de um serviço específico e identificá-lo como a instância perf de destino nas configurações. Essas solicitações perf detectadas serão roteadas para a instância perf quando chegarem ao serviço para processamento.
É totalmente orientado para configuração e hot loading (técnica de desenvolvimento/update de software), podemos ajustar facilmente a porcentagem de carga de trabalho usando automação sem ter que implantar uma nova versão
Pode ser amplamente aplicado à maioria dos nossos serviços, pois o mecanismo faz parte do gateway e do pacote base
Um único ponto de alteração também significa fácil reversão para reduzir os riscos na produção
Ao transformar nossa solução para ser mais cloud-native (aplicativos e sistemas de software que são projetados e construídos especificamente para serem executados em ambientes de nuvem), também estamos explorando como podemos criar uma abordagem semelhante para oferecer suporte a outro roteamento de tráfego oferecido por provedores de nuvem pública ou Kubernetes.
ACA para minimizar os riscos de impacto para o usuário
A implantação canary é uma estratégia para reduzir o risco de implantação de uma nova versão de software na produção. Normalmente, envolve a implantação de uma nova versão do software, chamada de versão canary, para um pequeno subconjunto de usuários junto com a versão estável em execução. Em seguida, dividimos o tráfego entre as duas versões para que uma parte das solicitações recebidas seja desviada para a versão canary.
A qualidade da versão canary é então avaliada pela chamada ACA. Isso compara as principais métricas que descrevem o comportamento das versões antiga e nova. Se houver degradação significativa das métricas, a versão canary será interrompida e todo o tráfego será roteado para a versão estável para minimizar o impacto do comportamento inesperado.
Usamos o mesmo conceito para construir nossa solução de teste de carga automática. A solução usa a plataforma Kayenta para a ACA por meio do Spinnaker para permitir implantações canary automatizadas. Nosso fluxo de teste de carga típico ao seguir este método parece assim:
Por meio do fluxo de trabalho, adicionamos gradualmente a carga de tráfego (por exemplo, 5%, 10%, 25%, 50%) ao host de destino conforme especificado ou até atingir seu ponto de interrupção.
A cada aumento de carga, a análise canary é executada repetidamente com a Kayenta por um determinado período de tempo (por exemplo, 5 minutos) para comparar as principais métricas do host testado com o período de pré-carregamento como linha de base e o atual período de pós-carregamento como experimento.
A comparação (modelo de configuração canary) se concentra em verificar se o host de destino:
Atinge restrições de recursos, por exemplo, o uso da CPU excede 90%.
Tem um aumento significativo nas métricas de falha, por exemplo, registros de erros, exceções de HTTP ou rejeições de limite de taxa.
Possui métricas de aplicativos principais ainda razoáveis, por exemplo, uma latência HTTP de menos de 2 segundos (personalizável para cada serviço)
Para cada análise, a Kayenta nos fornece um relatório para indicar o resultado e o teste termina imediatamente após a falha.
Essa detecção de falha geralmente leva menos de 30 segundos, reduzindo significativamente a chance de afetar a experiência de nossos usuários finais.
Ativando insights de dados
É crucial coletar informações suficientes sobre todos os processos e execuções de teste descritos anteriormente. O objetivo final é melhorar a confiabilidade e robustez do nosso sistema, o que é impossível sem insights de dados.
Um resumo geral do teste captura a porcentagem máxima de carga que o host foi capaz de suportar, o pico de uso da CPU e o QPS do host. Com base nisso, ele também estima a contagem de instâncias que podemos precisar implantar para atender nossa reserva de capacidade, considerando a máxima histórica do QPS dos serviços.
Outras informações valiosas para análise incluem a versão do software, especificação do servidor, contagem implantada e um link para o painel de controle do monitor onde podemos ver o que aconteceu durante o teste.
Uma curva de benchmark (curva de referência) indica como o desempenho mudou nos últimos três meses para que possamos descobrir possíveis problemas relacionados a uma versão específica do aplicativo.
As tendências de CPU e QPS mostram como o uso da CPU se correlacionou com o volume de solicitações que o servidor teve de lidar. Essa métrica pode ajudar a estimar o espaço livre do servidor para o crescimento do tráfego de entrada.
O comportamento da latência da API captura como o tempo de resposta varia em diferentes condições de carga para as cinco principais APIs. Podemos então otimizar o sistema, se necessário, em um nível de API individual.
As métricas de distribuição de carga da API nos ajudam a entender como a composição da API afeta o desempenho do serviço e fornece mais informações sobre áreas de melhoria.
Normalização e produtização
À medida que nosso sistema continua crescendo e evoluindo, continuaremos buscando e melhorando a estabilidade e a confiabilidade do serviço. Vamos continuar isso através de:
Um cronograma de teste de carga regular e estabelecido para serviços críticos.
Teste de carga automático como parte de nossos pipelines de CI/CD.
Maior produtização de toda a solução para se preparar para adoção em larga escala em toda a organização.
Limitações
Existem algumas limitações para a abordagem de teste de carga atual:
O roteamento baseado em FlowFlag só é aplicável à nossa estrutura de microsserviço. Estamos procurando expandir a solução para mais cenários de roteamento, aproveitando o recurso de roteamento ponderado comum de balanceadores de carga em nuvem ou uma Kubernetes Ingress.
Como baseamos o teste no tráfego real do usuário na produção, não podemos realizar testes de recursos em APIs ou casos de uso específicos. Além disso, para serviços com volume muito baixo, o valor seria limitado, pois talvez não conseguiríamos identificar seu obstáculo.
Realizamos esses testes em serviços individuais, em vez de cobrir calling chains (cadeias de chamada) de ponta a ponta.
Às vezes, o teste em produção pode afetar usuários reais se ocorrerem falhas. Portanto, devemos ter análise de falhas e reversão automática com recursos completos de automação.
Considerações finais
É fundamental pensarmos em cenários de pico de tráfego para evitar a sobrecarga do sistema e garantir seu tempo de atividade. É por isso que criamos os processos de gerenciamento de capacidade e teste de carga descritos ao longo deste artigo. Para resumir:
Nosso gerenciamento de capacidade é orientado por picos e incorporado em cada estágio do ciclo de vida do serviço, evitando sobrecarga com atividades como medição, configuração de prioridade, alertas e relatórios de capacidade, etc. Em última análise, é isso que torna os processos e necessidades da Binance únicos em comparação com uma situação típica de gerenciamento de capacidade.
O benchmark de serviço obtido do teste de carga é o foco do planejamento e gerenciamento de capacidade. Ele determina com precisão o recurso de infraestrutura necessário para dar suporte às demandas de negócios atuais e futuras. Por fim, isso teve que ser realizado em produção com uma solução exclusiva desenvolvida pela Binance que nos permitiu atender às nossas necessidades específicas.
Com tudo isso reunido, esperamos que você possa ver que um bom planejamento e estruturas completas ajudam a criar o serviço que os Binancers conhecem e apreciam.
Leitura complementar
(Blog) Apresentando o Oráculo VRF da Binance: a próxima geração de aleatoriedade verificável
(Blog) Binance se junta à FIDO Alliance em preparação para implementação de Chave de Segurança
Referências
[1] Dominic Ogbonna, A-Z of Capacity Management: Practical Guide for Implementing Enterprise IT Monitoring & Capacity Planning, Capítulo 4, Capítulo 6: https://www.amazon.com/Capacity-Management-Implementing-Enterprise-Monitoring-ebook/dp/B07871VCFR
[2] Luis Quesada Torres, Doug Colish, SRE Best Practices for Capacity Management: https://static.googleusercontent.com/media/sre.google/en//static/pdf/login_winter20_10_torres.pdf
[3] Alejandro Forero Cuervo, Sarah Chavis, livro Google SRE, Capítulo 21 - Handling Overload: https://sre.google/sre-book/handling-overload