Solución de problemas de rendimiento lento: Uso efectivo de 'netstat' y 'ss'

Domina las herramientas esenciales de redes Linux `netstat` y `ss` para solucionar problemas de rendimiento de manera eficiente. Esta guía compara el legado `netstat` con la utilidad moderna y más rápida `ss`, proporcionando ejemplos prácticos de comandos. Aprende a filtrar resultados por estado de conexión, identificar servicios en escucha y diagnosticar cuellos de botella de red rápidamente utilizando estadísticas de sockets Netlink.

Solución de problemas de rendimiento lento: Uso efectivo de 'netstat' y 'ss'

Cuando un servicio Linux se siente lento, la tabla de sockets es uno de los lugares más rápidos para separar "la aplicación está sobrecargada" de "la ruta de red está desordenada". Un servidor web que no puede aceptar nuevas conexiones, un trabajador que está atascado abriendo sesiones de base de datos y un host con un montón de handshakes TCP medio abiertos, todos parecen una lentitud vaga para la persona que espera al otro lado.

netstat y ss te ayudan a responder una pregunta más específica: ¿qué sockets de red existen en esta máquina ahora mismo, en qué estado están y qué proceso los posee? netstat sigue siendo útil en sistemas antiguos y en runbooks antiguos. ss es la herramienta a la que recurro primero en Linux moderno porque es más rápida en hosts ocupados y tiene un mejor filtrado incorporado.

¿Por qué monitorear los sockets de red?

La latencia y lentitud de la red a menudo están relacionadas con problemas de conexión más que con agotamiento de CPU o memoria. Monitorear los sockets ayuda a los administradores a responder preguntas críticas como:

  • ¿Qué puertos están escuchando activamente conexiones?
  • ¿Hay demasiadas conexiones atascadas en los estados SYN_RECV o TIME_WAIT?
  • ¿Qué proceso (PID) está usando un puerto específico?
  • ¿Hay conexiones salientes inesperadas ocurriendo?

Al examinar las estadísticas de sockets, puedes descartar rápidamente problemas de configuración de red o identificar contención de recursos relacionada con el manejo de conexiones.

La herramienta heredada: netstat

netstat ha sido la utilidad estándar para mostrar conexiones de red, tablas de enrutamiento, estadísticas de interfaz y conexiones de enmascaramiento durante décadas. Aunque está obsoleto en favor de ss en muchos sistemas modernos, sigue estando ampliamente disponible y a menudo es familiar para los administradores de larga trayectoria.

Ejemplos comunes de netstat

Las banderas más comunes utilizadas con netstat proporcionan una visión general completa:

Banderas Descripción
-a Muestra todos los sockets (escuchando y no escuchando)
-n Muestra direcciones numéricas en lugar de intentar resolver nombres de host y servicios (acelera la salida)
-t Muestra conexiones TCP
-u Muestra conexiones UDP
-l Muestra solo sockets en escucha
-p Muestra el PID/nombre del programa asociado al socket (requiere privilegios de root)

Ejemplo: Ver todas las conexiones TCP activas numéricamente

sudo netstat -ant

Ejemplo: Encontrar qué está escuchando en el puerto 80 (HTTP)

sudo netstat -tulpen | grep ':80'

Entendiendo los estados de conexión (netstat)

La salida de netstat a menudo incluye una columna State. Los estados clave a observar incluyen:

  • LISTEN: Esperando conexiones entrantes.
  • ESTABLISHED: Una conexión activa y abierta.
  • TIME_WAIT: Un socket esperando un breve período después de cerrar para asegurar que los paquetes retrasados sean manejados.
  • SYN_RECV: Esperando el reconocimiento final de un handshake de tres vías (puede indicar un ataque de inundación SYN si es excesivo).

Advertencia sobre netstat: netstat a menudo depende de analizar los archivos /proc/net/*, lo que puede ser lento, especialmente en sistemas con un volumen muy alto de conexiones activas (miles). Esta es la razón principal por la que se desarrolló ss.

El reemplazo moderno: ss (Estadísticas de sockets)

La utilidad ss es significativamente más rápida que netstat porque recupera información del socket directamente del espacio del kernel utilizando sockets Netlink, evitando las búsquedas más lentas del sistema de archivos.

Ejemplos comunes de ss

La estructura de banderas para ss es muy similar a netstat, promoviendo una transición fácil:

Banderas Descripción
-a Muestra todos los sockets
-n Muestra direcciones numéricas
-t Muestra sockets TCP
-u Muestra sockets UDP
-l Muestra sockets en escucha
-p Muestra información del proceso (PID/Programa)

Ejemplo: Ver todas las conexiones TCP activas numéricamente (Equivalente a netstat -ant)

ss -ant

Ejemplo: Encontrar qué está escuchando en el puerto 443 (HTTPS)

sudo ss -tulpen | grep ':443'

Filtrado avanzado con ss

Una de las mayores ventajas de ss es su capacidad para realizar filtrado directo en los estados de conexión, lo cual es mucho más eficiente que canalizar la salida de netstat a grep.

Filtrado por estado de conexión

Puedes usar la opción state directamente dentro del comando ss. Esto es extremadamente útil para diagnosticar acumulación de conexiones.

Encontrar todos los sockets actualmente en estado TIME-WAIT:

ss -tan state time-wait

Encontrar todos los sockets en estado SYN-SENT (lado del cliente esperando respuesta del servidor):

ss -tan state syn-sent

Filtrado por puerto o dirección

Filtrar por dirección o puerto de destino/origen es sencillo:

Mostrar conexiones establecidas destinadas al puerto 22 (SSH):

ss -tn state established '( dport = :22 or sport = :22 )'

Mostrar conexiones relacionadas con una dirección IP local específica:

ss -ant '( daddr = 192.168.1.100 or saddr = 192.168.1.100 )'

Análisis de rendimiento: Comparación netstat vs. ss

Al solucionar problemas, la elección entre las herramientas a menudo se reduce a la velocidad y el detalle.

Característica netstat ss
Velocidad Más lento (Lee archivos) Mucho más rápido (Usa sockets Netlink)
Sintaxis Madura, bien documentada Banderas similares, opciones específicas más nuevas
Filtrado Requiere canalizar a grep Soporte nativo de filtrado por estado y dirección
Profundidad de información Bueno para lo básico Más detalle sobre tamaños de búfer de socket (Información TCP)
Disponibilidad Casi universal Estándar en distribuciones Linux modernas

Diagnosticando el establecimiento lento de conexiones

Si los clientes reportan conexiones lentas, verifica si hay sockets atascados esperando handshakes. Usar ss es la forma más rápida de determinar esto:

  1. Verifica conteos altos de SYN-RECV: Esto sugiere que el servidor está recibiendo solicitudes de conexión pero no completando el handshake, a menudo debido a agotamiento de recursos o alta carga de tráfico.
    ss -s | grep syn-rec
    
  2. Verifica conteos altos de SYN-SENT: Si el servidor mismo está iniciando muchas conexiones (por ejemplo, actuando como cliente para bases de datos u otras APIs), esto muestra que está esperando respuestas.
    ss -s | grep syn-sent
    

Si ves números altos sostenidos en cualquiera de las categorías, trátalos como una pista, no como un veredicto. SYN-SENT puede significar que un host remoto está caído, una ruta es incorrecta, un firewall está descartando tráfico silenciosamente, o el servicio remoto está sobrecargado. SYN-RECV puede significar que el servidor está bajo carga, los paquetes se están perdiendo, o los clientes están abriendo conexiones y no completándolas.

Un flujo de triaje práctico

Cuando alguien dice "la aplicación está lenta", normalmente empiezo con un pase corto y repetible:

sudo ss -tulpen
ss -s
sudo ss -tan state established '( sport = :443 or dport = :443 )' | head
sudo ss -tan state syn-recv
sudo ss -tan state time-wait | head

El primer comando confirma que el servicio esperado está realmente escuchando y muestra el proceso propietario. El resumen muestra si el host tiene un número sorprendente de sockets TCP. El comando filtrado de establecidos prueba si el tráfico real del cliente está conectado al puerto. Las comprobaciones de syn-recv y time-wait muestran si la configuración de la conexión o la rotación de conexiones merecen atención.

Por ejemplo, imagina un proxy inverso Nginx donde los usuarios se quejan de que las nuevas solicitudes se cuelgan durante unos segundos. sudo ss -tulpen | grep ':443' confirma que Nginx posee el listener HTTPS. ss -s muestra un gran total TCP, y sudo ss -tan state syn-recv '( sport = :443 )' sigue devolviendo filas de los mismos rangos de origen. Eso no prueba automáticamente un ataque, pero te dice que mires las comprobaciones de salud del balanceador de carga, la pérdida de paquetes ascendente, la presión del backlog SYN, los registros del firewall y posiblemente los límites de velocidad.

Ahora imagina que el mismo proxy tiene muy pocos sockets SYN_RECV pero muchas conexiones establecidas a una base de datos ascendente en el puerto 5432. Eso te aleja del HTTPS público y te dirige hacia la ruta de la base de datos:

sudo ss -tanp '( dport = :5432 or sport = :5432 )'

Si el proceso propietario es tu aplicación y el conteo sigue aumentando, la siguiente pregunta útil es si la aplicación está filtrando conexiones, esperando consultas lentas o fallando en devolver conexiones a un pool. ss no responde esa pregunta a nivel de aplicación, pero te lleva a la habitación correcta.

Leyendo TIME_WAIT sin entrar en pánico

TIME_WAIT es un estado TCP normal, no un error por sí mismo. Un servidor que maneja muchas conexiones de corta duración mostrará naturalmente sockets TIME_WAIT. Existen para que los paquetes retrasados de una conexión antigua no se confundan con una nueva.

La pregunta útil es si TIME_WAIT coincide con la carga de trabajo. Un trabajo por lotes que abre una nueva conexión HTTP para cada pequeña solicitud puede crear una ola de TIME_WAIT. Un servicio que debería usar keep-alive pero no lo hace puede hacer lo mismo. Antes de ajustar la configuración del kernel, verifica si la aplicación puede reutilizar conexiones, habilitar HTTP keep-alive o usar un pool de clientes adecuado.

Ten cuidado con los consejos antiguos que sugieren cambiar ciegamente los sysctls de TCP para "arreglar" TIME_WAIT. Algunas configuraciones dependen de la versión del kernel, algunas han sido eliminadas o desaconsejadas con el tiempo, y algunas crean fallas sutiles detrás de NAT o balanceadores de carga. Comienza por entender por qué las conexiones son de corta duración.

Comprobando la presión local versus remota

Un detalle que ahorra tiempo es si el host local está principalmente aceptando conexiones o principalmente haciéndolas. Un proxy frontend generalmente tiene muchas conexiones donde el puerto local es 80 o 443. Un servidor de aplicaciones que habla con bases de datos y APIs puede tener muchas conexiones donde el puerto remoto es 5432, 3306, 6379 o 443.

Para listeners locales y tráfico entrante:

sudo ss -tan '( sport = :443 )'

Para tráfico saliente hacia una dependencia:

sudo ss -tan '( dport = :6379 )'

Esa distinción cambia la siguiente conversación. Si el HTTPS entrante se está acumulando, es posible que necesites inspeccionar el balanceador de carga, la terminación TLS, los límites de trabajadores o el comportamiento del cliente. Si las conexiones Redis salientes se están acumulando, la aplicación local puede estar creando demasiadas conexiones de cliente, esperando en Redis o reintentando de manera demasiado agresiva.

Cuando necesites un conteo rápido sin leer cientos de filas, combina ss con herramientas simples de shell:

sudo ss -tan state established '( dport = :443 )' | wc -l
sudo ss -tan state established '( dport = :5432 )' | wc -l

El conteo incluye la línea de encabezado, por lo que no es una métrica perfecta. Para triaje, sigue siendo útil. Si el número se duplica cada minuto durante un incidente, tienes una señal más fuerte que una sola instantánea.

Contenedores y espacios de nombres de red

En hosts contenerizados, ten cuidado con dónde ejecutas el comando. Ejecutar ss en el host muestra los espacios de nombres de red del host y los puertos publicados, pero puede no mostrar la misma vista que el proceso ve dentro de su contenedor. Si un servicio se ejecuta en un contenedor, compara ambas vistas:

sudo ss -tulpen
docker exec <contenedor> ss -tulpen

Para Kubernetes, usa la vista del nodo para los listeners a nivel de host y kubectl exec para el espacio de nombres de red del pod. Un puerto puede estar abierto dentro del contenedor mientras que el host, el servicio, el ingress o la política de red aún impiden que el tráfico llegue a él. ss es una herramienta de verdad local, no una prueba de conectividad de extremo a extremo.

Mejores prácticas para la solución de problemas de red

  1. Usa siempre -n: Al solucionar problemas de rendimiento o scripting, usa la bandera numérica (-n) para evitar retrasos en la resolución de DNS, que pueden hacer que los diagnósticos sean lentos.
  2. Prioriza ss: Adopta ss como tu herramienta predeterminada. Reserva netstat solo para sistemas heredados donde ss no esté disponible.
  3. Ejecuta como root para PID: Para ver qué programa está usando un puerto, generalmente necesitas sudo o privilegios de root al usar la bandera -p con ambas utilidades.
  4. Verifica las estadísticas de interfaz: No olvides los contadores de interfaz. Usa ip -s link show <nombre_interfaz> para verificar paquetes perdidos o errores, que podrían indicar un problema de capa física en lugar de un problema de socket.
  5. Compara instantáneas. Una salida de ss es una fotografía. Dos salidas tomadas con un minuto de diferencia te dicen si la situación está creciendo, disminuyendo o estable.
  6. Escribe el filtro exacto. Durante incidentes, un comando guardado como ss -tan '( dport = :5432 )' es más fácil de repetir y comparar que una tubería grep recordada a medias.

El hábito que vale la pena es simple: comienza con los listeners, pasa a los estados de conexión, identifica el proceso propietario, luego decide si el siguiente paso pertenece a la aplicación, la ruta de red, el firewall o el kernel.