Os aplicativos nativos da nuvem estão sendo desenvolvidos em um ritmo acelerado. Embora ainda não dominem os portfólios de aplicativos, eles estão aumentando em número. O interesse em contêineres está intimamente associado às arquiteturas nativas da nuvem (baseadas em microsserviços) devido à dependência inerente de infraestrutura para comunicações e escala.
Normalmente, o dimensionamento de microsserviços é obtido por meio de clonagem horizontal. Ou seja, se precisarmos de mais instâncias de um determinado serviço, simplesmente o clonamos e o adicionamos ao pool disponível, do qual um balanceador de carga escolhe responder às solicitações. Fácil, fácil. Quando esses microsserviços representam de perto elementos funcionais, esse modelo funciona ainda melhor.
O balanceador de carga em questão geralmente é um componente do orquestrador de contêineres e usa como padrão o algoritmo TCP round robin padrão do setor. Isso significa que uma solicitação chega e o balanceador de carga escolhe o recurso "próximo da fila" para responder.
Este método é frequentemente comparado à fila de um banco ou do DMV. Mas isso não é totalmente preciso. Em um cenário de rodízio real, você não é direcionado para o "próximo recurso disponível". Você é direcionado para o recurso "próximo da fila", mesmo que esse recurso esteja ocupado. Ironicamente, os métodos de distribuição do DMV e do seu banco local são mais eficientes do que um verdadeiro algoritmo round robin.
Eu sei direito?
Isso também é verdade para aplicativos. O mesmo serviço — mesmo no nível funcional — pode ser clonado porque atende ao mesmo conjunto de solicitações. Mas essas solicitações nem sempre são iguais em termos de execução por causa dos dados. Isso mesmo, dados. A mesma solicitação funcional — ou chamada de API — pode levar mais ou menos tempo para ser executada, dependendo dos dados enviados ou solicitados. Afinal, levará menos tempo para recuperar e serializar um único registro de cliente do que para recuperar e serializar dez ou cem registros de clientes.
E é aí que o sistema round robin falha um pouco e introduz variabilidade que pode impactar o desempenho. O axioma operacional nº 2 ainda se aplica às arquiteturas nativas da nuvem e baseadas em microsserviços: à medida que a carga aumenta, o desempenho diminui .
Round robin é como texugo-do-mel. Não importa se um recurso está sendo sobrecarregado por solicitações com conjuntos de dados significativos como respostas. O sistema round robin diz "você é o próximo", esteja você pronto ou não. Isso pode resultar em desempenho irregular para os usuários cujas solicitações acabam em uma fila em um recurso cada vez mais sobrecarregado.
Se você está preocupado com o desempenho — e deveria estar — então uma alternativa melhor é qualquer um dos outros algoritmos padrão, como menos conexões ou tempo de resposta mais rápido. Basicamente, você quer que seu algoritmo leve em consideração a carga e/ou a velocidade em vez de simplesmente impor cegamente solicitações a recursos que podem não ser uma escolha ideal.
Alguns podem pensar que, à medida que escalamos a pilha do TCP para o HTTP e para o HTTP+, esse problema se resolverá. Não é bem assim. O método de distribuição — o algoritmo de balanceamento de carga — ainda é relevante, independentemente da camada em que você o baseia. O round robin não se importa com a arquitetura, ele se importa com os recursos e toma decisões com base em um pool disponível. Não faz diferença para o algoritmo se esse pool é destinado a dimensionar uma única chamada de API ou um monólito inteiro.
Portanto, seria bom se o balanceador de carga fosse inteligente o suficiente para reconhecer quando uma consulta resultaria em dados "acima da média" antes de ser executada. Firewalls de aplicativos da Web, como o F5 WAF, conseguem reconhecer quando um resultado está fora do comum, mas isso depende da resposta e permite principalmente uma melhor segurança do aplicativo. O que precisamos é que o balanceador de carga seja inteligente o suficiente para prever uma resposta legítima "extragrande".
Se o balanceador de carga fosse capaz desse tipo de discernimento, ele poderia levar isso em consideração na tomada de decisões e distribuir as solicitações de maneira mais uniforme entre os recursos disponíveis. O que realmente queremos é não ser forçados a especificar um algoritmo rígido para tomar decisões. Seria melhor se o balanceador de carga pudesse tomar a decisão com base nos limites de negócios e nas características técnicas, como tempos de resposta, tempo de execução previsto, tamanho dos dados retornados e a carga atual em cada recurso.
Em última análise, esse é o tipo de inteligência que só pode ser alcançado por meio de melhor visibilidade e aprendizado de máquina. Se o balanceador de carga puder aprender por meio da experiência a reconhecer quais consultas levam mais tempo do que outras, ele poderá aplicar esse conhecimento para distribuir melhor as solicitações, de modo que um tempo de resposta consistente e previsível possa ser alcançado.
O balanceamento de carga não vai desaparecer. É a nossa melhor resposta técnica para dimensionar tudo, da rede aos aplicativos. Mas ele precisa evoluir junto com o resto da infraestrutura para ser mais dinâmico, autônomo e inteligente.