Otimização de TCP para o desempenho e a resiliência da rede


Esta página descreve métodos para calcular as definições corretas para diminuir a latência das suas ligações TCP em cenários híbridos e na nuvem. Google Cloud Esta página também ajuda a compreender formas de melhorar a latência da ligação entre processos no Google Cloud.

A arquitetura de microserviços moderna defende que os programadores devem criar pequenos serviços com uma única responsabilidade. Os serviços devem comunicar através de TCP ou UDP, com base nas expetativas de fiabilidade do sistema. Por isso, é fundamental que os sistemas baseados em microsserviços comuniquem com fiabilidade e baixa latência.

Google Cloud oferece fiabilidade e baixa latência, disponibilizando uma rede global, o que significa que os utilizadores da sua aplicação também podem expandir-se a nível global. Ter uma rede global significa que cria uma rede de nuvem virtual privada (VPC) que abrange regiões e zonas. As aplicações podem estabelecer ligação entre si em várias regiões e zonas sem nunca sair da Google Cloud rede.

As aplicações escritas para um ambiente de centro de dados tradicional podem apresentar um desempenho lento quando são movidas para um ambiente de nuvem híbrida, ou seja, quando alguns dos componentes da aplicação são executados num centro de dados corporativo e outros são executados na nuvem. O desempenho lento pode ser o resultado de vários fatores. Este artigo centra-se nas latências de ida e volta e na forma como a latência afeta o desempenho do TCP em aplicações que movem uma quantidade considerável de dados em qualquer parte da rede.

Otimize o desempenho do TCP

O problema: latência e comportamento de TCP

O TCP usa um mecanismo de janelas para impedir que um remetente rápido ultrapasse um recetor lento. O recetor anuncia a quantidade de dados que o remetente deve enviar antes de ter de aguardar uma atualização da janela do recetor. Como resultado, se uma aplicação de receção não conseguir receber dados na ligação, existe um limite para a quantidade de dados que podem ser colocados em fila de espera pela aplicação.

A janela TCP permite uma utilização eficiente da memória nos sistemas de envio e receção. À medida que a aplicação de receção consome dados, são enviadas atualizações de janelas ao remetente. A atualização da janela mais rápida possível ocorre num ciclo de ida e volta, o que leva à seguinte fórmula para um dos limites do desempenho da transferência em massa de uma ligação TCP:

Débito <= tamanho da janela / latência do tempo de ida e volta (RTT)

No design original do TCP, esta janela tem um tamanho máximo de 65 535 bytes (64 KiB - 1). Esta foi a quantidade máxima de dados que o remetente pôde enviar antes de receber uma atualização da janela para permitir o envio de mais dados.

Alterações no TCP desde a sua introdução

Desde a introdução do TCP, algumas funcionalidades importantes foram alteradas:

  • As velocidades típicas da rede aumentaram quatro ordens de magnitude.
  • A memória típica num sistema aumentou quatro ordens de magnitude.

O resultado da primeira alteração é que os tamanhos das janelas TCP originais originaram uma utilização ineficiente dos recursos de rede. Um remetente envia uma quantidade de dados correspondente a uma janela à melhor velocidade possível nas condições de rede e, em seguida, fica inativo durante um período considerável enquanto aguarda a atualização da janela TCP. O resultado da segunda alteração é que os remetentes e os destinatários podem usar mais memória para a rede, de modo a resolver a limitação exposta pela primeira alteração.

O diagrama seguinte ilustra esta troca.

O remetente envia apenas 64 KB de dados e passa muito tempo à espera após o envio antes de receber uma atualização da janela

O remetente não consegue usar totalmente a rede porque está a aguardar a atualização da janela TCP antes de enviar dados adicionais.

Enviar mais dados de cada vez

A solução é enviar mais dados de cada vez. À medida que a largura de banda da rede aumenta, mais dados cabem no canal (rede) e, à medida que o canal fica mais longo, demora mais tempo a confirmar a receção dos dados. Esta relação é conhecida como o produto largura de banda-atraso (BDP). Este valor é calculado como a largura de banda multiplicada pelo tempo de resposta (RTT), o que resulta num valor que especifica o número ideal de bits a enviar para preencher o canal. A fórmula é a seguinte:

BDP (bits) = largura de banda (bits/segundo) * RTT (segundos)

O BDP calculado é usado como o tamanho da janela TCP para otimização.

Por exemplo, imagine que tem uma rede de 10 Gbps com um RTT de 30 milissegundos. Para o tamanho da janela, use o valor do tamanho da janela TCP original (65 535 bytes). Este valor não se aproxima da utilização da capacidade de largura de banda. O desempenho máximo de TCP possível nesta associação é o seguinte:

(65535 bytes * 8 bits/byte) = largura de banda * 0,030 segundos
largura de banda = (65535 bytes * 8 bits/byte) / 0,030 segundos
largura de banda = 524280 bits / 0,030 segundos
largura de banda = 17476000 bits / segundo

Por outras palavras, estes valores resultam num débito um pouco superior a 17 Mbits por segundo, o que representa uma pequena fração da capacidade de 10 Gbps da rede.

A solução: dimensionamento do tamanho da janela TCP

Para resolver as limitações de desempenho impostas pelo design original do tamanho da janela TCP, foram introduzidas extensões ao protocolo TCP que permitem que o tamanho da janela seja dimensionado para valores muito maiores. O dimensionamento de janelas suporta janelas até 1 073 725 440 bytes, ou quase 1 GiB. Esta funcionalidade está descrita na RFC 7323 como opção de escala da janela TCP.

As extensões de escala da janela expandem a definição da janela TCP para usar 30 bits e, em seguida, usam um fator de escala implícito para transportar este valor de 30 bits no campo da janela de 16 bits do cabeçalho TCP. Para ver se a funcionalidade está ativada em sistemas baseados no Linux, use o seguinte comando:

sudo sysctl net.ipv4.tcp_window_scaling

Todas as máquinas virtuais Linux têm esta funcionalidade ativada por predefinição. Google Cloud Um valor de retorno de 1 indica que a opção está ativada. Se a funcionalidade estiver desativada, pode ativá-la através do seguinte comando:

sudo sysctl -w net.ipv4.tcp_window_scaling=1

Débito com um tamanho da janela maior

Pode usar o exemplo anterior para mostrar a vantagem de ter o dimensionamento da janela. Tal como antes, suponha uma rede de 10 Gbps com uma latência de 30 milissegundos e, em seguida, calcule um novo tamanho da janela através desta fórmula:

(Velocidade da ligação * latência) / 8 bits = tamanho da janela

Se introduzir os números de exemplo, obtém o seguinte:

(10 Gbps * 30 ms/1000 seg) / 8 bits/byte = tamanho da janela
(10 000 Mbps * 0,030 segundos) / 8 bits/byte = 37,5 MB

Aumentar o tamanho da janela TCP para 37 MB pode aumentar o limite teórico do desempenho da transferência em massa de TCP para um valor próximo da capacidade da rede. Claro que muitos outros fatores podem limitar o desempenho, incluindo a sobrecarga do sistema, o tamanho médio dos pacotes e o número de outros fluxos que partilham o link, mas, como pode ver, o tamanho da janela mitiga substancialmente os limites impostos pelo tamanho da janela limitado anterior.

Definir parâmetros ajustáveis do Linux para alterar o tamanho da janela TCP

No Linux, o tamanho da janela TCP é afetado pelos seguintes sysctl(8) ajustáveis:

net.core.rmem_max
net.core.wmem_max
net.ipv4.tcp_rmem
net.ipv4.tcp_wmem

Os dois parâmetros ajustáveis afetam o tamanho máximo da janela TCP para aplicações que tentam controlar o tamanho da janela TCP diretamente, limitando o pedido das aplicações a não mais do que esses valores. Os dois parâmetros ajustáveis seguintes afetam o tamanho da janela TCP para aplicações que permitem que o ajuste automático do Linux faça o trabalho.

O valor ideal do tamanho da janela depende das suas circunstâncias específicas, mas um ponto de partida é o maior BDP (produto largura de banda-atraso) para o caminho ou os caminhos através dos quais espera que o sistema envie dados. Nesse caso, deve definir os parâmetros ajustáveis através dos seguintes passos:

  1. Certifique-se de que tem privilégios de raiz.
  2. Obter as definições de buffer atuais. Guarde estas definições caso queira reverter estas alterações.

    sudo sysctl -a | grep mem
    
  3. Defina uma variável de ambiente para o novo tamanho da janela TCP que quer usar:

    MaxExpectedPathBDP=8388608
    
  4. Defina o tamanho máximo da memória intermédia de receção do SO para todos os tipos de ligações:

    sudo sysctl -w net.core.rmem_max=$MaxExpectedPathBDP
    
  5. Defina o tamanho máximo do buffer de envio do SO para todos os tipos de ligações:

    sudo sysctl -w net.core.wmem_max=$MaxExpectedPathBDP
    
  6. Defina as definições do buffer de memória de receção de TCP (tcp_rmem):

    sudo sysctl -w net.ipv4.tcp_rmem="4096 87380 $MaxExpectedPathBDP"
    

    A definição tcp_rmem assume três valores:

    • O tamanho mínimo da memória intermédia de receção que pode ser atribuído a um socket TCP. Neste exemplo, o valor é 4096 bytes.
    • O tamanho do buffer de receção predefinido, que também substitui o valor /proc/sys/net/core/rmem_default usado por outros protocolos. No exemplo, o valor é de 87380 bytes.
    • O tamanho máximo da memória intermédia de receção que pode ser atribuído a um socket TCP. No exemplo, isto está definido para o valor que definiu anteriormente (8388608 bytes).
  7. Defina as definições do buffer de memória de envio TCP (tcp_wmem):

    sudo sysctl -w net.ipv4.tcp_wmem="4096 16384 $MaxExpectedPathBDP"
    

    A definição tcp_wmem assume três valores:

    • O espaço mínimo da memória intermédia de envio de TCP disponível para uma única porta TCP.
    • O espaço de buffer predefinido permitido para um único soquete TCP.
    • O espaço máximo da memória intermédia de envio de TCP.
  8. Defina os parâmetros ajustáveis para que as ligações subsequentes usem os valores que especificou:

    sudo sysctl -w net.ipv4.route.flush=1
    

Para manter estas definições nos reinícios, acrescente os comandos que definiu anteriormente ao ficheiro /etc/sysctl.conf:

sudo bash -c 'cat << EOF >> /etc/sysctl.conf
net.core.rmem_max=8388608
net.core.wmem_max=8388608
net.ipv4.tcp_rmem=4096 87380 8388608
net.ipv4.tcp_wmem=4096 16384 8388608
net.ipv4.route.flush=1
EOF'

Testar RTT com um tamanho da janela atualizado

Quando o TCP tem um tamanho da janela suficientemente grande para usar o BDP, a imagem muda, conforme mostrado no diagrama seguinte:

O remetente envia uma grande quantidade de dados de cada vez e passa muito pouco tempo à espera de uma atualização da janela

O tamanho da janela TCP pode sempre ser adaptado com base nos recursos disponíveis para o processo envolvido e o algoritmo TCP em utilização. Conforme mostra o diagrama, o dimensionamento da janela permite que uma ligação vá muito além do tamanho da janela de 65 KiB definido na especificação TCP original.

Pode testar isto. Primeiro, certifique-se de que fez alterações ao tamanho da janela TCP no seu computador local e num computador remoto definindo os parâmetros ajustáveis em ambas as máquinas. Em seguida, execute os seguintes comandos:

dd if=/dev/urandom of=sample.txt bs=1M count=1024 iflag=fullblock
scp sample.txt your_username@remotehost.com:/some/remote/directory

O primeiro comando cria um ficheiro de 1 GB sample.txt com dados aleatórios. O segundo comando copia esse ficheiro da sua máquina local para uma máquina remota.

Tenha em atenção o resultado do comando scp na consola, que apresenta a largura de banda em Kbps. Deve ver uma diferença considerável nos resultados antes e depois das alterações ao tamanho da janela TCP.

Otimize a resiliência da rede TCP através da rerota protetora

O Protective ReRoute (PRR) é uma técnica baseada no anfitrião para encaminhar pacotes em torno de falhas numa rede de vários caminhos. A Google implementa a PRR em toda a frota e complementa os mecanismos de resiliência da rede padrão para melhorar a disponibilidade geral da rede.

A PRR está disponível para Google Cloud clientes em dois modos: modo de hipervisor e modo de convidado. Todos os Google Cloud clientes recebem automaticamente o PRR do modo de hipervisor sem que sejam necessárias ações.

O PRR no modo de hipervisor protege a grande maioria do tráfego, com determinadas exceções:

  • Se uma instância tiver um enorme volume de tráfego (por exemplo, se uma instância estiver a enviar ativamente pacotes para milhares de instâncias em várias regiões ao mesmo tempo), nem todos os pacotes estão protegidos.

  • O PRR no modo de hipervisor protege os segmentos principais do caminho de rede, mas não é totalmente ponto a ponto.

  • O PRR no modo de hipervisor reage em segundos de um único dígito.

O PRR do modo de convidado pode ser usado para aplicações críticas que são particularmente sensíveis a eventos de rede de curta duração, têm padrões de distribuição amplos, são altamente sensíveis à perda de pacotes ou requerem o tempo de recuperação de rede mais rápido possível (na escala de tempo de RTT). Pode adotar a PRR do modo convidado se cumprir as seguintes condições:

  • A instância de computação tem de executar o Linux com o kernel 4.20 ou posterior. Para verificar a versão do kernel do Linux, execute o comando uname -r na instância de computação.
  • As seguintes opções sysctl têm de estar ativadas: /proc/sys/net/ipv6/auto_flowlabels. Normalmente, esta opção sysctl está ativada por predefinição.
  • Se for usado com a interface de rede VirtIO, apenas o tráfego de rede IPv6 está protegido.
  • Se for usado com a interface de rede gVNIC, o tráfego de rede IPv4 e IPv6 está protegido.

O que se segue?