A rede global em Google Cloud oferece alta confiabilidade e baixa latência ao conectar aplicativos em regiões e zonas sem sair da rede do Google. No entanto, as configurações padrão do TCP/IP do Linux geralmente são ajustadas para ambientes locais e podem causar gargalos de desempenho na nuvem.
Para ter o melhor desempenho no Google Cloud, use as configurações TCP/IP neste documento, que são otimizadas especificamente para o ambiente de nuvem.
As configurações mencionadas neste documento foram testadas para uso no ambienteGoogle Cloud . As configurações são principalmente para comunicações internas de instâncias e não se aplicam necessariamente à comunicação entre instâncias do Compute Engine e endereços externos.
Como entender o limite de capacidade de processamento
O TCP usa um mecanismo de "janelamento" para gerenciar o fluxo de dados entre um remetente e um receptor. A capacidade máxima de processamento possível é regida pela seguinte relação:
Throughput <= window size / round-trip time (RTT) latency
No design original do TCP, o tamanho máximo da janela é limitado a 65.535 bytes (64 KiB - 1), o que geralmente deixa as redes modernas de alta velocidade subutilizadas, já que o remetente espera atualizações da janela.
Script de shell para otimizar o desempenho do TCP
As seguintes configurações de TCP são recomendadas para melhorar o desempenho:
- Reduzir o MinRTO: recupere-se mais rápido da perda de pacotes reduzindo os atrasos de retransmissão.
- Ativar o enfileiramento justo: minimize o congestionamento e as quedas devido a picos de aplicativos.
- Desativar o início lento após o período de inatividade: reinicie na última taxa de transferência boa conhecida após um período de inatividade da conexão.
- Desativar o trem de ACK do TCP Cubic HyStart: ignora sinais de congestionamento falso-positivo ao aumentar a taxa de transferência de dados.
- Aumentar os orçamentos de memória de soquete: aumente a quantidade máxima permitida de dados em trânsito por conexão.
- Ative o GRO de hardware: aumente a eficiência do processamento de recebimento TCP/IP para grandes fluxos combinando dados em menos pacotes, mas maiores.
- Aumentar a MTU para 4.082 bytes: aumenta a eficiência da transferência para fluxos de grande capacidade.
É possível ativar essas configurações sugeridas com o seguinte script de shell. Antes de executar o script, substitua eth0 pela interface de rede principal da instância de computação.
# Set DEV to your primary network interface
DEV=eth0
# 1. Reduce MinRTO
sysctl -w net.ipv4.tcp_rto_min_us=5000
# 2. Enable Fair Queueing
tc qdisc replace dev $DEV root fq
# 3. Disable slow start after idle
sysctl -w net.ipv4.tcp_slow_start_after_idle=0
# 4. Disable TCP Cubic HyStart ACK train
echo 2 > /sys/module/tcp_cubic/parameters/hystart_detect
# 5. Increase socket memory budgets
echo 4194304 > /proc/sys/net/core/rmem_max
echo 4194304 > /proc/sys/net/core/wmem_max
echo 4194304 > /proc/sys/net/ipv4/tcp_notsent_lowat
echo "4096 262144 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 262144 33554432" > /proc/sys/net/ipv4/tcp_wmem
# 6. Enable hardware GRO
ethtool -K $DEV rx-gro-hw on
As seções a seguir descrevem cada uma das configurações sugeridas em mais detalhes.
Reduzir o MinRTO
Recupere-se mais rápido da perda de pacotes reduzindo os atrasos de retransmissão.
O tempo limite de retransmissão (RTO, na sigla em inglês) do TCP controla por quanto tempo um remetente TCP aguarda um sinal de
ACK antes de retransmitir. O Linux inicializa o RTO em um segundo (de acordo com a seção 2.1 da RFC 6298) e o ajusta ao longo do tempo para o tempo de retorno (RTT) mais uma margem de segurança.
O RTO mínimo (MinRTO) implementa um limite inferior nesse ajuste. Se a estimativa de RTO for muito baixa, ela poderá introduzir retransmissões espúrias, em que o remetente retransmite pacotes enquanto a resposta ainda está em processo.
O MinRTO padrão é de 200 ms, o que é desnecessariamente conservador para redes de nuvem modernas. Um valor de 5 ms foi amplamente testado em Google Cloud e é um padrão seguro para conexões entre servidores Linux modernos em Google Cloud.
Outro fator são os ACKs atrasados, em que o peer atrasa as respostas ACK. Esse
atraso permite o envio em lote de ACKs em vários pacotes de dados ou a combinação de um ACK
com um pacote de dados na direção oposta. Os timers de ACK atrasado são baseados no RTT, assim como o timer de RTO.
Diminuir o MinRTO acelera o reparo de perdas em conexões de baixo RTT, como conexões em uma zona ou região. Esse ajuste não afeta o comportamento de conexões com um RTT alto, já que não muda o RTT estimado delas.
Como configurar o MinRTO
É possível configurar o MinRTO usando um destes métodos:
Como usar
sysctl(Linux 6.11 e versões mais recentes):É possível configurar o MinRTO padrão usando um comando
sysctl:sysctl -w net.ipv4.tcp_rto_min_us=5000Como usar
ip route(controle por rota ou versões do Linux anteriores a 6.11):Como alternativa, para versões mais antigas do Linux ou controle por rota, o MinRTO pode ser definido por rota:
ip route change default rto_min 5ms
A abordagem por rota é preferível em ambientes em que as conexões podem sair Google Cloud ou se comunicar com pilhas TCP/IP que não são do Linux. Esses sistemas podem ter timers de ACK atrasado diferentes. Para uma implantação ampla na Internet pública, é recomendável manter a configuração padrão conservadora de minRTO e aplicar a configuração de 5 ms apenas para rotas na nuvem privada virtual Google Cloud .
Ativar o enfileiramento justo
Minimizar o congestionamento e as perdas de pacotes causadas por picos de aplicativos.
Ao contrário das filas PEPS (primeiro a entrar, primeiro a sair) padrão, o enfileiramento justo (FQ) distribui a largura de banda de maneira justa entre diferentes fluxos. Ele também controla o tráfego ao permitir que cada conexão TCP calcule a taxa e o tempo de entrega ideais para cada pacote. Se a FQ estiver presente, a pilha TCP vai depender dela para manter os pacotes até o momento ideal de entrega. Essa limitação reduz os picos em um fluxo, o que minimiza as perdas e retransmissões de pacotes.
Para definir o modelador de tráfego FQ como o modelador de tráfego do dispositivo de rede, use o seguinte comando tc (controle de tráfego):
tc qdisc replace dev $DEV root fq
Em instâncias grandes com alta largura de banda de saída, o dispositivo de rede pode ter várias filas de transmissão. Para essas instâncias, talvez seja preferível fragmentar o ajuste da programação em filas de transmissão instalando o controlador de tráfego de várias filas (MQ). É um multiplexador que anexa um modelador de tráfego independente a cada fila de transmissão. Os modeladores de tráfego por fila reduzem a disputa em bloqueios e linhas de cache em todas as CPUs.
Desativar o início lento após ficar ocioso
Manter altas taxas de transferência após um período de inatividade da conexão.
Para evitar congestionamento, as conexões TCP começam enviando dados a uma taxa baixa e aumentam exponencialmente a taxa até que a perda de pacotes seja detectada. Essa fase inicial é conhecida como início lento.
Por padrão, o TCP volta para as configurações conservadoras de "Início lento" após um período de inatividade. Um período ocioso pode ser tão curto quanto um tempo limite de retransmissão (RTO), conforme definido na RFC 2581. Desativar esse recurso permite que a conexão seja retomada imediatamente na última taxa válida conhecida.
Sempre que possível, os aplicativos devem usar conexões de longa duração em vez de estabelecer conexões repetidas com o mesmo peer. Isso evita o custo do estabelecimento da conexão e mantém as informações de congestionamento. No entanto, mesmo com conexões de longa duração, após um período ocioso, o TCP esquece as informações de congestionamento por padrão e volta à configuração conservadora inicial e à fase de "início lento".
Para desativar o recurso de início lento após inatividade, use o seguinte comando:
sysctl -w net.ipv4.tcp_slow_start_after_idle=0
Desativar o trem de ACK do TCP Cubic HyStart
Escalone rapidamente para altas taxas de transferência ignorando sinais de congestionamento de falso positivo.
A taxa de crescimento exponencial da fase de início lento pode ser agressiva, possivelmente ultrapassando a taxa de meta ideal. O Hybrid Start (HyStart) é um mecanismo adicional projetado para sair da fase de "início lento" mais cedo usando dois indicadores principais de congestionamento:
- Atraso no tempo de retorno (RTT): mede o atraso de propagação dos pacotes na rede. Durante períodos de congestionamento de rede, as filas de pacotes se acumulam em links de gargalo. Isso faz com que o RTT aumente, o que pode indicar a presença de congestionamento.
- Espaçamento de ACK: depende de indicadores de que os pacotes estão sendo atrasados em um gargalo, mas se concentra nos ACKs de resposta. Esse mecanismo pressupõe que, sem congestionamento, os ACKs vão chegar com o mesmo espaçamento dos pacotes de dados originais. Esse padrão é chamado de trem de ACK. Se os ACKs forem atrasados além desse padrão esperado, isso indica que pode haver congestionamento.
Para otimizar a performance, desative a detecção de trens de pacotes ACK, mas mantenha o mecanismo de atraso de RTT ativado.
echo 2 > /sys/module/tcp_cubic/parameters/hystart_detect
Aumentar os orçamentos de memória de soquete
Aumente a capacidade de processamento máxima em links de RTT alto permitindo mais dados em trânsito.
A quantidade de dados em trânsito é uma função da largura de banda e do atraso de propagação, conhecido como produto do atraso e da largura de banda (BDP, na sigla em inglês). O BDP é calculado como a largura de banda multiplicada pelo tempo de retorno (RTT), resultando em um valor que especifica o número ideal de bits a serem enviados para preencher o canal:
BDP (bits) = bandwidth (bits/second) * RTT (seconds)
Todos os dados em voo precisam permanecer em buffer no remetente caso seja necessário transmiti-los novamente. Os limites de memória de soquete TCP podem limitar diretamente a capacidade de processamento alcançável, determinando a quantidade de dados em trânsito que pode ser armazenada em buffer.
No Linux, os limites de memória de soquete TCP são configurados com as seguintes
configurações sysctl(8):
net.core.rmem_maxnet.core.wmem_maxnet.ipv4.tcp_rmemnet.ipv4.tcp_wmem
Esses limites de memória de soquete TCP existem para evitar o uso de toda a memória do sistema e causar condições de falta de memória (OOM), especialmente em cargas de trabalho com muitas conexões. Aumentar esses limites pode aumentar a capacidade de processamento, especialmente em caminhos de RTT alto. A menos que a contagem de conexões seja de milhões, há pouco risco em aumentar esses limites.
Essas variáveis definem limites máximos para o tamanho do buffer de soquete, não a alocação direta de memória. Aumentar esses valores não afeta a alocação de memória real para conexões com RTT baixo, como as de uma zona Google Cloud .
Os dois primeiros parâmetros ajustáveis afetam o tamanho máximo da janela TCP para
aplicativos que definem o tamanho da janela TCP diretamente, o que relativamente poucos
aplicativos fazem. Esses limites restringem o que um aplicativo pode pedir explicitamente
com as opções de soquete SO_RCVBUF e SO_SNDBUF.
Para versões do kernel do Linux 6.18 e mais recentes, net.core.rmem_max e net.core.wmem_max têm como padrão 4 MB. Com base em anos de experiência, essas configurações são consideradas seguras. Para versões anteriores do Linux, recomendamos aumentar esses limites para 4 MB em plataformas modernas:
echo 4194304 > /proc/sys/net/core/rmem_max
echo 4194304 > /proc/sys/net/core/wmem_max
O segundo conjunto de limites, net.ipv4.tcp_rmem e net.ipv4.tcp_wmem, gerencia os limites de ajuste automático do buffer de envio e recebimento do TCP.
Cada uma dessas configurações usa três valores: tamanho mínimo, padrão inicial e máximo da memória de soquete. Os valores máximos padrão costumam ser mais conservadores do que o necessário em plataformas modernas. Por exemplo:
tcp_rmem: 4096, 131072, 6291456tcp_wmem: 4096, 16384, 4194304
A pilha TCP dimensiona automaticamente os buffers de envio e recebimento de TCP com base em estimativas de RTT e janela de congestionamento. Um tamanho máximo de buffer de gravação de 4194304, ou 4 MB, é pequeno para conexões de RTT alto. Com um RTT de 100 ms, essa configuração limita a capacidade de processamento a 40 MB/s no melhor caso. Em vez de tentar calcular quais valores usar, uma abordagem mais simples é usar padrões seguros para servidores modernos com muitos GB de RAM.
Como precaução extra, recomendamos limitar a quantidade de dados que podem ser
enfileirados no soquete, mas ainda não enviados. Embora o objetivo de aumentar o wmem máximo seja permitir mais dados em trânsito, um processo pode gravar no soquete mais rápido do que o TCP pode enviar, causando o acúmulo de uma fila de dados não enviados no host e desperdiçando memória. Para evitar isso, limite a quantidade de dados ainda não enviados definindo tcp_notsent_lowat e aumente o limite geral de wmem para permitir buffers maiores em trânsito.
A menos que um servidor tenha milhões de conexões, as configurações a seguir serão seguras. Mas, se você tiver condições de falta de memória com muitas conexões, use um tamanho máximo de buffer menor.
echo 4194304 > /proc/sys/net/ipv4/tcp_notsent_lowat
echo "4096 262144 16777216" > /proc/sys/net/ipv4/tcp_rmem
echo "4096 262144 33554432" > /proc/sys/net/ipv4/tcp_wmem
Ativar o GRO de hardware
Aumenta a eficiência do processamento de recebimento de TCP/IP para fluxos grandes. Reduzir a sobrecarga da CPU agrupando os pacotes recebidos
Para a maioria das operações TCP/IP, o custo do ciclo de CPU é dimensionado com a taxa de pacotes, não com a taxa de bytes. Para reduzir essa sobrecarga na transmissão, os sistemas operacionais modernos enviam dados TCP pelo caminho de transmissão em pacotes grandes que contêm vários segmentos TCP. Eles podem variar até 64 KB ou até mesmo centenas de kilobytes com o Linux BIG-TCP.
Esses pacotes grandes excedem o tamanho máximo de pacote na rede, a MTU. Essa otimização do sistema operacional depende do suporte do dispositivo de rede para dividir esses pacotes e enviá-los como um trem de pacotes menores, cada um contendo um único segmento TCP. Esse suporte, a descarga de segmentação TCP (TSO, na sigla em inglês), está amplamente disponível e ativado por padrão.
Ao receber, os dispositivos GVNIC em plataformas de terceira geração e mais recentes podem realizar o inverso: armazenar brevemente segmentos em buffer no dispositivo para ver se segmentos consecutivos chegam e, em caso afirmativo, combiná-los e encaminhá-los como pacotes de vários segmentos para o host. Esse recurso é conhecido como Receive Segment Coalescing (RSC) no Windows e Large Receive Offload (LRO) ou Hardware Generic Receive Offload (HW-GRO) no Linux. O HW-GRO é um refinamento mais rigoroso do LRO.
O HW-GRO pode ser ativado por padrão. Isso acontece quando disponível.
Enquanto isso, em plataformas com dispositivos GVNIC que oferecem suporte ao recurso, ative a GRO de hardware usando o ethtool. Dependendo da versão do kernel e do driver, o recurso é anunciado como LRO ou HW-GRO. A implementação é a mesma, seja qual for o nome.
ethtool -K $DEV large-receive-offload on
ethtool -K $DEV rx-gro-hw on
Aumentar o tamanho da MTU para 4.082 bytes
Aumentar a eficiência da transferência de dados para fluxos de alta capacidade.
Aumentar o tamanho do pacote, semelhante às otimizações de TSO e HW-GRO, aumenta a eficiência da transferência porque a maior parte do trabalho de processamento é feita por pacote, não por byte.
As redes VPCGoogle Cloud podem oferecer suporte a pacotes de até 8.898 bytes, o que é significativamente maior do que a MTU padrão de 1.460 bytes. Usar um tamanho de pacote de rede maior reduz os ciclos de CPU gastos por byte de capacidade de processamento (goodput).
Considerações sobre o tamanho ideal do pacote
Embora pacotes maiores sejam geralmente melhores, a MTU máxima possível nem sempre é a escolha ideal. O ganho de eficiência ao enviar menos pacotes precisa ser equilibrado com os seguintes custos:
- Uso de memória: buffers maiores exigem mais memória atribuída ao dispositivo de rede para recebimento de pacotes. Se você tiver muitas filas, uma quantidade considerável de memória poderá ficar sem uso.
- Processamento de pacotes pequenos: buffers maiores processam pacotes pequenos, como confirmações (ACKs) puras, com menos eficiência.
- Custos de alocação de CPU: os custos de datapath são significativamente afetados pela alocação e liberação de memória. Alinhar o tamanho do pacote a um múltiplo de páginas de memória ajuda a otimizar esse custo de CPU.
- Interação com TSO: o tamanho do pacote afeta sutilmente a descarga de segmentação TCP (TSO). Para criar o maior pacote TSO possível, talvez seja necessário escolher um tamanho máximo do segmento (MSS) menor. Por exemplo, considerando o maior pacote IP possível de 64 KB, incluindo cabeçalhos, um MSS de 4 KB resulta em um payload maior (60 KB) do que um MSS de 8 KB (56 KB).
Para a maioria das cargas de trabalho, a diferença de eficiência entre MTUs de 4 KB, 8 KB ou 9 KB é pequena. No entanto, qualquer um deles é uma melhoria significativa em relação aos pacotes padrão de 1.460 bytes.
Recomendação para pacotes do tamanho de uma página
Como uma opção robusta e geralmente eficiente, recomendamos definir o tamanho da MTU da sua rede VPC como 4.082 bytes. Esse tamanho é recomendado porque permite que todo o pacote Ethernet caiba em uma página de memória de 4.096 bytes, o que otimiza a alocação de páginas de memória. Essa recomendação é para o MTU da camada 3, que inclui o cabeçalho IP, mas exclui a camada de link Ethernet de 14 bytes.
Configuração da MTU de IP
É possível configurar a MTU para cada rede VPC diretamente no console do Google Cloud .
Para a maioria das distribuições do Linux em Google Cloud, não é necessário fazer configuração manual na instância de computação. A instância aprende automaticamente a MTU da rede usando DHCP durante a inicialização (usando a opção 26). Em seguida, a instância define a MTU do dispositivo de rede para corresponder. Recomendamos usar essa configuração automática.
Se a configuração manual for necessária, a MTU do dispositivo de rede poderá ser definida como um valor menor que a MTU da rede VPC usando o seguinte comando:
ip link set dev $DEV mtu 4082
Definir tamanhos de MTU diferentes para rotas específicas
Se a instância de computação se comunicar externamente fora da VPC, em que a MTU do caminho pode ser menor, definir a MTU em rotas específicas é a opção preferida. Nesse cenário, defina a MTU padrão como 1.460 bytes, que é um valor conservador, e aplique a MTU mais alta, por exemplo, 4.082 bytes, somente para rotas intra-VPC:
#Set intra-VPC route MTU:
ip -4 route change $SUBNET/$MASK dev $DEV mtu 4082
#Set default route MTU:
ip -4 route change default dev $DEV mtu 1460
Configurar o tamanho máximo do segmento (MSS) do TCP
O tamanho máximo do segmento (MSS) do TCP determina o tamanho do payload do pacote para uma conexão TCP. Como os pacotes TCP/IP não podem exceder o tamanho da MTU para evitar fragmentação ou perda de pacotes, o MSS precisa ser dimensionado de acordo.
Em geral, não é necessário configurar o MSS do TCP manualmente, porque o sistema operacional o deriva automaticamente da MTU do caminho.
O MSS abrange o payload e as opções de TCP, mas exclui o cabeçalho IPv4 de 20 bytes e o cabeçalho TCP de 20 bytes. Portanto, em uma rede IPv4, o MSS é normalmente 40 bytes menor que a MTU.
Se você preferir um MSS menor para tráfego específico, configure-o por rota. Por exemplo, se a MTU da rede VPC e do dispositivo usar o máximo (8.896 bytes) para tráfego geral, mas você quiser usar uma MTU de 4 KB para tráfego TCP, use o seguinte comando:
ip -4 route change default dev $DEV advmss 4042
Modo de divisão do cabeçalho
As plataformas de terceira geração oferecem um recurso opcional de divisão do cabeçalho de recebimento, que fica desativado por padrão.
A divisão de cabeçalho separa cabeçalhos e dados de pacotes em buffers distintos. Isso permite preencher uma página inteira de memória com 4.096 bytes de dados. Essa
separação permite otimizações importantes, como substituir operações caras de
cópia do kernel para o espaço do usuário por operações mais baratas de mapeamento de páginas de memória (por exemplo, usando o Linux TCP_ZEROCOPY_RECEIVE).
Quando o recurso de divisão de cabeçalho de recebimento está ativado, o cálculo da MTU muda. A MTU ideal é aquela em que todos os cabeçalhos são mapeados para o buffer de cabeçalho e o buffer de payload preenche uma página inteira de dados. Com a divisão de cabeçalho ativada:
- Um buffer de cabeçalho contém:
- Ethernet (14 bytes)
- IPv4 (20 bytes)
- Cabeçalhos TCP (20 bytes)
- Opções comuns de TCP (12 bytes para configuração padrão com carimbos de data/hora TCP)
- O buffer de dados contém 4.096 bytes de dados de payload.
Isso resulta em um tamanho total de frame de 4.162 bytes e, portanto, uma MTU de 4.148 bytes.
A seguir
- Leia a postagem do blog sobre 5 etapas para melhorar o desempenho da rede do Google Cloud .
- Saiba mais sobre os produtos de rede global.
- Saiba mais sobre os níveis de rede no Google Cloud.
- Saiba como comparar o desempenho da rede.