Cuando un sitio web o una API reciben mucha carga, los primeros errores a menudo no tienen nada que ver con la CPU o la RAM: Too many open files, nf_conntrack: table full, dropping packet, conexiones que se quedan colgadas en estado SYN o una cola de escucha que se desborda. Son límites del kernel y de los procesos cuyos valores predeterminados están pensados para una máquina pequeña, no para un servidor que gestiona decenas de miles de conexiones. Esta guía muestra cómo averiguar qué límite está alcanzando y cómo aumentar el límite de descriptores de archivo (ulimit), ajustar la pila TCP con sysctl, dimensionar la tabla de seguimiento de conexiones y configurar Nginx en consonancia.
# Kernel messages about dropped packets or full tables
dmesg -T | grep -iE 'conntrack|too many|possible SYN flooding' | tail
# Socket summary and listen queues (Recv-Q close to Send-Q = backlog is full)
ss -s
ss -lnt
# Listen queue overflows and dropped SYNs since boot
nstat -az | grep -iE 'ListenOverflows|ListenDrops|TCPReqQFull'
# Connection tracking usage vs maximum
cat /proc/sys/net/netfilter/nf_conntrack_count /proc/sys/net/netfilter/nf_conntrack_max 2>/dev/null
# Open file limit of the shell and of a running service (Nginx worker example)
ulimit -n
grep 'Max open files' /proc/$(pgrep -f 'nginx: worker' | head -1)/limits
Cada conexión, archivo de log y socket usa un descriptor de archivo. El valor predeterminado habitual de 1024 por proceso es demasiado bajo para un proxy o una base de datos con mucha carga. Aumente el máximo de todo el sistema, los límites por usuario para las sesiones interactivas y, sobre todo, el límite de los propios servicios systemd, porque los servicios ignoran /etc/security/limits.conf.
# System-wide maximum
cat > /etc/sysctl.d/90-files.conf <<'EOF2'
fs.file-max = 2097152
fs.nr_open = 2097152
EOF2
# Login sessions (takes effect at the next login)
cat > /etc/security/limits.d/90-nofile.conf <<'EOF2'
* soft nofile 1048576
* hard nofile 1048576
root soft nofile 1048576
root hard nofile 1048576
EOF2
# A specific service, e.g. Nginx (repeat for mysqld, php-fpm, your app)
mkdir -p /etc/systemd/system/nginx.service.d
cat > /etc/systemd/system/nginx.service.d/limits.conf <<'EOF2'
[Service]
LimitNOFILE=1048576
EOF2
systemctl daemon-reload && systemctl restart nginx
Los siguientes valores son un punto de partida razonable para un servidor web, proxy o API con mucha carga. Colóquelos en un archivo propio para poder ver y revertir sus cambios fácilmente.
cat > /etc/sysctl.d/91-network-tuning.conf <<'EOF2'
# Longer accept and SYN queues for bursts of new connections
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 16384
# More local ports for outgoing connections (proxies, crawlers, API clients)
net.ipv4.ip_local_port_range = 1024 65000
# Reuse TIME_WAIT sockets for new outgoing connections (safe; tcp_tw_recycle no longer exists)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Keepalive: detect dead peers after about 10 minutes instead of 2 hours
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
# Keep SYN cookies on as a basic protection against SYN floods
net.ipv4.tcp_syncookies = 1
# Bigger socket buffers for fast long-distance transfers
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
# BBR congestion control (kernel 4.9+)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF2
sysctl --system
sysctl net.core.somaxconn net.ipv4.tcp_congestion_control
Para más información sobre BBR, consulte activar BBR en Linux. Recuerde que las aplicaciones pasan su propio backlog a listen(); Nginx, por ejemplo, necesita listen 80 backlog=65535; para usar la cola más grande.
Si usa firewalld, ufw, NAT con iptables o Docker, el kernel registra cada conexión en la tabla conntrack. Cuando se llena, los paquetes nuevos se descartan y el sitio parece inaccesible "de forma aleatoria". El máximo predeterminado depende de la RAM y a menudo es de solo 65536 o 262144.
# Load the module so the keys exist, and raise the limits
modprobe nf_conntrack
cat > /etc/sysctl.d/92-conntrack.conf <<'EOF2'
net.netfilter.nf_conntrack_max = 1048576
# Forget idle established connections after 2 hours instead of 5 days
net.netfilter.nf_conntrack_tcp_timeout_established = 7200
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
EOF2
sysctl --system
# Hash table size (about max / 4), applied at module load
echo 'options nf_conntrack hashsize=262144' > /etc/modprobe.d/nf_conntrack.conf
echo 262144 > /sys/module/nf_conntrack/parameters/hashsize
# Load the module at boot so the sysctl values are applied
echo nf_conntrack > /etc/modules-load.d/nf_conntrack.conf
Cada entrada de conntrack ocupa unos 300 bytes de memoria del kernel, así que un millón de entradas cuestan alrededor de 300 MB. En un servidor web puro sin NAT también puede evitar por completo el seguimiento de los puertos 80/443 con una regla notrack, pero ampliar la tabla es la solución más sencilla.
# /etc/nginx/nginx.conf (main context and events block)
worker_processes auto;
worker_rlimit_nofile 1048576;
events {
worker_connections 65535;
multi_accept on;
}
http {
keepalive_timeout 30;
keepalive_requests 1000;
# ...
}
# In each server block, let the listen socket use the bigger backlog
# listen 80 backlog=65535;
# listen 443 ssl backlog=65535;
nginx -t && systemctl reload nginx
grep 'Max open files' /proc/$(pgrep -f 'nginx: worker' | head -1)/limits
Vuelva a ejecutar los comandos del paso 1 durante los picos de tráfico. ListenOverflows debería dejar de aumentar, el número de entradas de conntrack debería mantenerse muy por debajo del máximo y los errores "too many open files" deberían desaparecer de los logs de su aplicación. Para monitorizar de forma continua la CPU, la memoria, el disco y el ancho de banda, consulte nuestra guía de monitorización de servidores.
Para proxies y APIs suelen ser el límite de descriptores de archivo del servicio y la tabla conntrack; para sitios con picos repentinos de visitantes, el backlog de escucha (somaxconn más el backlog de Nginx). El paso 1 le indica cuál está alcanzando.
El módulo conntrack todavía no está cargado. Ejecute modprobe nf_conntrack y añádalo a /etc/modules-load.d/ como se muestra en el paso 4.
Una CDN reduce el número de conexiones que llegan a su servidor, pero el servidor de origen sigue necesitando suficientes descriptores de archivo y backlog para las conexiones que abre la CDN, y para todo el tráfico de API o WebSocket que no se almacena en caché.
¿Sigue sin resolverlo después de seguir estos pasos? Abra un ticket de soporte y el equipo técnico de IMIDC, disponible 24/7, le ayudará. Incluya la IP del servidor, la versión del sistema operativo, los mensajes de error que aparecen y la salida de los comandos del paso 1 para que podamos localizar el problema más rápido.