Em um de meus empregadores, trabalhamos em uma API REST (mas também se aplica ao SOAP). O cliente, que é a interface do usuário do aplicativo, faria chamadas pela Web (LAN em implantações típicas de produção) para a API. A API faria chamadas para o banco de dados.
Um tema recorrente nas nossas discussões é o desempenho: algumas pessoas da equipe acreditam que você não deve ter várias chamadas ao banco de dados (geralmente lê) de uma única chamada da API por causa do desempenho; você deve otimizá-los para que cada chamada à API tenha apenas (exatamente) uma chamada ao banco de dados.
Mas isso é realmente importante? Considere que a interface do usuário precisa fazer uma chamada de rede para a API; isso é muito grande (ordem de magnitude de milissegundos). Os bancos de dados são otimizados para manter as coisas na memória e executar leituras muito, muito rapidamente (por exemplo, o SQL Server carrega e mantém tudo na RAM e consome quase toda a RAM livre, se puder).
TLDR: É realmente significativo se preocupar com várias chamadas ao banco de dados quando já estamos fazendo uma chamada de rede pela LAN? Se sim, por quê?
Para ser claro, estou falando de ordem de magnitude - eu sei que depende de detalhes (hardware da máquina, escolha de API e DB, etc.) Se eu tiver uma chamada que leva O (milissegundos), otimiza para DB chamadas que levam uma ordem de magnitude menor, realmente importam? Ou há mais para o problema do que isso?
Edit: para a posteridade, acho ridículo afirmar que precisamos melhorar o desempenho combinando chamadas de banco de dados nessas circunstâncias - especialmente com a falta de criação de perfil. No entanto, não é minha decisão se fazemos isso ou não; Quero saber qual é a lógica por trás de pensar que essa é uma maneira correta de otimizar as chamadas de API da web.
fonte
Respostas:
A lógica
Em teoria, você está correto. No entanto, existem algumas falhas nessa lógica:
Pelo que você declarou, não está claro se você realmente testou / definiu o perfil do seu aplicativo. Em outras palavras, você realmente sabe que as transferências de rede do aplicativo para a API são o componente mais lento? Por ser intuitivo, é fácil supor que sim. No entanto, ao discutir desempenho, você nunca deve assumir. No meu empregador, sou o líder de desempenho. Quando eu entrei, as pessoas continuaram falando sobre CDNs, replicação etc. com base na intuição sobre quais devem ser os gargalos. Acontece que nossos maiores problemas de desempenho foram o desempenho ruim das consultas ao banco de dados.
Você está dizendo que, como os bancos de dados são bons na recuperação de dados, o banco de dados está necessariamente em execução com desempenho máximo, está sendo usado de maneira ideal e não há nada que possa ser feito para melhorá-los. Em outras palavras, os bancos de dados são projetados para serem rápidos, portanto nunca precisarei me preocupar com isso. Outra linha de pensamento perigosa. É como dizer que um carro deve se mover rapidamente, então não preciso trocar o óleo.
Essa maneira de pensar assume um único processo de cada vez, ou, em outras palavras, nenhuma simultaneidade. Ele pressupõe que uma solicitação não possa influenciar o desempenho de outra solicitação. Os recursos são compartilhados, como E / S de disco, largura de banda de rede, conjuntos de conexões, memória, ciclos de CPU, etc. Portanto, reduzir o uso de um recurso compartilhado por uma chamada de banco de dados pode impedir que outras solicitações diminuam a velocidade. Quando entrei para meu empregador atual, a gerência acreditava que ajustar uma consulta ao banco de dados de 3 segundos era uma perda de tempo. 3 segundos é tão pouco, por que perder tempo com isso? Não estaríamos melhor com uma CDN ou compactação ou outra coisa? Mas se eu puder executar uma consulta de 3 segundos em 1 segundo, digamos, adicionando um índice, que é 2/3 a menos de bloqueio, 2/3 a menos de tempo gasto ocupando um encadeamento e, mais importante, menos dados lidos no disco,
A teoria
Existe uma concepção comum de que o desempenho do software é simplesmente velocidade .
De uma perspectiva puramente de velocidade, você está certo. Um sistema é tão rápido quanto seu componente mais lento. Se você definiu o perfil do seu código e descobriu que a Internet é o componente mais lento, obviamente todo o resto não é a parte mais lenta.
No entanto, considerando o exposto, espero que você possa ver como a contenção de recursos, a falta de indexação, o código mal escrito etc. podem criar diferenças surpreendentes no desempenho.
As suposições
Uma última coisa. Você mencionou que uma chamada de banco de dados deve ser barata em comparação com uma chamada de rede do aplicativo para a API. Mas você também mencionou que o aplicativo e os servidores de API estão na mesma LAN. Portanto, os dois não são comparáveis às chamadas de rede? Em outras palavras, por que você está assumindo que a transferência da API é uma ordem de magnitude mais lenta que a transferência do banco de dados quando ambos têm a mesma largura de banda disponível? É claro que os protocolos e as estruturas de dados são diferentes, entendo isso, mas discuto a suposição de que são ordens de magnitude diferentes.
Onde fica murkey
Essa questão toda é sobre chamadas de banco de dados "múltiplas" versus "únicas". Mas não está claro quantas são múltiplas. Por causa do que eu disse acima, como regra geral, recomendo fazer quantas chamadas de banco de dados forem necessárias. Mas isso é apenas uma regra de ouro.
Aqui está o porquê:
TL; DR
Sim, mas apenas até certo ponto. Você deve tentar minimizar o número de chamadas ao banco de dados quando for prático, mas não combine chamadas que não tenham nada a ver apenas com o objetivo de combiná-las. Além disso, evite chamar o banco de dados em um loop a todo custo.
fonte
Parece que sua equipe está otimizando antes de ter um motivo. Você mediu o tempo para executar essas solicitações? As chances de forçar esse paradigma criarão um desempenho pior para o usuário final, pois as viagens de ida e volta ao servidor da Web terão uma latência muito maior do que o tempo de conexão do servidor da Web ao banco de dados. Além disso, a maioria dos navegadores da Web fará apenas duas conexões simultâneas com um único servidor da Web; portanto, para páginas complexas, você provavelmente terá um gargalo.
De qualquer maneira, as decisões de otimização não devem ser tomadas sem dados para fazer backup. Meça e descubra o que é melhor para a sua aplicação.
fonte
Nós não podemos contar.
Não temos a aparência de suas consultas. Não sabemos quanto tempo eles levam para serem concluídos. Não sabemos quanta sobrecarga está envolvida em cada solicitação ao seu servidor de API. Não sabemos como seus clientes estão geograficamente dispersos. Etc.
Se esse é um cenário que requer otimização e você pode decidir se deseja dividir ou unir as chamadas, é necessário compará-lo de duas maneiras : decida o que você está otimizando (latência da interface do usuário, carga da CPU do servidor, contenção, etc.) e escolha aquele que melhor atingir sua meta de otimização.
Afora isso, a única uma coisa que posso acrescentar com relativa certeza é esta:
Dentro de uma única solicitação, você deve executar todas as consultas necessárias para criar uma resposta.
Em outras palavras, se a resposta não puder ser gerada até que todas as N consultas sejam executadas, geralmente não faz sentido separá-las. Se você pode gerar resultados significativos, intermediários ou completos, após cada consulta, inicie o benchmarking.
fonte
Dois pensamentos:
Primeiro, para o consumidor que usa a API, ele está fazendo uma ligação para realizar uma tarefa. O que acontece depois que o servidor recebe a chamada para atender à solicitação não deve ser tão rígido. Se essa chamada de um consumidor exigir 10 itens de sub-trabalho para reunir os dados e devolvê-los, isso deve ser aceitável.
Segundo: você vê um problema real de desempenho do banco de dados com o processo em questão? Minha experiência mostrou que, muitas vezes, tentar colocar todos os aspectos de uma solicitação de banco de dados em uma única chamada pode resultar em uma chamada menos eficiente do que simplesmente fazer três ou quatro chamadas de dados. Os bancos de dados modernos são muito eficientes nos planos de cache e execução. Frequentemente, quando você tenta fazer demais, verá procedimentos com cursores (muito ruins para o desempenho porque os dados são atuados linha por linha, não como um conjunto de uma vez) e código que resulta em um plano menos eficiente do que se você tivesse quebrado a chamada em várias pequenas etapas fáceis.
Fora da organização simples do código, concordo que cada chamada de API possivelmente chame um único procedimento armazenado (ou função db), que por sua vez é responsável por preencher a solicitação. Pode haver mais de uma etapa no procedimento.
fonte
SELECT
s.Se o banco de dados estiver em um servidor diferente do seu serviço REST, cada chamada ao banco de dados resultará em uma ida e volta da rede e isso poderá prejudicar significativamente o desempenho:
Certa vez, observei que uma única chamada de serviço da web era traduzida para cerca de 500 consultas de banco de dados - isso dificilmente era um problema quando o serviço da web e o banco de dados estavam localizados na mesma máquina, mas se transformavam em um tempo de resposta de 6 a 7 segundos quando eles estavam em diferentes máquinas
Obviamente, 500 viagens de ida e volta ao banco de dados são bastante extremas. Não sei ao certo quais são seus requisitos de desempenho, mas como regra geral, eu diria que, se você ficar com menos de 10 consultas ao banco de dados por chamada REST, não deverá sofrer um impacto significativo no desempenho.
fonte
Temos alguns aplicativos muito, muito faladores. Há uma chamada de banco de dados para todos. Solteiro. Pequeno. Coisa. Servir dados de referência repetidamente é uma parte importante da carga de trabalho no sistema. Todo esse agendamento de threads de trabalho, aquisição e remoção de bloqueios, planejamento de verificação de cache etc. se soma, mesmo que não haja E / S de disco real. A contenção é maior porque as transações precisam reter bloqueios em várias chamadas de banco de dados e, portanto, a taxa de transferência é muito menor do que poderia ser. Agora, essas equipes estão tentando comprar servidores de banco de dados novos e muito caros por causa disso.
Portanto, embora a maior parte do tempo decorrido na configuração atual do sistema seja gasto com chamadas da API REST, ignorar o desempenho no nível do banco de dados está armazenando problemas para o futuro.
fonte
O caminho de otimização apresentado é simplesmente a maneira errada de ver as coisas.
As chamadas de API devem ser atômicas. Em outras palavras, eu devo poder fazer uma chamada de API da web para executar a ação que eu quero. Seja para buscar dados, atualize um registro ou o que for. NUNCA deve levar mais de uma chamada para causar a ação. E a tentativa de alavancar transações em várias chamadas deve ser evitada como uma praga.
Às vezes, uma única ação é bastante complexa. Por exemplo, buscando dados combinados de várias fontes: novamente, isso deve ser uma única chamada. Ou a coisa toda funciona ou a coisa toda falha.
Agora, dizer que uma única chamada de API deve executar apenas uma consulta ao banco de dados é um pouco idiota. Como você apontou, a sobrecarga para organizar a chamada pela rede geralmente é uma ordem de magnitude mais cara em termos de tempo geral.
Eu posso entender um pouco a afirmação de que uma única consulta é executada pode ser mais rápida que várias; mas isso dá uma impressão falsa, pois ignora o total de dados e carga de rede. Somente analisando as várias maneiras de extrair dados do banco de dados você pode descobrir qual é realmente o problema. Tenho certeza de que todo mundo tem uma história em que uma consulta específica executada 100 vezes mais frequentemente do que o esperado matou o sistema até que um índice adequado fosse implementado ...
Em última análise, você não será capaz de convencê-los com apenas uma conversa. Configure um caso de teste para as duas abordagens e faça o perfil delas. Preste atenção ao tempo total para adquirir os dados necessários, quantidade de tráfego de rede gerado, número e tempo das chamadas ao banco de dados etc. dados para comer corvo ou mostrar o caminho dourado.
fonte