A seguir, um trecho do capítulo 1 do Desempenho da base de dados em escala (um livro de acesso aberto que está disponível gratuitamente).Siga as aventuras altamente fictícias de Joan com alguns desafios de desempenho de banco de dados muito reais.Você vai rir.Você vai chorar.Você vai se perguntar como trabalhamos esta “história cheesy” em um livro profundamente técnico. Desempenho da base de dados em escala Atraída por palavras-chave impressionantes como “cloud híbrido”, “serverless” e “edge first”, Joan se juntou prontamente a uma nova empresa e começou a acompanhar sua pilha de tecnologia. Seu primeiro projeto recentemente iniciou uma transição de sua implementação interna de um sistema de banco de dados, que se revelou não crescer ao mesmo ritmo que o número de clientes, para uma das soluções de gerenciamento de banco de dados padrão da indústria. conhecidas no mundo SQL. Ácido Devido a algumas novas leis de proteção de dados que tendem a aparecer anualmente hoje em dia, o conselho da empresa decidiu que eles iriam manter seu próprio data center, em vez de usar um dos provedores de nuvem populares para armazenar informações sensíveis. Em um nível muito alto, o produto principal da empresa consistia em apenas duas camadas: O frontend, o ponto de entrada para os usuários, que realmente funciona em seus próprios navegadores e se comunica com o resto do sistema para trocar e persistir informações. O tudo-else, comumente conhecido como “backend”, mas na verdade inclui balanceadores de carga, autenticação, autorização, várias camadas de cache, bancos de dados, backups e assim por diante. A primeira tarefa introdutória de Joan foi implementar um serviço muito simples para coletar e resumir várias estatísticas do banco de dados, e integrar esse serviço com todo o ecossistema, de modo que ele recupere dados do banco de dados em tempo real e permita que as equipes do DevOps inspeccionem as estatísticas ao vivo. Para impressionar a administração e tranquilizá-los de que contratar Joan foi a melhor decisão deles neste trimestre, Joan decidiu entregar uma implementação de prova de conceito no seu primeiro dia!A política indiscutível da empresa era escrever software em Rust, então ela pegou o primeiro driver para o seu banco de dados de uma breve pesquisa crates.io e sentou-se em seu hackathon auto-organizado. O dia correu muito bem, com o ecossistema focado na ergonomia da Rust proporcionando uma experiência de desenvolvedor superior. Mas então Joan realizou seus primeiros testes de fumaça em um sistema real. A desconfiança se transformou em decepção e impotência quando ela percebeu que cada terceiro pedido (em média) terminou em um erro, mesmo que todo o cluster de banco de dados relatou estar em um estado saudável e operável. Infelizmente, a motorista Joan apressadamente escolheu para a fundação de seu trabalho, embora o código de código aberto por si só, era apenas um embrulho fino sobre o código C pré-compilado, legado, sem nenhuma fonte a ser encontrada. e fez uma adivinhação educada de que o Na base de dados usada pela empresa, as chaves são hashadas para solicitações de roteamento posteriores para nós apropriados.Se um valor de hash for calculado incorretamente, um pedido pode ser redirecionado para o nó errado que pode recusá-lo e devolver um erro em vez disso. O Wireshark O bug deve estar na implementação da chave de hash Incapaz de verificar a alegação devido à falta de código-fonte, Joan decidiu por um caminho mais simples - abandonar o driver escolhido originalmente e reimplementar a solução em um dos drivers oficialmente suportados, de código aberto apoiados pelo fornecedor de banco de dados, com uma base de usuários sólida e calendário de lançamento regularmente atualizado. Diário de Joan das lições aprendidas, parte I As lições iniciais incluem: Escolha um driver cuidadosamente.Ele está no centro do desempenho, robustez e confiabilidade do seu código. Os motoristas também têm bugs, e é impossível evitá-los. A menos que haja uma boa razão, prefira o motorista oficialmente suportado (se houver); Os drivers de código aberto têm vantagens: eles não são apenas verificados pela comunidade, mas também permitem a inspeção profunda do seu código, e até mesmo a modificação do código do driver para obter ainda mais insights para depuração; É melhor confiar em drivers com um cronograma de lançamento bem estabelecido, pois eles são mais propensos a receber correções de bugs (inclusive para vulnerabilidades de segurança) em um período de tempo razoável. Wireshark é uma ótima ferramenta de código aberto para interpretar pacotes de rede; dê uma tentativa se você quiser olhar debaixo do capô do seu programa. A tarefa introdutória foi finalmente concluída com sucesso, o que preparou Joan para receber sua primeira tarefa real. O Tuning Armada com a experiência adquirida trabalhando na tarefa introdutória, Joan começou a planejar como abordar sua nova tarefa: um aplicativo de mau comportamento.Um dos aplicativos causou notoriamente problemas de estabilidade para todo o sistema, interrompendo outras cargas de trabalho cada vez que experimentou quaisquer problemas. Este serviço particular foi responsável por injetar dados backup do sistema legado na nova base de dados. Como a empresa não estava em grande pressa, o aplicativo foi escrito com baixa concorrência em mente para ter baixa prioridade e não interferir com as cargas de trabalho do usuário. Infelizmente, uma vez a cada poucos dias algo continuou a desencadear uma anomalia. O aplicativo normalmente pacífico parecia estar tentando executar um ataque de negação de serviço em seu próprio banco de dados, inundando-o com solicitações até que o backend se sobrecarregou o suficiente para causar problemas para outras partes do ecossistema. Enquanto Joan observava as métricas apresentadas em um painel Grafana, sugerindo claramente que a taxa de solicitações geradas por esta aplicação começou a aumentar em torno do momento da anomalia, ela se perguntou como na Terra essa carga de trabalho poderia se comportar assim. Como a colaboração foi fortemente anunciada como uma das “fundamentações espirituais e culturais” da empresa durante as sessões de onboarding com um treinador no local, ela decidiu que é melhor discutir o assunto com seu colega, Tony. "Olha, Tony, eu não posso enrolar minha cabeça sobre isso", explicou ela. "Este serviço não envia quaisquer novos pedidos quando 100 deles já estão em vôo.E olhe bem aqui nos registros: 100 pedidos em andamento, um devolveu um erro de timeout, e ...", ela então parou, surpreso em sua própria epifania. “Ok, obrigado Tony, você é um querido – melhor sempre!”, ela concluiu e voltou para corrigir o código. Pato de borracha A observação que levou à descoberta da causa raiz foi bastante simples: a solicitação não realmente *retornou* um erro de timeout porque o servidor de banco de dados nunca enviou de volta tal resposta. A solicitação foi simplesmente qualificada como timed out pelo motorista, e descartada. Mas o único fato de que o motorista não está mais esperando por uma resposta para uma solicitação específica não significa que o banco de dados está processando-o! Com esse conhecimento, é fácil imaginar que, uma vez que 100 solicitações estejam fora do tempo do lado do cliente, o aplicativo pode pensar erroneamente que não estão mais em andamento e, felizmente, enviar mais 100 solicitações para o banco de dados, aumentando o número total de solicitações em voo (ou seja, concorrência) para 200. Diário de Joan das lições aprendidas, parte II As lições continuam: Os timeouts do lado do cliente são convenientes para os programadores, mas eles podem interagir mal com os timeouts do lado do servidor. Regra do polegar: faça os timeouts do lado do cliente por cerca de duas vezes mais tempo do que os do lado do servidor, a menos que você tenha uma razão extremamente boa para fazer o contrário. Alguns drivers podem ser capazes de emitir um aviso se detectarem que o timeout do lado do cliente é menor do que o do lado do servidor, ou mesmo modificar o timeout do lado do servidor para corresponder, mas geralmente é melhor verificar duas vezes. Tarefas com concorrência aparentemente fixa podem realmente causar picos em certas condições inesperadas. Inspecionar logs e painéis é útil na investigação de tais casos, por isso certifique-se de que as ferramentas de observação estão disponíveis tanto no cluster de banco de dados quanto para todas as aplicações do cliente. pontos bônus para rastreamento distribuído, como a integração OpenTelemetry. Com os timeouts do lado do cliente devidamente modificados, o aplicativo sufocou com muito menos frequência e em menor grau, mas ainda não era um cidadão perfeito no sistema distribuído. Ele ocasionalmente pegou um nó de banco de dados de vítimas e continuou a incomodá-lo com muitos pedidos, ignorando o fato de que outros sete nós estavam consideravelmente menos carregados e poderiam ajudar a lidar com a carga de trabalho também. Em outras ocasiões, sua concorrência foi relatada para ser exatamente 200% maior do que o esperado pela configuração. Sempre que as duas anomalias convergiram no tempo, o nó pobre não foi capaz de lidar com todos os pedidos que foi bombardeado com, e teve que desistir de uma parte justa deles. Um longo estudo da documentação do motorista, que, felizmente, estava disponível formatado e mantido razoavelmente atualizado, ajudou Joan aliviar essas dores também. O MDBOOK O primeiro problema foi simplesmente uma configuração errada da política de balanço de carga não padrão, que tentou muito para escolher o nó de banco de dados "menos carregado" de todos os disponíveis, com base em heurísticas e estatísticas atualizadas ocasionalmente pela própria base de dados. Infelizmente, esta política também foi “o melhor esforço”, e baseou-se no fato de que as estatísticas que chegam do banco de dados eram sempre legítimas – mas um nó de banco de dados estressado poderia se tornar tão sobrecarregado que não estava enviando estatísticas atualizadas de volta no tempo! Isso levou o driver a acreditar falsamente que esse servidor particular não estava realmente ocupado. O segundo problema (duplicação temporária da concorrência) foi causado por outro erro de configuração: uma política de retração especulativa excessiva. Depois de esperar por um período de tempo pré-configurado sem obter um reconhecimento do banco de dados, os motoristas reenviariam especulativamente um pedido para maximizar suas chances de sucesso. Este mecanismo é muito útil para aumentar a taxa de sucesso das solicitações. No entanto, se o pedido original também tiver sucesso, isso significa que o pedido especulativo foi enviado em vão. Para equilibrar os prós e contras, o retração especulativa deve ser configurado para reenviar solicitações apenas se for muito provável que o pedido original falhe. Caso contrário, como no caso de Joan, o retração especulativa pode agir muito rapidamente, duplicando o número Whew, nada dá uma corrida de endorfinas e dopamina simultânea como uma sessão de depuração de qualidade que termina em um sucesso surpreendente (exceto escrever uma história cheesy em um livro profundamente técnico, é claro). O fim . Se você chegou até aqui e não consegue obter o suficiente de histórias de desempenho de banco de dados, veja o que aconteceu com o pobre velho Patrick em “ E se você aprecia esse senso de humor, veja o de Piotr. . Editor’s note: Uma história de desempenho de banco de dados: Patrick's Unlucky Green Fedoras Novo livro sobre a escrita de blogs de engenharia