Alura > Cursos de DevOps > Cursos de Redes > Conteúdos de Redes > Primeiras aulas do curso NGINX Parte 2: performance, FastCGI e HTTPS

NGINX Parte 2: performance, FastCGI e HTTPS

Load balancer - Apresentação

Olá, pessoal! Boas-vindas à Alura. Eu sou o Vinicius Dias e vou guiar vocês nesse segundo treinamento de nginx. No treinamento anterior, nós já aprendemos o que é nginx, para que serve, como configurar um servidor web, proxy reverso, um load balancer, e agora vamos nos aprofundar em todos esses conteúdos.

Vamos ver mais algoritmos de load balancer, vamos entender o que é esse tal de round Robin, vamos ver sobre o least connections, waited round Robin, vamos entender todos esses nomes, e depois vamos conhecer um tal de fast cdi, como a internet evoluiu até chegar nesse ponto e o que mais existe, além disso. Mas claro, na prática, vamos fazer requisições para um servidor de fast cdi.

Depois vamos falar um pouco de performance. Principalmente usando o que o http já fornece para nós, cache, HTTP, compressão, keep alive, ou seja, manter conexões abertas, esse tipo de coisa bastante importante e interessante. Depois vamos falar um pouco sobre cache no lado do servidor, porque o nginx além de ser um load balancer, um proxy reverso, um servidor web, também pode ser um servidor de cache, e vamos ver como implementar isso, na prática.

No final vamos dar uma pincelada no assunto de segurança, configurando nginx para ler nossos certificados gerados por nós mesmos para abrir um site como https. Nós vamos entender um pouco sobre esse monte de nome de entidades certificadoras, certificados digitais, etc., mas nós vamos utilizar um certificado auto assinado para não usar nada externo e para não precisarmos de domínios, etc.

Mas não se assuste que isso tudo vai ficar bem mais claro lá para a frente. E se nesse processo alguma dúvida surgir, não hesite, abra um tópico no fórum, eu tento responder pessoalmente sempre que possível, mas quando não consigo nossa comunidade de alunos, moderados e instrutores é muito solícita e com certeza alguém vai conseguir te ajudar. Mais uma vez seja bem-vindo, espero que você aproveite bastante esse treinamento e até o próximo vídeo para começarmos a colocar a mão na massa.

Load balancer - Definindo pesos

No final do último treinamento, o que nós fizemos? Nós implementamos essa ilustração, um load balancer, ou um balanceador de cargas. Vamos recapitular o que fizemos, como isso foi implementado para pensarmos em um possível problema.

Temos um cliente, você, eu, qualquer pessoa na internet, acessando algum site, imagino que é o site da Alura. E o site da Alura por receber muitas requisições precisamos separar em mais de um servidor. Caso um servidor caia temos outro de pé, funcionando, para não sobrecarregar esses servidores, porque eles não aguentariam toda essa carga. Por vários motivos precisamos dividir esses servidores.

Quando esse cliente acessa um site da Alura temos o engine next configurado como um load balancer e cada requisição vai cair em um servidor diferente. Chegou a primeira requisição? Cai no primeiro. Chego outra requisição? Cai no segundo. Chegou mais uma? Primeiro, segundo, e vai dividindo igualmente as requisições.

Se temos 100 requisições chegando, 50 vão chegar para um servidor, 50 vão chegar para o outro. Vamos só recapitular rápido como implementamos isso. Vou abrir meu terminal. Lembrando que como estou no Mac meus caminhos são esses, mas para você saber o caminho na sua configuração, no seu sistema operacional, nginx -t vai mostrar o arquivo padrão.

Então meu arquivo padrão é esse nginx conf, nesse arquivo padrão sei que ele inclui todos os arquivos .conf de servers. Temos um load balancer, vamos abrir ele para ver e se precisar já modificar. Então usr/local/etc/nginx/servers/load-balancer, nesse load balancer estamos ouvindo a porta 8003 e cada hora que chega uma requisição para essa porta hora ele vai mandar para o serviço 1 hora ele vai mandar para o serviço 2.

Vamos testar isso de novo só para relembrarmos, hora ele manda para o serviço 1, e quando atualizo ele vai para o serviço 2. Ele vai alternando entre um e outro.

Recapitulamos o conceito de load balancer, vamos avançar um pouco. Imagine que por algum motivo, porque nossa infraestrutura é assim, porque isso foi configurado dessa forma, por algum motivo temos um servidor maior do que outro, com mais capacidade de responder requisições.

Imagine que nós temos dois servidores respondendo, no nosso caso o de serviço 1 e o de serviço 2. E o servidor que contém esse serviço 1, que está respondendo nessa porta, tem o dobro de memória RAM, de CPU, o dobro da capacidade de receber requisições. Então se ficamos mandando metade para cada um, se mantemos essa estrutura de chega uma requisição vai para um, chega outro vai para outro, vamos acabar sobrecarregando esse servidor menor ou não utilizando todos os recursos disponíveis no servidor maior.

O que quero fazer é poder atribuir pesos diferentes para cada um dos meus servidores disponíveis, e fazer isso com nginx é muito simples, posso informar que este servidor 1 tem o peso de 2. Posso usar qualquer número, posso dizer que tem peso 5 enquanto o outro tem peso 2, ou seja, a cada 7 requisições que chegam no meu sistema 5 vão cair no serviço 1 e duas vão cair no serviço 2.

Posso configurar esse peso de forma proporcional. Vou manter configurado o serviço 1 com peso 2 e o serviço 2 vai estar no padrão dele, que é o peso 1. Vou salvar isso, mas lembrando, se alterei essa configuração preciso fazer o meu reload. Nginx recarregado sem erro nenhum, vamos ver o que vai acontecer quando faço as requisições.

Caiu uma requisição no serviço 1, recarreguei mais uma requisição no serviço 1, recarreguei agora no serviço 2. Quando recarrego de novo, serviço 1, serviço 1, serviço 2. A cada duas requisições no serviço 1, uma requisição cai no serviço 2. Dessa forma conseguimos balancear melhor nossa carga. E esse é um dos algoritmos possíveis para balancear a carga. Então vamos falar um pouco de teoria já que já vimos a prática no próximo vídeo.

Load balancer - Algoritmos de balanceamento

Boas-vindas de volta. No último vídeo nós implementamos uma nova forma de um balanceamento de carga. Nós incrementamos nosso conhecimento de balanceamento de carga. Mas nós estudamos muita prática e não falamos tanto da teoria, então vamos entender a teoria por trás de algoritmos de balanceamento de carga.

Por padrão quando configuramos aquele upstream e definimos um proxy pass para um upstream nós temos essa figura, essa é a implementação padrão de um load balancer com nginx. No último vídeo aprendemos a definir pesos, para chegar em algo próximo desse cenário, onde quando tenho várias requisições posso mandar mais requisições para um servidor do que para o outro.

Essa ideia nós já entendemos na prática, mas, na teoria, esse algoritmo tem um nome, e é um nome importante de conhecermos, até porque esse mesmo algoritmo é utilizado em cenários fora de balanceamento de carga, então o nome desse algoritmo é round Robin, ele é utilizado inclusive em contextos de escalonamento de processos.

Não vou entrar em detalhes sobre o que é escalonamento de processos, mas imagina que tenho vários processos para serem executados na mesma CPU, no mesmo núcleo da CPU, como o processador vai decidir qual processo executar por tanto tempo? A implementação de round Robin define um espaço de tempo onde o processo vai ser executado, depois interrompido.

Esse mesmo espaço de tempo, esse mesmo período vai ser executado por outro processo, esse mesmo período vai ser entregue para outro processo executar. Depois outro, depois outro, e assim ele vai rodando. Quando o último finalizou eu volto para o primeiro. Essa é a ideia por trás de um round Robin.

Quando tenho essa mesma ideia implementada em um load balancer tenho isso que o nginx traz por padrão. Se tenho três servidores, por exemplo, imagine que tenho mais um, vou fazer a ligação. Se tenho três servidores a primeira requisição chega nesse, a segunda no segundo, a terceira no terceiro.

Acabou a lista de servidores nós voltamos para o começo, por isso esse nome round Robin, então vamos em quarta requisição, quinta requisição, sexta requisição. Esse é o algoritmo round Robin, só que quando precisamos definir pesos diferentes para cada um dos servidores, por exemplo, temos o que é chamado de waited round Robin ou round Robin ponderado.

Então atingimos esse objetivo através da diretiva wait, demos um peso maior para o servidor, para o primeiro servidor, e o segundo servidor tem um peso um pouco menor. A primeira requisição chega aqui, a segunda também, a terceira chega aqui, a quarta chega aqui, a quinta também, a sexta chega aqui. Assim vamos balanceando, baseado nesse espaço que temos, no número de requisições, puramente. Número de requisições que chegam.

Mas existem outros algoritmos que podem fazer sentido em outros casos, não vou citar todos, para não nos complicarmos muito, mas vou mostrar mais dois aqui. Imagine que vai ser uma requisição, uma conexão aberta. A primeira requisição chegou aqui, chegou a segunda requisição, e a terceira. A quarta chegou, a quinta chegou também, e a sexta chegou embaixo.

Mas o que acontece? Essa primeira requisição era para uma coisa muito simples, então ela já foi encerada, a terceira também. E vamos receber mais uma requisição embaixo, repare que nesse momento estou mandando mais requisições para o meu servidor mais fraco do que para o servidor mais potente, porque minha única métrica é a quantidade de requisições que estão chegando, e não a quantidade de requisições que estão abertas, ou seja, o número de conexões que meu servidor tem abertas.

Nesse cenário, quando tenho requisições que podem ter comportamentos diferentes, onde posso ter requisições muito demoradas e requisições muito simples precisamos balancear isso de forma mais inteligente. Vou apagar isso tudo e vamos pensar em outro cenário.

Vou manter só uma requisição, chegou a primeira requisição. Quando chega a segunda, o load balancer sabendo daqueles pesos que tenho que ter o dobro de requisições vai ver qual servidor tem menos conexões baseado naquele peso. Esse servidor pode receber uma conexão a mais porque ele ainda não tem o dobro lá, vou receber mais uma requisição.

Chegou a próxima requisição, ele vai ver, opa, esse servidor tem duas conexões ativas, e esse outro nenhuma. Vou mandar para cá. E agora nesse meio tempo uma das requisições já foi finalizada. Essa ainda está ativa. Então o load balancer vai mandar mais uma para cá, e de novo temos só duas conexões ativas, então ele pode mandar a próxima para baixo, ele pode mandar mais uma para cá, porque ainda não tem o dobro.

Quando essa requisição morreu, a próxima requisição pode vir para cá, porque tenho três em cima e nenhuma aqui. Ele vai balanceando de forma mais inteligente, sem sobrecarregar nenhum dos dois. Talvez isso tenha ficado muito complexo no desenho, mas basicamente é com peso ou sem peso ele vai ver quais servidores têm menos conexões e mandar essa requisição para lá.

Vamos pensar nisso sem peso, para ficar um pouco mais simples. Chegou uma requisição, vamos trazer para cá. Essa requisição chegou aqui, quando chega a próxima requisição o load balancer vai ver qual tem menos requisições, conexões ativas, ele vai mandar para baixo, e agora qual tem menos conexões ativas? Está igual. Então começa de novo, vai lá para o primeiro servidor.

Nisso, qual tem menos requisições ativas? O segundo, mandou para cá. Porém, enquanto isso, esse servidor a primeira requisição já foi respondida, quando mando a próxima requisição ele pode mandar para cá de novo, balanceando melhor. E nessa meio tempo essa requisição, essa conexão foi encerrada, então posso mandar a próxima para cá. Ele vai balanceando de forma mais inteligente.

Essa é a ideia por trás desse algoritmo de list connections, ou menor número de conexões. E para implementar ele é bastante simples. Basta eu informar no início do meu upstream essa diretiva least_comn, com isso ele vai ver qual o servidor, qual dos meus servers tem menos conexões ativas, abertas, e vai mandar requisição para lá, e ele considera o peso.

Segundo essa informação, again with server wait taken into consideration, então de novo com peso dos servidores sendo considerado. Aqui já temos dois algoritmos, o round Robin, que é o padrão, que já vem implementado sem informarmos nada, e nós temos o de least connections, o que podemos configurar se tivermos essa diretiva least connections.

Existem vários outros, só vou passar o olho, por exemplo, IP Hash, então baseado no hash do ip, ou seja, nas informações do ip que chegou à conexão posso mandar sempre esse mesmo ip para o mesmo servidor. Dessa forma consigo manter uma seção ativa, informações stateful lá, isso não é tão comum assim, mas pode ser bastante útil em alguns cenários.

Tenho um generic hash, posso ter alguma informação gerando hash, então sempre que cair nessa url vai para esse servidor. Quando cair nessa outra url vai para outro servidor. Posso ter informações assim, também é menos comum. Posso ter com least time, então para cada requisição o nginx pode ver qual servidor está com a menor latência além de menor número de conexões, então esse já é um pouco mais complexo, ele é utilizado apenas no nginx plus, ou seja, na versão paga.

Repare que esses outros não têm essa observação, então usamos na versão open source, e o último que pode ser simples de entender, mas que pode trazer complexidade é o de random, ou seja, cada requisição vai ser mandada para um servidor selecionado de forma aleatória.

Mas além dessa ideia aleatória nós podemos trazer algumas configurações. Por exemplo, de todos os servidores, tenho oito servidores, seleciono aleatoriamente dois, e dentro desses dois podemos distribuir através do menor número de conexões, do least time, etc.

Podemos configurar as coisas de formas muito complexas, mas te garanto que os mais comuns são o round Robin e o waited round Robin, e o least connections, quando usamos um desses dois se todas as nossas requisições vão para um servidor de aplicação ou se todas as nossas requisições só servem conteúdos estáticos, o round Robin é perfeito, nós não precisamos de nada além disso.

Agora, se algumas conexões, se um dos meus servidores é maior que outro, tem mais recursos, então o waited round Robin já resolve o caso. Agora se tenho requisições, conexões que vão demorar para ser respondidas e outras que são muito rápidas, então o algoritmo de least connections pode ajudar bastante. Eu posso ter muitas conexões demoradas em um servidor e passo a mandar mais requisições para o outro, dessa forma temos um rebalanceamento um pouco mais esperto.

Então se esse é um pouco mais esperto, por que eu utilizaria o round Robin? Porque ele exige menos do nosso load balancer, ele recebe a requisição e simplesmente vê, o último que mandei foi o servidor 2? Então, agora é 1. O último foi 1? Então, agora é 2. Já esse de least connections precisa armazenar quantas conexões estão abertas, ele tem um custo a mais. Depende do cenário onde você vai implementar cada um, mas essas são as características, prós e contras.

Sobre o curso NGINX Parte 2: performance, FastCGI e HTTPS

O curso NGINX Parte 2: performance, FastCGI e HTTPS possui 105 minutos de vídeos, em um total de 39 atividades. Gostou? Conheça nossos outros cursos de Redes em DevOps, ou leia nossos artigos de DevOps.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Redes acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas