Diagnóstico de un servidor que se congela bajo carga
Un servidor Linux con 16 GB de RAM ejecuta una aplicación Java y PostgreSQL. Bajo carga, el servidor deja de responder durante 30-60 s y luego se recupera. Los síntomas: free -m muestra memoria disponible cercana a 0 y swap en uso creciente; vmstat registra valores altos de si/so (swap in/out); el uso de CPU es alto pero no saturado; dmesg no muestra errores de hardware. La aplicación tiene -Xmx12g y PostgreSQL usa shared_buffers=4g. El equipo propone añadir más CPU y reiniciar el servidor cada noche.
1. Explica la causa raíz de las congelaciones y por qué añadir CPU o reiniciar no la resuelve.
Read the worked answer
La suma de memoria comprometida excede la RAM física: la JVM puede llegar a 12 GB de heap más overhead (metaspace, stacks, buffers directos), y PostgreSQL reserva 4 GB de shared_buffers más memoria de trabajo por conexión. Sobre 16 GB, el sistema entra en presión de memoria y empieza a paginar a swap. El intercambio de páginas (si/so altos) es órdenes de magnitud más lento que la RAM, y cuando el kernel pasa tiempo moviendo páginas (thrashing) el servidor deja de responder aunque la CPU no esté saturada: el cuello de botella es la memoria y la E/S de swap.
Añadir CPU no ayuda porque el problema no es cómputo. Reiniciar cada noche solo pospone el síntoma: la asignación de memoria sigue sobredimensionada y el swap se llena de nuevo.
El diagnóstico se confirma con si/so altos, swap creciente y disponibilidad cercana a cero, junto con la suma de configuraciones que supera la RAM.
2. Propón un plan de corrección medible para eliminar las congelaciones.
Read the worked answer
Plan en tres frentes, con métricas antes/después:
- Ajustar la memoria comprometida: reducir
-Xmxa un valor que deje margen para el sistema operativo y PostgreSQL (p. ej., heap de 6-8 GB según perfil real, medido con el recolector), y ajustarshared_buffersywork_memde PostgreSQL a la RAM disponible. La suma de picos debe quedar por debajo de la RAM física con 15-20% de holgura. - Reducir la presión: limitar conexiones concurrentes, usar un pool, y revisar fugas de memoria con volcados de heap si el uso crece sin liberarse. Considerar
vm.swappinessbajo solo como medida complementaria, no como solución. - Medir: registrar
si/so, memoria disponible, latencia p95 y reinicios. Criterio de éxito: cero swap in/out sostenido y latencia estable bajo la carga pico; validar con prueba de carga reproducible.
Si tras ajustar el consumo la carga sigue creciendo, la decisión sería escalar verticalmente (más RAM) o separar la base de datos en otro host, pero primero hay que corregir la configuración.