O NGINX Plus R9 apresenta a capacidade de reverter proxy e balancear a carga do tráfego UDP, uma melhoria significativa nos recursos de balanceamento de carga da Camada 4 do NGINX Plus.
Esta postagem do blog analisa os desafios de executar um servidor DNS em uma infraestrutura de aplicativo moderna para ilustrar como o NGINX Open Source e o NGINX Plus podem balancear a carga de tráfego UDP e TCP de forma eficaz e eficiente. (As verificações de integridade do aplicativo [ativo] são exclusivas do NGINX Plus, mas, de outra forma, as informações neste blog se aplicam igualmente ao NGINX Open Source; para resumir, nos referiremos ao NGINX Plus no restante da postagem).
[Editor – Para uma visão geral de todos os novos recursos do NGINX Plus R9, consulte Anunciando o NGINX Plus R9 em nosso blog.]
Ao contrário do TCP, o UDP não garante, por definição, a entrega de dados de ponta a ponta. É semelhante a enviar uma mensagem por pombo-correio: você definitivamente sabe que a mensagem foi enviada, mas não pode ter certeza de que ela chegou. Há vários benefícios nessa abordagem “sem conexão” – mais notavelmente, menor latência do que o TCP, tanto porque as mensagens individuais menores do UDP usam menos largura de banda quanto porque não há um processo de handshake para estabelecer uma conexão. O UDP deixa o problema de detecção de tempos limite e outros problemas de nível de rede para o desenvolvedor do aplicativo. Mas o que isso significa para o DNS?
Como vários outros protocolos baseados em UDP, o DNS usa um fluxo de dados de solicitação-resposta. Por exemplo, um cliente DNS solicita o endereço IP correspondente a um nome de host e recebe uma resposta. Se uma resposta não chegar dentro de um determinado período de tempo limite, o cliente DNS envia a mesma solicitação para um servidor DNS “backup”. No entanto, ter que esperar o tempo limite antes de tentar novamente uma solicitação pode transformar o que normalmente é um processo extremamente rápido (medido em milissegundos) em um processo muito lento (medido em segundos).
Usar o NGINX Plus para fazer proxy e balancear a carga do tráfego DNS reduz o número de ocasiões em que o cliente enfrenta um tempo limite. Com vários servidores DNS por trás do balanceador de carga NGINX Plus, os clientes só enfrentam um tempo limite quando há uma partição de rede entre o cliente e o NGINX Plus. O cliente não enfrenta problemas com os servidores DNS quando o NGINX Plus usa verificações de integridade do aplicativo . Ao monitorar a disponibilidade e o tempo de resposta de cada servidor, o NGINX Plus evita o envio de solicitações de clientes para um servidor com problemas.
Embora a grande maioria do tráfego DNS seja via UDP, há operações DNS comuns que usam TCP. O DNS usa UDP para mensagens pequenas (até 512 bytes), mas TCP para operações que exigem (ou provavelmente exigirão) mensagens maiores. Historicamente, o TCP era usado com DNS apenas para transferências de zona de um servidor de nomes primário autoritativo para seus servidores de nomes secundários. No entanto, com a mudança para contêineres e infraestrutura imutável, o DNS é cada vez mais usado como o principal mecanismo de descoberta de serviços, por meio do uso de registros SRV
.
Os registros DNS SRV
foram originalmente introduzidos para aparelhos de voz sobre IP (VoIP) usando SIP para descobrir seus servidores, mas podem ser usados para qualquer tipo de serviço. No entanto, os registros SRV
incluem muito mais informações do que a maioria dos outros tipos de registros DNS. Como resultado, apenas cerca de 10 registros SRV
cabem na resposta UDP padrão de 512 bytes, em oposição a cerca de 30 registros A.
Quando uma resposta DNS excede o limite de 512 bytes, os primeiros 512 bytes são retornados, mas a resposta é sinalizada como “truncada”. Neste ponto, um cliente DNS pode lidar com a resposta truncada da melhor forma possível ou tentar novamente a mesma solicitação usando TCP.
Isso significa que, ao balancear a carga de servidores DNS em uma infraestrutura de rede moderna, o NGINX Plus pode esperar receber uma mistura de tráfego UDP e TCP.
A ilustração a seguir mostra uma visão simplificada de um ambiente de microsserviços com dois balanceadores de carga. O balanceador de carga de frontend faz proxy de solicitações dos clientes públicos do aplicativo, selecionando a melhor instância de microsserviço e executando muitas outras funções que não discutiremos aqui. Vamos nos concentrar no balanceador de carga DNS, que fica entre o ambiente de microsserviços e os servidores DNS que fornecem informações de descoberta de serviço para os microsserviços.
O NGINX Plus implementa o balanceamento de carga da Camada 4 no módulo Stream , de modo que o balanceamento de carga UDP e TCP é configurado no bloco stream
, conforme mostrado no snippet a seguir.
Aviso: Você não pode simplesmente adicionar este trecho de configuração como um novo arquivo no diretório /etc/nginx/conf.d . Ocorre um erro de validação (“a diretiva de fluxo não é permitida aqui”) porque o arquivo de configuração padrão nginx.conf do NGINX Plus inclui o conteúdo dos arquivos no diretório conf.d no bloco http
. A solução mais simples é incluir o bloco de fluxo
completo diretamente em nginx.conf .
fluxo { upstream dns_servers {
servidor 192.168.136.130:53;
servidor 192.168.136.131:53;
}
servidor {
ouvir 53 udp;
ouvir 53; #tcp
proxy_pass dns_servers;
log_de_erros /var/log/nginx/dns.log info;
}
}
Primeiro definimos o grupo upstream de servidores DNS. As diretivas do servidor
especificam o número da porta em que nossos servidores upstream estão escutando, 53 (a porta conhecida para DNS).
O bloco server{}
define como o NGINX Plus lida com o tráfego DNS de entrada. As duas diretivas de escuta
informam ao NGINX Plus para escutar na porta 53 o tráfego UDP e TCP. TCP é o protocolo padrão da Camada 4 para o módulo Stream, então não o especificamos explicitamente como um parâmetro como fazemos para UDP.
A diretiva proxy_pass
informa ao NGINX Plus o que fazer com o tráfego que está escutando. Aqui, enviamos esse tráfego para o grupo upstream dns_servers . O NGINX Plus usa UDP automaticamente ao encaminhar solicitações UDP do cliente para servidores upstream (e TCP para solicitações TCP do cliente), então não precisamos especificar explicitamente o protocolo da Camada 4 no grupo upstream.
Não há diretiva access_log
no módulo Stream, porque o NGINX Plus não inspeciona a carga útil de segmentos TCP ou datagramas UDP (como faz para pacotes HTTP). No entanto, podemos usar o parâmetro info
na diretiva error_log
para registrar o processamento de conexão e eventos de proxy.
[Editor – O registro de acesso foi habilitado no módulo Stream após a publicação deste blog, no NGINX Open Source 1.11.4 e no NGINX Plus R11 .]
Para melhorar a disponibilidade dos nossos servidores DNS, podemos adicionar mais algumas diretivas e configurar verificações de integridade ativas (do aplicativo).
A primeira diretiva adicional é proxy_responses
, que diz quantas respostas o NGINX Plus espera para cada solicitação UDP com proxy. No nosso caso, após receber uma única resposta, o NGINX Plus para imediatamente de esperar por outras respostas, o que libera a memória e o soquete usados para aquela sessão.
A segunda diretiva adicional, proxy_timeout
, determina quanto tempo o NGINX Plus aguarda uma resposta do servidor (aqui estamos reduzindo o padrão de 10 minutos para 1 segundo). Se o NGINX Plus não receber nenhuma resposta dentro desse período, ele tentará o próximo servidor no grupo upstream e marcará o servidor upstream que não responde como indisponível por um período definido (10 segundos por padrão) para que nenhum outro cliente sofra um atraso induzido por tempo limite durante esse período.
servidor { ouvir 53 udp; ouvir 53; #tcp proxy_pass servidores_dns; log_de_erros /var/log/nginx/dns.log info; respostas_proxy 1 ; tempo_limite_proxy 1s ; }
Também podemos alterar a quantidade de tempo que um servidor fica marcado como indisponível, incluindo a opção fail_timeout
na diretiva server
no grupo upstream. Com a seguinte configuração, o NGINX Plus marca servidores upstream com falha como indisponíveis por 60 segundos:
servidores dns upstream { servidor 192.168.136.130:53 fail_timeout=60s ; servidor 192.168.136.131:53 fail_timeout=60s ; }
Isso nos permite controlar quanto atraso um cliente experimentará caso um de nossos servidores DNS falhe. Entretanto, se uma solicitação TCP for tentada para um servidor DNS com falha, a verificação de erros inerente no TCP permite que o NGINX Plus o marque automaticamente como indisponível para que solicitações subsequentes de TCP ou UDP para esse servidor sejam evitadas.
O recurso de verificação de integridade ativa no NGINX Plus é uma ferramenta adicional e extremamente valiosa para alta disponibilidade de qualquer serviço com balanceamento de carga, incluindo DNS. Em vez de esperar que uma solicitação TCP real de um cliente DNS falhe antes de marcar o servidor DNS como inativo, fazemos com que o NGINX Plus tente periodicamente uma conexão TCP na porta 53 para estabelecer se o servidor DNS está ativo e funcionando corretamente, incluindo a diretiva health_check
com seu parâmetro port=53
no bloco server{}
. (O NGINX Plus, por padrão, envia verificações de integridade para a porta especificada pela diretiva listen
, 53 no nosso caso. Então aqui estamos usando o parâmetro para configurar o padrão explicitamente, mas poderíamos especificar uma porta diferente se também modificássemos nossos servidores DNS para responder ao tráfego nela.)
Com o UDP, podemos ir um passo além e configurar uma verificação de integridade ativa que faz uma pesquisa de DNS real para um registro conhecido. Por exemplo, podemos colocar o seguinte registro CNAME
no arquivo de zona para o mesmo subdomínio usado para descoberta de serviços no ambiente de microsserviços.
healthcheck EM CNAME healthy.svcs.example.com.
Dada a natureza leve do UDP, podemos observar o tráfego de rede e extrair facilmente a sequência de bytes que representa uma pesquisa de DNS. Em seguida, criamos um bloco de configuração de correspondência
com essa string como parâmetro para a diretiva de envio
. A diretiva expect
especifica a resposta que o servidor deve retornar para ser considerado íntegro.
corresponder dns_lookup {
enviar x00x01x00x00x00x01x00x00x00x00x00x00x00x06x68x65x61 ...;
esperar ~* "healthy.svcs.example.com.";
}
O benefício dessa verificação profunda de integridade no nível do aplicativo é que, mesmo que seu servidor de nomes esteja ativo e em execução, realizar uma pesquisa de DNS real para seu domínio de produção revela problemas de configuração e corrupção de dados que poderiam causar problemas posteriormente.
A equipe de suporte do NGINX Plus pode ajudar a preparar verificações de integridade do UDP para pesquisas de DNS e outros protocolos.
O snippet a seguir destaca as diretivas adicionais necessárias para verificações de integridade ativas.
fluxo { upstream dns_servers { zona dns_mem 64k ; servidor 192.168.136.130:53 fail_timeout=60s; servidor 192.168.136.131:53 fail_timeout=60s; } correspondência dns_lookup { enviar x00x01x00x00x00x01x00x00x00x00x00x00x06x68x65x61 ...; esperar ~* "healthy.svcs.example.com."; } servidor { ouvir 53 udp; ouvir 53; #tcp health_check correspondência=dns_lookup intervalo=20 falhas=2 aprovações=2 udp; health_check intervalo=20 falhas=1 aprovações=2 porta=53; #tcp proxy_pass dns_servers; error_log /var/log/nginx/dns.log depuração; respostas do proxy 1; tempo limite do proxy 1s; } }
A diretiva de zona
define uma zona de memória compartilhada chamada dns_mem , que disponibiliza os resultados das verificações de integridade (e outras informações de estado) para todos os processos de trabalho do NGINX Plus.
A diretiva match
é discutida logo acima.
A diretiva health_check
tem vários parâmetros que você pode ajustar para seu ambiente. Aqui definimos verificações de integridade separadas para UDP e TCP, respectivamente. Devido à diferença entre UDP e TCP, exigimos duas falhas sucessivas de verificação de integridade do UDP antes de marcar o servidor DNS como não íntegro, mas apenas uma falha do TCP. Para ambos os protocolos, exigimos duas respostas bem-sucedidas antes de marcar um servidor como saudável novamente, para evitar o envio de solicitações para um servidor instável e "oscilante".
Uma vantagem de definir um único grupo upstream de servidores DNS para tráfego UDP e TCP é que uma verificação de integridade com falha para qualquer um dos protocolos marca o servidor como não íntegro e o remove do pool com balanceamento de carga.
Embora a implantação de apenas dois servidores de back-end possa ser uma solução eficaz de alta disponibilidade, os recursos de balanceamento de carga do NGINX Plus permitem que você dimensione os servidores de back-end horizontalmente sem o conhecimento do cliente.
É improvável que o ambiente de microsserviços de exemplo descrito acima exija o dimensionamento dos servidores DNS de backend. No entanto, um ISP que fornece serviços de DNS a todos os seus assinantes sofre carga constante e potencial para picos enormes, criando a necessidade de um grande número de servidores DNS e um proxy front-end para balancear a carga do tráfego entre eles.
Todos os algoritmos de balanceamento de carga NGINX e NGINX Plus estão disponíveis para TCP e UDP, bem como HTTP:
(Você também pode configurar pesos em todos os algoritmos para aumentar ainda mais sua eficiência. Para uma discussão, consulte a seção sobre pesos em Escolhendo uma técnica de balanceamento de carga NGINX Plus em nosso blog.)
Enquanto as solicitações HTTP podem variar enormemente em termos de carga e demandas de processamento colocadas nos servidores de backend, as solicitações DNS normalmente geram a mesma carga. Por esse motivo, é improvável que os algoritmos de Menos Conexões e Menos Tempo ofereçam vantagem sobre o Round Robin. Em particular, Least Connections inclui em sua contagem de conexões quaisquer solicitações UDP para as quais o NGINX Plus ainda está aguardando uma resposta do servidor upstream. Enquanto os valores para proxy_responses
e proxy_timeout
não forem atingidos, o NGINX Plus ainda estará contando conexões para servidores upstream que podem já ter concluído seu trabalho.
Quando você tem um grande número de clientes e um protocolo que faz muito “diálogo” – várias mensagens trocadas entre cliente e servidor, como no fluxo de desafio-resposta RADIUS – então usar um hash de IP de origem permite que esse diálogo ocorra com um único servidor de backend. Em outras palavras, ele estabelece a persistência da sessão , o que significa que o NGINX Plus direciona todas as solicitações de um determinado cliente para o mesmo servidor. O exemplo a seguir configura o algoritmo de balanceamento de carga Hash para um par de servidores de autenticação RADIUS, com o endereço IP de origem (cliente) (capturado pela variável $remote_addr
) como a chave.
upstream radius_servers { hash $remote_addr; # Hash do IP de origem
servidor 192.168.136.201:1812;
servidor 192.168.136.202:1812;
}
Para obter mais informações sobre balanceamento de carga UDP e TCP, confira os seguintes recursos:
upstream
Para saber mais sobre outros excelentes recursos do NGINX Plus R9, consulte Anunciando o NGINX Plus R9 em nosso blog e assista ao nosso webinar sob demanda, Novidades no NGINX Plus R9 .
Para experimentar o NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso.
"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."