
Airbnb captura e reproduz tráfego real do MySQL para testes de carga
Contexto e motivação
A Airbnb opera um conjunto de centenas de clusters de bancos de dados compatíveis com MySQL, atendendo milhares de casos de uso com milhões de consultas por segundo (QPS). Para lidar com dimensionamento de clusters, upgrades, migrações e depuração de incidentes, a empresa construiu um sistema interno de captura e reprodução de tráfego real de banco de dados.
O sistema anterior era fragmentado: cada binding de linguagem usava seu próprio framework de logging para enviar rastros de consultas ao Kafka, com replayers customizados por caso de uso. Essa abordagem, herdada do pipeline de observabilidade, tinha custo de manutenção alto, propriedade ambígua, escalava mal na arquitetura orientada a serviços e carecia de informação suficiente para reproduzir transações completas - o que impedia verificar se as mesmas consultas retornam os mesmos resultados em um novo banco.
Objetivos do novo sistema
O novo sistema persegue três objetivos: teste de carga com tráfego real de produção (benchmarks sintéticos como sysbench não cobrem o espectro completo de consultas; a reprodução permite dimensionar clusters com folga insuficiente ou superprovisionados); compatibilidade de consultas em upgrades e migrações (reproduzindo o mesmo tráfego contra dois alvos e comparando resultados, como entre MySQL 5.7 e 8.0 ou entre MySQL e engines compatíveis); e depuração de performance, já que os digests do performance_schema não contêm informação suficiente para reproduzir problemas.
Arquitetura
O ponto de captura é o ProxySQL, proxy open-source que entende o protocolo MySQL e já fica entre as aplicações e os bancos, exigindo nenhuma mudança nas aplicações. Três componentes construídos internamente:
- Log Mover: um sidecar do ProxySQL monitora os arquivos de log de consultas (ativados por regras de query, com pouco impacto de performance) e os transfere para armazenamento de objetos na nuvem.
- Log Processor: job offline que decodifica os logs binários, separa consultas por cluster, remonta a ordem original das transações, agrupa consultas em janelas de cinco minutos por timestamp (permitindo controle fino do ritmo de reprodução) e armazena metadados como timestamp, usuário e cluster. Ele também reescreve instruções INSERT para fixar explicitamente o valor capturado de last_insert_id, garantindo que leituras dependentes desse valor se comportem de forma consistente entre bancos. O tradeoff aceito é deixar de exercitar a geração nativa de auto-incremento do alvo.
- Log Replayer: composto por um API Server (plano de controle com interface web), um agendador de tarefas e trabalhadores que escalam até milhares de instâncias. Oferece dois modos: "Replay only" (teste de carga, em velocidades de 1x, 2x, 3x ou QPS alvo, rastreando erros, latências por digest e utilização) e "Replay and compare" (teste de compatibilidade, executando as mesmas consultas contra dois bancos e registrando divergências).
O agendador atribui a cada lote um "horário esperado de início" compartilhado, para que os trabalhadores reproduzam juntos a concorrência e o ritmo originais; se tarefas começam a falhar, ele interrompe novos agendamentos para evitar problemas em cascata.
Como as consultas capturadas podem conter dados pessoais, o pipeline as trata como dados de produção: criptografia em trânsito e em repouso, acesso pelo princípio do menor privilégio, logging habilitado apenas pela janela necessária e reprodução somente em ambientes equivalentes a produção.
Resultados
Na migração de MySQL 5.7 para 8.0, a reprodução identificou problemas cedo. Em performance, como o 8.0 remove o query cache, a equipe usou bisseção - reproduzir contra 5.7 com e sem cache, depois comparar 5.7-sem-cache contra 8.0 - e encontrou padrões de consultas duplicadas que o cache absorvia silenciosamente. No caso mais severo, a latência de um padrão de consulta saltou de 0,03 para 2,6 segundos, lendo 273 MB por join em vez de 5 MB, rastreada a uma mudança no MySQL 8.0.20+ na leitura de linhas durante ordenação. Em correção, o modo "Replay and compare" revelou consultas sem ORDER BY determinístico (ou sem desempate único) que retornam linhas diferentes com LIMIT no novo engine, permitindo que as equipes adicionassem ordenação explícita.
No planejamento de capacidade, a equipe reproduz tráfego em velocidades maiores antes da alta temporada de viagens: em um cluster grande, reproduzir 80% mais tráfego de escrita elevou a latência média de commit em quase 500%, de cerca de 6 ms para 34 ms, revelando o teto do cluster antes do tráfego real. Times agora podem solicitar reproduções por uma ferramenta self-serve, também útil para identificar folga e otimizar bin-packing e custos.
Conclusão
A tese central: benchmarks sintéticos mostram como o banco lida com a carga imaginada; reproduzir tráfego real mostra como ele lida com a carga que você realmente tem. Essa diferença levou o fleet MySQL da Airbnb de 5.7 para 8.0 sem incidente maior em produção, priorizando os clusters de maior risco e capturando regressões de latência e consultas não determinísticas fora de produção.