Otimização TCP para desempenho de rede


Esta página descreve métodos para calcular as configurações corretas para diminuir a latência de suas conexões TCP em Google Cloud e cenários híbridos. Esta página também ajuda você a entender maneiras de melhorar a latência da conexão entre processos dentro Google Cloud.

A arquitetura moderna de microsserviços defende que os desenvolvedores devem construir pequenos serviços com responsabilidade única. Os serviços devem se comunicar utilizando TCP ou UDP, com base nas expectativas de confiabilidade do sistema. Portanto, é fundamental que os sistemas baseados em microsserviços se comuniquem com confiabilidade e baixa latência.

Google Cloud fornece confiabilidade e baixa latência ao fornecer uma rede global , o que significa que os usuários do seu aplicativo também podem se tornar globais. Ter uma rede global significa criar uma rede de nuvem privada virtual (VPC) que abrange regiões e zonas . Os aplicativos podem se conectar entre si em regiões e zonas sem nunca sair do Google Cloud rede.

Os aplicativos que foram escritos para um ambiente de data center tradicional podem apresentar desempenho lento quando são movidos para um ambiente de nuvem híbrida, ou seja, quando alguns dos componentes do aplicativo são executados em um data center corporativo e outros são executados na nuvem. O desempenho lento pode ser o resultado de vários fatores. Este artigo se concentra nas latências de ida e volta e em como a latência afeta o desempenho do TCP em aplicativos que movem uma quantidade considerável de dados em qualquer parte da rede.

O problema: latência e comportamento do TCP

O TCP usa um mecanismo de janelamento para evitar que um remetente rápido ultrapasse um receptor lento. O receptor anuncia quantos dados o remetente deve enviar antes que o remetente precise aguardar uma atualização da janela do destinatário. Como resultado, se um aplicativo receptor não puder receber dados na conexão, haverá um limite para a quantidade de dados que poderá ficar na fila aguardando o aplicativo.

A janela TCP permite o uso eficiente da memória nos sistemas de envio e recebimento. À medida que o aplicativo receptor consome dados, as atualizações da janela são enviadas ao remetente. O mais rápido que a atualização da janela pode acontecer é em uma viagem de ida e volta, o que leva à seguinte fórmula para um dos limites do desempenho de transferência em massa de uma conexão TCP:

Taxa de transferência <= tamanho da janela/latência do tempo de ida e volta (RTT)

No design original para TCP, esta janela tem tamanho máximo de 65.535 bytes (64 KiB - 1). Essa era a quantidade máxima de dados que o remetente poderia enviar antes de receber uma atualização de janela para permitir o envio de mais dados.

Mudanças no TCP desde sua introdução

Desde que o TCP foi introduzido, alguns recursos principais mudaram:

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

O resultado da primeira mudança é que os tamanhos originais das janelas TCP levaram a um uso ineficiente dos recursos da rede. Um remetente enviaria dados de uma janela na melhor velocidade possível sob condições de rede e, em seguida, ficaria ocioso por um período de tempo considerável enquanto aguardava a atualização da janela TCP. O resultado da segunda mudança é que remetentes e destinatários podem usar mais memória para rede para resolver a limitação exposta pela primeira mudança.

O diagrama a seguir ilustra esse intercâmbio.

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

O remetente não pode utilizar totalmente a rede porque está aguardando a atualização da janela TCP antes de enviar dados adicionais.

Enviando mais dados por vez

A solução é enviar mais dados por vez. À medida que a largura de banda da rede aumenta, mais dados podem caber no canal (rede) e, à medida que o canal fica mais longo, leva mais tempo para confirmar o recebimento dos dados. Essa relação é conhecida como produto de atraso de largura de banda (BDP). Isso é calculado como a largura de banda multiplicada pelo tempo de ida e volta (RTT), resultando em um valor que especifica o número ideal de bits a serem enviados para preencher o canal. A fórmula é esta:

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

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

Por exemplo, imagine que você tenha uma rede de 10 Gbps com um RTT de 30 milissegundos. Para o tamanho da janela, use o valor do tamanho original da janela TCP (65535 bytes). Este valor não chega nem perto de aproveitar a capacidade de largura de banda. O desempenho máximo do TCP possível neste link é o seguinte:

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

Em outras palavras, esses valores resultam em uma taxa de transferência um pouco superior a 17 Mbits por segundo, o que é 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 oferece suporte a janelas de até 1.073.725.440 bytes ou quase 1 GiB. Este recurso é descrito na RFC 7323 como opção de escala de janela TCP .

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

sudo sysctl net.ipv4.tcp_window_scaling

Todos Google Cloud As máquinas virtuais Linux têm esse recurso habilitado por padrão. Um valor de retorno 1 indica que a opção está habilitada. Se o recurso estiver desabilitado, você poderá habilitá-lo usando o seguinte comando:

sudo sysctl -w net.ipv4.tcp_window_scaling=1

Taxa de transferência com um tamanho de janela maior

Você pode usar o exemplo anterior para mostrar a vantagem de ter o dimensionamento de janelas. Como antes, suponha uma rede de 10 Gbps com latência de 30 milissegundos e calcule um novo tamanho de janela usando esta fórmula:

(Velocidade do link * latência) / 8 bits = tamanho da janela

Se você inserir os números de exemplo, obterá isto:

(10 Gbps * 30ms/1000seg) / 8bits/byte = tamanho da janela
(10.000 Mbps * 0,030 segundo) / 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 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 do pacote e o número de outros fluxos que compartilham o link, mas como você pode ver, o tamanho da janela atenua substancialmente os limites impostos pelo tamanho limitado da janela anterior.

Configurando ajustes do Linux para alterar o tamanho da janela TCP

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

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

Os dois primeiros ajustes afetam o tamanho máximo da janela TCP para aplicativos que tentam controlar o tamanho da janela TCP diretamente, limitando a solicitação dos aplicativos a não mais do que esses valores. Os segundos dois ajustes afetam o tamanho da janela TCP para aplicativos que permitem que o ajuste automático do Linux faça o trabalho.

O valor ideal do tamanho da janela depende das circunstâncias específicas, mas um ponto de partida é o maior BDP (produto de atraso de largura de banda) para o caminho ou caminhos pelos quais você espera que o sistema envie dados. Nesse caso, você deseja definir os ajustáveis ​​usando as seguintes etapas:

  1. Certifique-se de ter privilégios de root.
  2. Obtenha as configurações atuais do buffer. Salve essas configurações caso queira reverter essas alterações.

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

    MaxExpectedPathBDP=8388608
    
  4. Defina o tamanho máximo do buffer de recebimento do SO para todos os tipos de conexõ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 conexões:

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

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

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

    • O tamanho mínimo do buffer de recebimento que pode ser alocado para um soquete TCP. Neste exemplo, o valor é 4096 bytes.
    • O tamanho do buffer de recebimento padrão, que também substitui o valor /proc/sys/net/core/rmem_default usado por outros protocolos. No exemplo, o valor é 87380 bytes.
    • O tamanho máximo do buffer de recebimento que pode ser alocado para um soquete TCP. No exemplo, isso é definido com o valor definido anteriormente ( 8388608 bytes).
  7. Defina as configurações do buffer de memória de envio TCP ( tcp_wmem ):

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

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

    • O espaço mínimo de buffer de envio TCP disponível para um único soquete TCP.
    • O espaço de buffer padrão permitido para um único soquete TCP.
    • O espaço máximo do buffer de envio TCP.
  8. Defina os ajustáveis ​​para que as conexões subsequentes usem os valores especificados:

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

Para persistir essas configurações durante as reinicializações, anexe os comandos definidos anteriormente ao arquivo /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'

Testando RTT com um tamanho de janela atualizado

Quando o TCP tem um tamanho de janela grande o suficiente para utilizar o BDP, a imagem muda, conforme mostrado no diagrama a seguir:

O remetente envia uma grande quantidade de dados por vez e gasta muito pouco tempo esperando por uma atualização da janela

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

Você pode testar isso sozinho. Primeiro, certifique-se de ter feito alterações no tamanho da janela TCP em seu computador local e em um computador remoto, definindo os ajustes 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 arquivo sample.txt de 1 GB que contém dados aleatórios. O segundo comando copia esse arquivo da sua máquina local para uma máquina remota.

Observe a saída do comando scp no console, que exibe a largura de banda em Kbps. Você deverá ver uma diferença considerável nos resultados antes e depois das alterações no tamanho da janela TCP.

O que vem a seguir