La configuración TCP por defecto de Linux está pensada para funcionar bien en cualquier red, no para exprimir enlaces rápidos con latencia alta ni para servidores que aceptan miles de conexiones por segundo. En este tutorial ajustarás la pila TCP de Ubuntu 24.04 en tres frentes: el algoritmo de control de congestión (BBR), el tamaño de los buffers y las colas de conexiones entrantes. Mediremos el rendimiento con iperf3 antes y después para comprobar que cada cambio aporta algo.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Los parámetros son iguales en Debian 12 y Rocky Linux 9.
- Un usuario no root con privilegios
sudo. - Una segunda máquina con Linux para las pruebas de rendimiento, idealmente en otra ubicación para medir con latencia real.
- Haber leído la guía de parámetros del kernel con sysctl, o saber qué hace
/etc/sysctl.d/.
Paso 1: Medir el rendimiento actual
Instala iperf3 en ambas máquinas. En Ubuntu, el instalador pregunta si quieres arrancarlo como servicio; responde No, lo lanzarás a mano:
sudo apt update
sudo apt install iperf3
En el servidor que vas a optimizar, abre el puerto de iperf3 en el firewall y arráncalo en modo servidor:
sudo ufw allow 5201/tcp
iperf3 -s
Desde la otra máquina, primero mide la latencia y después lanza una prueba de 30 segundos. Sustituye your_server_ip por la IP del servidor:
ping -c 10 your_server_ip
iperf3 -c your_server_ip -t 30
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-30.00 sec 1.12 GBytes 320 Mbits/sec 1843 sender
[ 5] 0.00-30.04 sec 1.11 GBytes 318 Mbits/sec receiver
Repite con -R para medir en sentido contrario (el servidor envía, que es lo habitual en un servidor web):
iperf3 -c your_server_ip -t 30 -R
Anota el Bitrate y la columna Retr (retransmisiones) de ambas pruebas. Detén el servidor iperf3 con Ctrl+C cuando termines cada tanda.
Consulta también los contadores de desbordamiento de la cola de conexiones, que indican si el servidor rechaza conexiones bajo carga:
nstat -az TcpExtListenOverflows TcpExtListenDrops
#kernel
TcpExtListenOverflows 0 0.0
TcpExtListenDrops 0 0.0
Paso 2: Activar BBR y la cola fq
Ubuntu 24.04 usa por defecto el control de congestión cubic, que reduce la velocidad al detectar pérdida de paquetes. BBR, desarrollado por Google, estima el ancho de banda y la latencia del camino y suele dar más rendimiento en enlaces con latencia alta o algo de pérdida, como las conexiones entre continentes.
Comprueba el algoritmo actual y los disponibles:
sysctl net.ipv4.tcp_congestion_control net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_available_congestion_control = reno cubic
BBR es un módulo del kernel. Cárgalo y configúralo para que se cargue en cada arranque:
sudo modprobe tcp_bbr
echo tcp_bbr | sudo tee /etc/modules-load.d/bbr.conf
Crea un archivo de configuración para los ajustes de red de este tutorial:
sudo nano /etc/sysctl.d/60-tcp-tuning.conf
# Control de congestión BBR con la cola fq, que reparte el envío en el tiempo
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
Aplica la configuración:
sudo sysctl --system
net.core.default_qdisc solo afecta a las colas que se creen a partir de ahora. Para aplicarlo a la interfaz actual sin reiniciar, averigua su nombre y reemplaza su cola:
ip route show default
default via 203.0.113.1 dev eth0 proto static
sudo tc qdisc replace dev eth0 root fq
Verifica ambos cambios. Sustituye eth0 por el nombre de tu interfaz:
sysctl net.ipv4.tcp_congestion_control
tc qdisc show dev eth0
net.ipv4.tcp_congestion_control = bbr
qdisc fq 8001: root refcnt 2 limit 10000p flow_limit 100p buckets 1024 ...
Paso 3: Ampliar los buffers TCP
El rendimiento máximo de una conexión TCP está limitado por su ventana: como mucho puede enviar el tamaño del buffer por cada viaje de ida y vuelta. Para saber cuánto buffer necesitas, calcula el producto ancho de banda por retardo (BDP):
BDP = ancho de banda (bytes/s) x RTT (s)
1 Gbit/s con 100 ms de RTT = 125.000.000 x 0,1 = 12,5 MB
Los máximos por defecto de Ubuntu 24.04 son 6 MB para recepción y 4 MB para envío, insuficientes para ese caso. Consulta los valores actuales:
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem net.core.rmem_max net.core.wmem_max
net.ipv4.tcp_rmem = 4096 131072 6291456
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.rmem_max = 212992
net.core.wmem_max = 212992
Los tres valores de tcp_rmem y tcp_wmem son mínimo, inicial y máximo por conexión. El kernel ajusta cada conexión entre esos límites de forma automática, así que subir el máximo no reserva memoria por adelantado. net.core.rmem_max y wmem_max limitan lo que una aplicación puede pedir explícitamente con setsockopt.
Añade al archivo /etc/sysctl.d/60-tcp-tuning.conf:
# Buffers de hasta 64 MB por conexión (suficiente para 1-10 Gbit/s con latencia alta)
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.ipv4.tcp_rmem = 4096 131072 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# No volver a arranque lento tras un periodo sin tráfico en conexiones persistentes
net.ipv4.tcp_slow_start_after_idle = 0
# Detectar problemas de MTU en rutas que bloquean ICMP
net.ipv4.tcp_mtu_probing = 1
No hace falta activar tcp_window_scaling, tcp_timestamps ni tcp_sack: ya vienen a 1 y el escalado de ventana es imprescindible para usar buffers de más de 64 KB. Compruébalo:
sysctl net.ipv4.tcp_window_scaling net.ipv4.tcp_timestamps net.ipv4.tcp_sack
Paso 4: Ampliar las colas de conexiones entrantes
Cuando llegan muchas conexiones a la vez, se encolan en dos sitios: la cola de conexiones a medio abrir (SYN recibido) y la cola de aceptación de cada socket, donde esperan hasta que la aplicación llama a accept(). Si se llenan, el kernel descarta conexiones y los clientes ven latencia o errores.
Añade al mismo archivo:
# Cola de aceptación máxima por socket (la aplicación también debe pedirla)
net.core.somaxconn = 8192
# Conexiones a medio abrir pendientes de completar el handshake
net.ipv4.tcp_max_syn_backlog = 8192
# Paquetes pendientes de procesar por la CPU en cada interfaz
net.core.netdev_max_backlog = 16384
net.core.somaxconn es solo un tope. Cada aplicación indica su propio backlog al abrir el socket y el kernel usa el menor de los dos. En Nginx, por ejemplo, se configura en la directiva listen:
listen 80 backlog=8192;
Comprueba el backlog real de los sockets en escucha. En sockets LISTEN, la columna Send-Q es el tamaño máximo de la cola y Recv-Q las conexiones que esperan en ese momento:
ss -ltn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 8192 0.0.0.0:80 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:*
Paso 5: Ajustar puertos locales y conexiones cerradas
Estos ajustes solo importan si el servidor abre muchas conexiones salientes, por ejemplo un proxy inverso o un balanceador que conecta con backends.
# Más puertos locales para conexiones salientes (por defecto 32768-60999)
net.ipv4.ip_local_port_range = 10240 65535
# Reutilizar sockets en TIME_WAIT para nuevas conexiones salientes
net.ipv4.tcp_tw_reuse = 1
# Liberar antes las conexiones cerradas por nuestro lado que esperan al otro extremo
net.ipv4.tcp_fin_timeout = 15
Algunas aclaraciones, porque es la parte con más mitos:
tcp_fin_timeoutcontrola el estadoFIN_WAIT_2, noTIME_WAIT. La duración deTIME_WAIT(60 segundos) es fija en el kernel.tcp_tw_reuse = 1solo afecta a conexiones salientes y es seguro.tcp_tw_recycle, que aparece en guías antiguas, rompía conexiones detrás de NAT y se eliminó del kernel en la versión 4.12.- El rango de puertos empieza en 10240 para no chocar con servicios que escuchan en puertos bajos. Si algún servicio escucha en un puerto de ese rango, añádelo a
net.ipv4.ip_local_reserved_ports.
Aplica todo el archivo:
sudo sysctl --system
Paso 6: Verificar la mejora
Arranca de nuevo iperf3 -s en el servidor y repite las mismas pruebas desde la otra máquina:
iperf3 -c your_server_ip -t 30
iperf3 -c your_server_ip -t 30 -R
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-30.00 sec 3.21 GBytes 919 Mbits/sec 212 sender
[ 5] 0.00-30.04 sec 3.20 GBytes 915 Mbits/sec receiver
La mejora depende mucho de la latencia: en una red local casi no notarás diferencia, mientras que entre continentes BBR y los buffers mayores pueden multiplicar el rendimiento.
Mientras corre la prueba -R, comprueba en el servidor que la conexión usa BBR y que su ventana ha crecido:
ss -tin dst your_client_ip
ESTAB 0 3145728 203.0.113.10:5201 198.51.100.20:41822
bbr wscale:10,10 rto:304 rtt:101.2/0.8 mss:1448 cwnd:1024 ...
Con tráfico real, vigila los desbordamientos de cola durante unos días. Si TcpExtListenOverflows sigue creciendo, la aplicación no acepta conexiones lo bastante rápido o su backlog es menor que somaxconn:
nstat -az TcpExtListenOverflows TcpExtListenDrops
Cuando termines las pruebas, cierra el puerto de iperf3:
sudo ufw delete allow 5201/tcp
Solución de problemas
sysctl: setting key "net.ipv4.tcp_congestion_control": No such file or directory. El módulo tcp_bbr no está cargado. Ejecuta sudo modprobe tcp_bbr y comprueba que existe /etc/modules-load.d/bbr.conf.
iperf3: error - unable to connect to server. El puerto 5201 está bloqueado en el firewall del servidor o en un firewall intermedio, o iperf3 -s no está en marcha.
El rendimiento no mejora. Si el RTT es bajo (menos de 5 ms), los buffers por defecto ya bastan y el límite está en la tarjeta de red, la CPU o el disco. Comprueba el uso de CPU con top durante la prueba.
Conclusión
Has cambiado el control de congestión a BBR, ampliado los buffers TCP según el producto ancho de banda por retardo, dimensionado las colas de conexiones y medido el resultado con iperf3. Como siguientes pasos, ajusta el backlog de tu servidor web o balanceador para que aproveche el nuevo somaxconn, sube el límite de archivos abiertos por proceso si manejas decenas de miles de conexiones, y monitoriza las retransmisiones con nstat en producción.
