Tuning de Rede no Linux: Otimização de Throughput com sysctl e ethtool

Introdução à Otimização de Performance de Rede no Linux

Em ambientes de alta performance, como servidores web com tráfego intenso, bancos de dados distribuídos ou sistemas de armazenamento em rede, a performance da pilha de rede é um fator crítico. Uma configuração de rede sub-otimizada no kernel linux pode se tornar um gargalo significativo, limitando o throughput, aumentando a latência e subutilizando hardware de rede caro, como interfaces de 10GbE, 40GbE ou superiores. Felizmente, o kernel Linux oferece um conjunto granular de parâmetros ajustáveis que permitem aos administradores de sistemas otimizar o comportamento da pilha de rede para cargas de trabalho específicas.

Este artigo técnico explora duas das ferramentas mais poderosas para essa tarefa: sysctl, para ajustar os parâmetros do kernel em tempo real, e ethtool, para configurar os parâmetros da placa de rede (NIC) em nível de hardware e driver. Abordaremos os conceitos fundamentais por trás dos buffers de rede, controle de congestionamento TCP, offloading de hardware e balanceamento de interrupções, fornecendo uma base sólida para maximizar o desempenho de rede em seus sistemas Linux.

Ajustando a Pilha de Rede do Kernel com sysctl

O utilitário sysctl é a interface primária para inspecionar e modificar os parâmetros do kernel em tempo de execução. Esses parâmetros, expostos através do sistema de arquivos virtual /proc/sys/, controlam diversos subsistemas, incluindo a pilha de rede (localizada em /proc/sys/net/). As alterações podem ser feitas temporariamente com o comando sysctl -w ou de forma permanente, editando o arquivo /etc/sysctl.conf (ou arquivos em /etc/sysctl.d/).

Otimização de Buffers de Memória de Rede

Um dos ajustes mais impactantes é o dimensionamento dos buffers de memória de rede. Buffers muito pequenos podem causar perdas de pacotes (packet drops) sob rajadas de tráfego, enquanto buffers excessivamente grandes podem consumir memória desnecessária e introduzir bufferbloat, um fenômeno que aumenta a latência.

  • Buffers de Socket Genéricos (Core): Estes são os buffers padrão para todos os protocolos.
    • net.core.rmem_max: Define o tamanho máximo do buffer de recebimento (receive) em bytes para qualquer socket.
    • net.core.wmem_max: Define o tamanho máximo do buffer de envio (write) em bytes para qualquer socket.
    • net.core.netdev_max_backlog: Controla o número máximo de pacotes que podem ser enfileirados na placa de rede antes de serem processados pelo kernel. Um valor baixo (padrão: 1000) pode levar a drops se a CPU não conseguir processar as interrupções de rede com rapidez suficiente. Em redes de 10GbE ou mais, aumentar este valor para 30000 ou mais é uma prática comum.
  • Buffers Específicos do TCP: O TCP possui seu próprio conjunto de parâmetros de buffer, que permitem uma auto-otimização dentro de limites definidos.
    • net.ipv4.tcp_rmem = 4096 87380 6291456: Define os valores mínimo, padrão e máximo para o buffer de recebimento TCP. O kernel ajusta o buffer dinamicamente entre o mínimo e o máximo.
    • net.ipv4.tcp_wmem = 4096 16384 4194304: Define os valores mínimo, padrão e máximo para o buffer de envio TCP.

Para redes de alta velocidade e baixa latência (LANs de 10GbE+), aumentar os valores máximos desses buffers é crucial. Valores como 16MB (16777216 bytes) para net.core.rmem_max e net.core.wmem_max são um bom ponto de partida.

Ajustes no Comportamento do Protocolo TCP

Além dos buffers, o comportamento do TCP pode ser ajustado para otimizar a transferência de dados e o gerenciamento de conexões.

  • Algoritmo de Controle de Congestionamento: O algoritmo de controle de congestionamento determina como o TCP reage à perda de pacotes e à variação de latência. O padrão moderno é o cubic, mas para redes com alta latência e grande largura de banda (Long Fat Networks – LFNs), o algoritmo bbr (Bottleneck Bandwidth and Round-trip propagation time) desenvolvido pelo Google pode oferecer um throughput significativamente maior. Para verificar os algoritmos disponíveis: sysctl net.ipv4.tcp_available_congestion_control. Para alterar: sysctl -w net.ipv4.tcp_congestion_control=bbr.
  • Gerenciamento de Conexões: Em servidores que lidam com um número massivo de conexões curtas, como servidores web, os seguintes parâmetros são importantes:
    • net.ipv4.tcp_max_syn_backlog: Aumenta o tamanho da fila para conexões TCP em estado SYN_RECV. Isso ajuda a mitigar ataques de SYN flood e a lidar com picos legítimos de novas conexões. Valores como 4096 ou 8192 são comuns.
    • net.ipv4.tcp_tw_reuse: Permite a reutilização de sockets no estado TIME_WAIT para novas conexões. É útil para reduzir o esgotamento de portas em servidores que originam um grande volume de conexões de saída. Atenção: Deve ser usado com cautela, principalmente se o servidor estiver atrás de um NAT.
    • net.core.somaxconn: Define o comprimento máximo da fila de sockets pendentes de um `accept()`. Um valor padrão baixo (e.g., 128) pode limitar o número de novas conexões que um serviço como Nginx ou Apache pode aceitar. Aumentar para 1024 ou 4096 é recomendado.

Configurações de Baixo Nível com ethtool

Enquanto sysctl opera nas camadas de transporte e rede, ethtool permite interagir diretamente com o driver da interface de rede e com o hardware da NIC, operando nas camadas de enlace e física. Essas configurações são cruciais para garantir que o hardware não seja o gargalo.

Ajuste de Ring Buffers

Os Ring Buffers (ou descritores de anel) são áreas de memória compartilhadas entre a NIC e o kernel para a troca de pacotes. Existem buffers de recepção (RX) e de transmissão (TX). Se o kernel não conseguir processar os pacotes do buffer RX rápido o suficiente, a NIC começará a descartar os pacotes que chegam. Aumentar o tamanho desses buffers pode fornecer uma margem extra durante picos de tráfego.

  • Verificar os valores atuais e máximos: ethtool -g eth0
  • Ajustar os valores: ethtool -G eth0 rx 4096 tx 4096 (Use os valores máximos reportados pelo comando anterior como referência).

O trade-off aqui é um leve aumento na latência, pois pacotes podem permanecer no buffer por mais tempo. No entanto, para cargas de trabalho focadas em throughput, o benefício de evitar perdas de pacotes geralmente supera essa desvantagem.

Funcionalidades de Offloading de Hardware

NICs modernas possuem a capacidade de realizar tarefas que normalmente seriam executadas pela CPU, um processo chamado de offloading. Isso libera ciclos de CPU para as aplicações.

  • Verificar as funcionalidades ativas: ethtool -k eth0
  • Tipos comuns de offload:
    • rx-checksumming / tx-checksumming: A NIC valida/calcula os checksums de pacotes TCP/UDP.
    • tcp-segmentation-offload (TSO): Permite que o kernel envie um grande buffer de dados para a NIC, que então o segmenta em pacotes TCP menores (MTU-sized). Isso reduz drasticamente a carga na CPU para grandes transferências.
    • generic-receive-offload (GRO): O oposto do TSO. A NIC agrupa pacotes pequenos recebidos em um buffer maior antes de passá-lo ao kernel, reduzindo o número de interrupções e o overhead de processamento.

Geralmente, é benéfico manter a maioria dos offloads ativados. Para desativar uma funcionalidade específica (por exemplo, para depuração): ethtool -K eth0 gro off.

Interrupt Coalescing

A cada pacote (ou grupo de pacotes) recebido, a NIC gera uma interrupção (IRQ) para notificar a CPU. Em redes de alta velocidade, isso pode levar a uma “tempestade de interrupções”, consumindo uma quantidade enorme de recursos da CPU. O Interrupt Coalescing agrupa múltiplas interrupções em uma só, seja com base no tempo ou no número de pacotes.

  • Verificar as configurações atuais: ethtool -c eth0
  • Ajustar os parâmetros: ethtool -C eth0 rx-usecs 125 rx-frames 256

Ajustar esses valores é um equilíbrio delicado: valores mais altos (mais coalescing) melhoram o throughput e reduzem o uso da CPU, mas aumentam a latência. Para servidores de arquivos ou de backup, valores agressivos são aceitáveis. Para aplicações sensíveis à latência, como bancos de dados ou negociação de alta frequência, valores mais baixos são preferíveis.

Balanceamento de Carga de Interrupções (IRQ Affinity)

Por padrão, em sistemas multi-core, as interrupções de uma única fila de rede (RX/TX queue) de uma NIC são frequentemente direcionadas a um único núcleo de CPU. Em uma rede de 10GbE ou superior, esse único núcleo pode se tornar o gargalo, atingindo 100% de utilização enquanto os outros permanecem ociosos. Para resolver isso, as interrupções podem ser distribuídas entre múltiplos núcleos.

NICs modernas suportam múltiplas filas (Multi-Queue). Cada fila pode ter sua interrupção (IRQ) associada a um núcleo de CPU diferente. Este processo é conhecido como configuração de afinidade de IRQ (IRQ Affinity).

  1. Identificar os IRQs da sua NIC: cat /proc/interrupts | grep eth0
  2. Definir a afinidade: A afinidade é controlada escrevendo uma máscara de bits no arquivo /proc/irq/<IRQ_NUMBER>/smp_affinity. Por exemplo, para fixar o IRQ 125 no núcleo 2 (CPU1), a máscara seria ‘2’ (0010 em binário): echo 2 > /proc/irq/125/smp_affinity. Para fixar no núcleo 3 (CPU2), a máscara seria ‘4’ (0100).

Automatizar esse processo com scripts é uma prática comum para garantir que a afinidade seja aplicada corretamente após cada reinicialização. O serviço irqbalance tenta fazer isso dinamicamente, mas para performance máxima e previsível, muitos administradores o desabilitam e definem a afinidade manualmente.

Exemplo Prático: Configuração para Servidor 10GbE

A seguir, um exemplo de conjunto de configurações para um servidor web de alto tráfego com uma interface de 10GbE.

Configurações em /etc/sysctl.conf:


# Aumenta o tamanho máximo dos buffers de socket
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# Aumenta os buffers de memória TCP
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Aumenta a fila de pacotes de entrada
net.core.netdev_max_backlog = 30000

# Aumenta a fila de conexões pendentes
net.core.somaxconn = 4096

# Aumenta o backlog de conexões TCP SYN
net.ipv4.tcp_max_syn_backlog = 8192

# Reduz o tempo de espera no estado FIN-WAIT-2
net.ipv4.tcp_fin_timeout = 30

# Habilita reutilização de sockets TIME-WAIT
net.ipv4.tcp_tw_reuse = 1

# Usa o algoritmo BBR para controle de congestionamento
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

Comandos ethtool (a serem executados na inicialização):


# Supondo que a interface seja enp1s0
IFACE=enp1s0

# Aumenta os ring buffers para o máximo suportado (verificar com ethtool -g)
ethtool -G $IFACE rx 4096 tx 4096

# Configura o interrupt coalescing para focar em throughput
ethtool -C $IFACE adaptive-rx off adaptive-tx off rx-usecs 125 tx-usecs 125

Monitoramento e Validação

Nenhuma otimização deve ser feita às cegas. É fundamental estabelecer uma linha de base (baseline) de performance antes de qualquer alteração e medir o impacto de cada ajuste. Ferramentas essenciais para essa tarefa incluem:

  • iperf3: Para testes de throughput de rede bruto entre dois pontos.
  • netstat -s e ss -s: Fornecem estatísticas detalhadas por protocolo, úteis para identificar problemas como retransmissões TCP ou perdas de pacotes.
  • ethtool -S <interface>: Exibe estatísticas específicas do driver da NIC, como `rx_dropped` ou `rx_crc_errors`, que indicam problemas em nível de hardware ou driver.
  • htop / top: Para monitorar o uso da CPU por núcleo e verificar se as interrupções (`si` ou `softirq`) estão bem distribuídas ou sobrecarregando um único núcleo.

O processo de tuning é iterativo. Aplique uma alteração de cada vez, meça seu impacto sob uma carga de trabalho realista e decida se a mantém. O que funciona para um servidor de streaming de vídeo pode não ser o ideal para um servidor de banco de dados transacional. A compreensão dos princípios subjacentes é a chave para tomar decisões informadas e extrair o máximo de performance da sua infraestrutura de rede Linux.