🎨 Sysprovider Code
Sysprovider LogoWiki
🇪🇸Hosting español para ecommerce

Optimización de kernel TCP/IP para servidores web de alta concurrencia

Actualizado el 27 de mayo de 2026

Introducción: El cuello de botella invisible

En entornos de servidores web con alta concurrencia, el límite del rendimiento rara vez reside en la CPU o la RAM, sino en la pila de red del sistema operativo. Cada conexión TCP, cada paquete SYN, ACK o FIN, cada re-transmisión, consume ciclos de CPU y recursos de memoria en el kernel. La configuración por defecto del kernel Linux está diseñada para ser conservadora, priorizando la estabilidad y el bajo consumo de recursos en sistemas de escritorio o servidores con baja carga. Para un servidor que maneja decenas de miles de conexiones simultáneas (como un balanceador de carga, un servidor Nginx o un servidor de aplicaciones Node.js), esta configuración es un lastre.

Este artículo técnico desglosa las optimizaciones críticas del stack TCP/IP en Linux para servidores web de alta concurrencia. No solo mostraremos los comandos sysctl, sino que explicaremos la mecánica subyacente, el por qué de cada cambio y cómo medir su impacto. Asumimos un sistema operativo moderno (kernel 5.x+), aunque los principios aplican a versiones anteriores.

Fundamentos del Stack TCP/IP en Alta Concurrencia

Antes de modificar parámetros, es crucial entender el flujo de una conexión TCP y dónde se producen los cuellos de botella.

  1. Three-Way Handshake (3WHS): El cliente envía un SYN, el servidor responde con SYN-ACK y el cliente confirma con ACK. Este proceso consume una entrada en la cola de conexiones incompletas (SYN backlog) y, al completarse, una entrada en la cola de conexiones aceptadas (listen backlog).
  2. Transferencia de Datos: El kernel gestiona los buffers de envío (send buffer) y recepción (receive buffer) para cada socket. Un buffer demasiado pequeño causa fragmentación y esperas; uno demasiado grande desperdicia memoria.
  3. Cierre de Conexión (Four-Way Handshake): El cierre ordenado (FIN) o abrupto (RST) libera recursos. Las conexiones en estado TIME_WAIT son especialmente problemáticas, ya que mantienen el socket ocupado durante un período de tiempo (por defecto, 60 segundos) para asegurar que paquetes tardíos no interfieran con nuevas conexiones.

Los problemas comunes en alta concurrencia incluyen:

  • Agotamiento del SYN Backlog: El servidor descarta paquetes SYN entrantes porque la cola está llena.
  • Agotamiento de Puertos Efímeros: El servidor (actuando como cliente, ej. proxy inverso) se queda sin puertos locales para nuevas conexiones salientes.
  • Exceso de TIME_WAIT: Miles de conexiones en espera, consumiendo entradas en la tabla de conexiones y puertos.
  • Buffer de Red Subdimensionado: El kernel no puede manejar ráfagas de tráfico, causando pérdida de paquetes y retransmisiones.
  • Latencia por Congestión: Algoritmos de control de congestión ineficientes para conexiones de baja latencia (típicas en centros de datos).

Diagnóstico Inicial: Herramientas Esenciales

No optimices sin medir. Estas herramientas te darán una foto instantánea de la salud de tu stack TCP/IP.

ss (Socket Statistics) - El Sucesor de netstat

# Estadísticas resumidas de sockets TCP
ss -s

# Conexiones TCP en estado TIME_WAIT
ss -tan state time-wait

# Conexiones establecidas y su backlog
ss -tan state established

# Mostrar el tamaño de los buffers de recepción y envío
ss -t -i

nstat (Network Statistics) - Contadores del Kernel

# Muestra todos los contadores SNMP del kernel relacionados con TCP
nstat -az | grep -E "Tcp|Ip"

# Monitorear en tiempo real las retransmisiones
watch -n 2 'nstat -az | grep -E "Retrans|Loss"'

sar (System Activity Reporter) - Series Temporales

# Estadísticas de red cada segundo, 10 veces
sar -n TCP,ETCP,DEV 1 10

Nota: Busca específicamente tcpsynretrans (retransmisiones SYN), tcpretrans (retransmisiones generales), tcpoutrsts (envíos RST), y tcpcurrestab (conexiones establecidas actuales). Un aumento en estos contadores es una señal de alerta temprana.

Optimización del Backlog de Conexiones

net.core.somaxconn - El Backlog de Escucha

Este parámetro define el tamaño máximo del backlog para sockets de escucha (los que ejecutan listen()). Cuando una aplicación (Nginx, Apache) acepta conexiones, las extrae de esta cola. Si la cola está llena, el kernel comienza a descartar conexiones SYN.

  • Valor por defecto: 128 (muy bajo para alta concurrencia).
  • Optimización: 4096, 8192 o incluso 16384.
# Ver valor actual
sysctl net.core.somaxconn

# Aplicar cambio (temporal)
sudo sysctl -w net.core.somaxconn=8192

# Hacer permanente
echo "net.core.somaxconn = 8192" | sudo tee -a /etc/sysctl.conf

¿Por qué 8192? Este número es un compromiso. Un backlog demasiado grande puede ser contraproducente si tu aplicación no puede aceptar conexiones lo suficientemente rápido; simplemente movería el cuello de botella del kernel a la aplicación. 8192 suele ser un punto de partida excelente para Nginx o HAProxy bien configurados. Además, debes configurar tu servidor web para que use este backlog. En Nginx, el parámetro backlog en la directiva listen debe coincidir:

# /etc/nginx/nginx.conf
events {
    worker_connections 4096; # Aumentar según necesidad
    # multi_accept on; # Opcional: aceptar múltiples conexiones a la vez
}

http {
    server {
        listen 80 backlog=8192;
        listen 443 ssl backlog=8192;
        # ...
    }
}

net.ipv4.tcp_max_syn_backlog - El Backlog de SYN

Antes de que una conexión se complete (3WHS), el SYN entrante se almacena en una cola separada: el SYN backlog. Una vez que el cliente responde con el ACK final, la conexión se mueve a la cola de escucha (somaxconn).

  • Valor por defecto: 1024.
  • Optimización: 8192 o superior.
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=8192
echo "net.ipv4.tcp_max_syn_backlog = 8192" | sudo tee -a /etc/sysctl.conf

¿Por qué? Si el SYN backlog se llena, el kernel descarta los SYNs entrantes. El cliente retransmitirá el SYN (con un tiempo de espera exponencial), causando latencia y una mala experiencia de usuario. Este parámetro es especialmente crítico bajo ataques SYN flood, aunque para mitigarlos se usa tcp_syncookies.

net.core.netdev_max_backlog - El Backlog del Dispositivo de Red

Este es el número máximo de paquetes en la cola de entrada de la interfaz de red, antes de que el kernel los procese.

  • Valor por defecto: 1000.
  • Optimización: 5000 o 10000.
sudo sysctl -w net.core.netdev_max_backlog=10000
echo "net.core.netdev_max_backlog = 10000" | sudo tee -a /etc/sysctl.conf

¿Por qué? En servidores con alta tasa de paquetes por segundo (PPS), la CPU puede no ser capaz de procesar las interrupciones de red lo suficientemente rápido. Este backlog actúa como un amortiguador, evitando la pérdida de paquetes durante picos de tráfico.

Gestión de Conexiones y TIME_WAIT

net.ipv4.tcp_tw_reuse - Reutilización de TIME_WAIT

Este es uno de los parámetros más importantes y, a menudo, malentendidos. Habilita la reutilización segura de conexiones en estado TIME_WAIT para nuevas conexiones salientes.

  • Valor por defecto: 0 (desactivado).
  • Optimización: 1 (activado).
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
echo "net.ipv4.tcp_tw_reuse = 1" | sudo tee -a /etc/sysctl.conf

¿Por qué? Cuando tu servidor actúa como cliente (ej., un proxy inverso Nginx que se conecta a un backend), cada petición HTTP puede crear una nueva conexión TCP. Al cerrarse, esta conexión entra en estado TIME_WAIT. Sin tcp_tw_reuse, tu servidor se quedaría sin puertos efímeros (rango 32768-60999) bajo alta carga, ya que cada puerto estaría ocupado por una conexión en TIME_WAIT durante 60 segundos. Con tcp_tw_reuse=1, el kernel puede reutilizar un puerto de una conexión TIME_WAIT si el número de secuencia del nuevo SYN es mayor que el último número de secuencia de la conexión antigua (lo cual es casi siempre cierto). Esto no afecta a las conexiones entrantes.

net.ipv4.tcp_tw_recycle - NO USAR (Obsoleto/Problemas con NAT)

Este parámetro, que también aceleraba la reutilización de TIME_WAIT, está obsoleto desde el kernel 4.12 y no debe usarse. Causaba problemas graves con conexiones detrás de NAT (Network Address Translation), ya que el kernel rastreaba los paquetes por su dirección IP de origen y timestamp. Si múltiples clientes detrás de un mismo NAT se conectaban, el kernel podía descartar paquetes SYN legítimos porque el timestamp no era estrictamente creciente.

Advertencia: tcp_tw_recycle es peligroso. No lo actives. Usa tcp_tw_reuse en su lugar.

net.ipv4.tcp_fin_timeout - Tiempo de Espera para FIN-WAIT-2

Define el tiempo que el kernel esperará para recibir un FIN después de haber enviado uno propio (estado FIN-WAIT-2). Un valor bajo acelera la liberación de conexiones que no se cierran limpiamente.

  • Valor por defecto: 60 segundos.
  • Optimización: 15-30 segundos.
sudo sysctl -w net.ipv4.tcp_fin_timeout=30
echo "net.ipv4.tcp_fin_timeout = 30" | sudo tee -a /etc/sysctl.conf

¿Por qué? Algunos clientes o servidores backends pueden no enviar el FIN final (quedarse colgados). Reducir este timeout libera recursos del socket más rápido.

net.ipv4.tcp_keepalive_* - Mantener Vivas las Conexiones Inactivas

Estos parámetros controlan los probes keepalive que el kernel envía para verificar si una conexión inactiva sigue viva.

  • tcp_keepalive_time: Tiempo de inactividad antes del primer probe (por defecto 7200s).
  • tcp_keepalive_intvl: Intervalo entre probes (por defecto 75s).
  • tcp_keepalive_probes: Número de probes fallidos antes de declarar la conexión muerta (por defecto 9).

Optimización para servidores web: Reducir drásticamente estos valores para detectar conexiones muertas rápidamente.

# Enviar el primer probe después de 5 minutos de inactividad
sudo sysctl -w net.ipv4.tcp_keepalive_time=300
# Enviar probes cada 30 segundos
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=30
# Declarar la conexión muerta después de 3 probes fallidos
sudo sysctl -w net.ipv4.tcp_keepalive_probes=3

echo "net.ipv4.tcp_keepalive_time = 300" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_keepalive_intvl = 30" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_keepalive_probes = 3" | sudo tee -a /etc/sysctl.conf

¿Por qué? Conexiones HTTP persistentes (Keep-Alive) son comunes. Si el cliente se cae abruptamente (sin enviar FIN), el servidor mantendría el socket abierto indefinidamente (por defecto, 2 horas). Los keepalives permiten liberar esos recursos.

Optimización de Buffers y Ventanas TCP

net.core.rmem_max y net.core.wmem_max - Límites Globales

Estos son los límites superiores para los buffers de recepción y envío de cualquier socket.

  • Valor por defecto: 208 KB (212992 bytes) en sistemas modernos.
  • Optimización: 16 MB (16777216 bytes) para servidores de alto rendimiento.
sudo sysctl -w net.core.rmem_max=16777216
sudo sysctl -w net.core.wmem_max=16777216
echo "net.core.rmem_max = 16777216" | sudo tee -a /etc/sysctl.conf
echo "net.core.wmem_max = 16777216" | sudo tee -a /etc/sysctl.conf

¿Por qué? Un buffer de recepción pequeño significa que el kernel debe notificar al remitente más a menudo (ventana de recepción cero), lo que reduce el throughput. Un buffer grande permite que el kernel almacene en buffer grandes ráfagas de datos. El valor de 16 MB es un punto de partida común; para servidores con mucha RAM y conexiones de alta latencia (ej., entre centros de datos), se puede aumentar a 64 MB.

net.ipv4.tcp_rmem y net.ipv4.tcp_wmem - Buffers Automáticos TCP

Estos parámetros definen los buffers mínimos, por defecto y máximos para sockets TCP. El kernel ajusta automáticamente el buffer dentro de este rango según la carga.

  • Formato: min default max (en bytes).
  • Valores por defecto (kernel 5.x):
    • tcp_rmem: 4096 131072 6291456 (4KB, 128KB, 6MB)
    • tcp_wmem: 4096 16384 4194304 (4KB, 16KB, 4MB)

Optimización para alta concurrencia (muchas conexiones, baja latencia):

# Buffer de recepción: mínimo 4KB, por defecto 128KB, máximo 16MB
sudo sysctl -w net.ipv4.tcp_rmem="4096 131072 16777216"
# Buffer de envío: mínimo 4KB, por defecto 64KB, máximo 16MB
sudo sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

echo "net.ipv4.tcp_rmem = 4096 131072 16777216" | sudo tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_wmem = 4096 65536 16777216" | sudo tee -a /etc/sysctl.conf

¿Por qué estos valores?

  • Mínimo (4096): Suficiente para paquetes pequeños (SYN, ACK, etc.). No se desperdicia memoria en conexiones inactivas.
  • Por defecto (131072 / 65536): Un buen balance para la mayoría de las conexiones. El kernel empieza con este tamaño y lo ajusta dinámicamente.
  • Máximo (16777216): Permite que las conexiones que lo necesiten (ej., descarga de archivos grandes) utilicen buffers grandes para maximizar el throughput, respetando el límite global rmem_max/wmem_max.

Nota: El buffer por defecto es crucial. Un valor demasiado alto (ej., 1MB) para el buffer por defecto en un servidor con 10,000 conexiones significa 10GB de RAM solo para buffers de red, lo cual es insostenible. La optimización automática del kernel es tu amiga.

net.ipv4.tcp_window_scaling - Escalado de Ventana TCP

Habilitar el escalado de ventana TCP (RFC

¿Necesitas ayuda?Son dos de nuestros técnicos, Agustín y Mikel, y están disponibles para resolver cualquier problema.

Hablar con ellos ahora
Agustín y Mikel