Objetivo operativo: estabilidad antes que “máxima velocidad”
En operación diaria, el rendimiento de Apache se gestiona con tres palancas principales: el modelo de procesos/hilos (MPM), la forma en que se mantienen las conexiones (KeepAlive y timeouts) y el trabajo extra que hacemos por respuesta (compresión y caché). El objetivo para principiantes es evitar saturación (CPU/RAM), colas de conexiones y errores intermitentes, aplicando cambios pequeños y medibles.
MPM: prefork, worker y event (qué cambia y cuándo elegir)
Qué es un MPM
El MPM (Multi-Processing Module) define cómo Apache atiende solicitudes en paralelo: cuántos procesos crea, si usa hilos, y cómo maneja conexiones persistentes. Elegir el MPM correcto suele ser el mayor salto de estabilidad.
Comparativa rápida
| MPM | Modelo | Ventajas | Riesgos/precauciones | Recomendación para principiantes |
|---|---|---|---|---|
prefork | Procesos (sin hilos) | Compatibilidad amplia; aislamiento por proceso | Consume más RAM; menos eficiente con muchas conexiones | Úsalo si necesitas módulos no thread-safe o dependencias legacy |
worker | Procesos + hilos | Mejor uso de memoria; buena concurrencia | Requiere módulos thread-safe; cuidado con límites de hilos | Buena opción general si no hay requisitos especiales |
event | Procesos + hilos + gestión eficiente de KeepAlive | Excelente con muchas conexiones persistentes; reduce hilos “ocupados” esperando | Igual que worker respecto a thread-safety | Preferido en la mayoría de escenarios modernos con tráfico concurrente |
Cómo saber qué MPM está activo
Verifica el MPM en ejecución y los módulos cargados:
apachectl -V | grep -i mpmapachectl -M | grep mpmDeberías ver algo como mpm_event_module, mpm_worker_module o mpm_prefork_module.
Cambiar de MPM (paso a paso, con cuidado)
El cambio depende de la distribución, pero el flujo seguro es siempre: habilitar el MPM deseado, deshabilitar el actual, validar configuración y recargar/reiniciar.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
- Debian/Ubuntu (ejemplo típico):
a2dismod mpm_prefork mpm_worker mpm_eventa2enmod mpm_eventapachectl -tsystemctl reload apache2Si el cambio afecta a módulos que requieren reinicio total, usa:
systemctl restart apache2- RHEL/CentOS/Alma/Rocky (orientativo): suele gestionarse por paquetes y configuración en
conf.modules.d. Asegúrate de que solo un MPM quede cargado y valida conapachectl -M.
Precaución: si tu stack incluye componentes que no son seguros con hilos, evita worker/event hasta confirmarlo. Si no estás seguro, mantén prefork y optimiza concurrencia/KeepAlive primero.
Concurrencia y conexiones: MaxRequestWorkers, KeepAlive y Timeouts
Concepto clave: capacidad = “cuántas solicitudes simultáneas puedo atender”
Apache tiene un límite de trabajo concurrente. Si lo pones muy bajo, verás colas y latencia; si lo pones muy alto, el servidor puede quedarse sin RAM y empezar a intercambiar (swap) o matar procesos, empeorando todo.
Directivas principales (qué hacen)
MaxRequestWorkers: máximo de solicitudes simultáneas atendidas (en prefork: procesos; en worker/event: hilos). Es el “techo” de concurrencia.ServerLimityThreadsPerChild(worker/event): definen el máximo estructural de procesos/hilos.MaxRequestWorkersno puede excederServerLimit * ThreadsPerChild.KeepAlive: permite reutilizar la misma conexión TCP para varias solicitudes (mejora rendimiento percibido, pero retiene recursos si se abusa).KeepAliveTimeout: cuánto tiempo se mantiene la conexión abierta esperando otra solicitud.Timeout: tiempo máximo para operaciones de red (por ejemplo, lectura/escritura). Un valor demasiado alto puede “atar” workers con clientes lentos.RequestReadTimeout(si está disponible): protege contra clientes muy lentos limitando tiempos de lectura de cabeceras/cuerpo.
Guía práctica: ajustar concurrencia sin romper el servidor
Paso 1: mide el consumo por worker. En un momento de carga representativa, identifica procesos/hilos de Apache y su memoria. Herramientas útiles:
ps -o pid,ppid,cmd,%mem,rss -C apache2 --sort=-rss | headps -o pid,ppid,cmd,%mem,rss -C httpd --sort=-rss | headObserva el RSS (memoria residente) típico. Para una estimación simple, toma un valor “promedio alto” (por ejemplo, el percentil alto visual: no el máximo extremo, pero tampoco el mínimo).
Paso 2: define un presupuesto de RAM para Apache. Como regla operativa, reserva memoria para el sistema y otros servicios (base de datos, cachés, etc.). En un servidor dedicado a Apache, podrías empezar reservando 25–40% para el sistema y el resto para Apache; si convive con otros servicios, sé más conservador.
Paso 3: calcula un MaxRequestWorkers inicial. Aproximación:
MaxRequestWorkers ≈ (RAM_disponible_para_Apache) / (RSS_promedio_por_worker)Ejemplo: si asignas 2 GB a Apache y cada worker consume ~50 MB, entonces 2048/50 ≈ 40. Empieza con 40 y ajusta según métricas.
Paso 4: aplica el ajuste en el bloque del MPM. Ubica el archivo del MPM (según distro) y ajusta. Ejemplos típicos:
<IfModule mpm_event_module> ServerLimit 4 ThreadsPerChild 25 MaxRequestWorkers 100 MaxConnectionsPerChild 0</IfModule><IfModule mpm_prefork_module> MaxRequestWorkers 50 MaxConnectionsPerChild 0</IfModule>Notas:
MaxConnectionsPerChild(antesMaxRequestsPerChild) ayuda a mitigar fugas de memoria reciclando workers. Para empezar, puedes dejar0(ilimitado) y, si sospechas crecimiento de memoria, probar valores como 5000–20000.- En
event/worker, si subesMaxRequestWorkers, revisa queServerLimit * ThreadsPerChildlo soporte.
KeepAlive: cuándo ayuda y cuándo estorba
KeepAlive On suele mejorar rendimiento en sitios con múltiples recursos (CSS/JS/imagenes) porque evita abrir muchas conexiones. El riesgo es que, con KeepAliveTimeout alto, los workers quedan “reservados” esperando, reduciendo capacidad real.
Configuración inicial razonable para principiantes:
KeepAlive On KeepAliveTimeout 2 MaxKeepAliveRequests 100- KeepAliveTimeout: 1–3 segundos suele ser un buen punto de partida.
- MaxKeepAliveRequests: limita cuántas solicitudes se sirven por conexión; 100 es común.
Timeouts: evita que clientes lentos consuman tu concurrencia
Valores demasiado altos pueden provocar que conexiones lentas ocupen workers durante mucho tiempo. Un punto de partida:
Timeout 60Si tienes cargas con subidas grandes o proxys lentos, ajusta con cuidado. Si está disponible, RequestReadTimeout puede protegerte de lecturas lentas:
<IfModule reqtimeout_module> RequestReadTimeout header=10-20,MinRate=500 body=20,MinRate=500</IfModule>Esto limita el tiempo de lectura y exige una tasa mínima, reduciendo el impacto de clientes problemáticos.
Compresión: mod_deflate y Brotli (impacto y precauciones)
Qué ganas y qué cuesta
La compresión reduce el tamaño de respuesta (menos ancho de banda, tiempos de carga menores), a cambio de CPU. En servidores con CPU limitada o contenido ya comprimido, conviene ser selectivo.
Reglas prácticas para principiantes
- Comprime texto: HTML, CSS, JS, JSON, XML, SVG.
- No comprimas (o no vale la pena) contenido ya comprimido: JPG/PNG/WebP, MP4, PDF (a menudo), ZIP.
- Verifica que el proxy/CDN (si existe) no esté duplicando compresión de forma inesperada.
Configurar mod_deflate (paso a paso)
Paso 1: habilita el módulo (si aplica en tu distro):
a2enmod deflatePaso 2: añade una configuración básica (por ejemplo en un archivo de conf dedicado):
<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/javascript application/x-javascript application/json application/xml image/svg+xml # Evita problemas con proxies antiguos BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html Header append Vary Accept-Encoding</IfModule>Paso 3: valida y recarga:
apachectl -t && systemctl reload apache2Paso 4: comprueba desde cliente:
curl -I -H 'Accept-Encoding: gzip' http://tu-sitio/Busca Content-Encoding: gzip y Vary: Accept-Encoding.
Brotli (si aplica)
Brotli suele comprimir mejor que gzip para texto, con un coste de CPU que puede ser mayor según el nivel. Si tu Apache tiene mod_brotli disponible, puedes habilitarlo y dejar gzip como fallback.
Ejemplo de configuración (orientativa):
<IfModule brotli_module> AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json application/xml image/svg+xml BrotliCompressionQuality 5 Header append Vary Accept-Encoding</IfModule>Consejo: empieza con calidad 4–6 para equilibrar CPU/beneficio. Evita niveles altos en servidores con picos de tráfico.
Caché básica: qué puedes cachear en Apache y qué no
Dos enfoques distintos
- Caché en el cliente (navegador): controlas cuánto tiempo el navegador reutiliza recursos estáticos. Es el “mejor primer paso” porque reduce solicitudes al servidor.
- Caché en el servidor (mod_cache): Apache guarda respuestas para servirlas más rápido. Útil en contenido repetido, pero requiere cuidado con contenido dinámico y cabeceras.
Caché en navegador para estáticos (paso a paso)
Paso 1: habilita módulos de cabeceras/expiración si aplica:
a2enmod expires headersPaso 2: define expiración para tipos estáticos comunes:
<IfModule mod_expires.c> ExpiresActive On ExpiresByType text/css "access plus 7 days" ExpiresByType application/javascript "access plus 7 days" ExpiresByType image/svg+xml "access plus 30 days" ExpiresByType image/png "access plus 30 days" ExpiresByType image/jpeg "access plus 30 days" ExpiresByType image/webp "access plus 30 days"</IfModule> <IfModule mod_headers.c> <FilesMatch "\.(css|js|png|jpg|jpeg|webp|svg)$"> Header set Cache-Control "public" </FilesMatch></IfModule>Precaución: si publicas archivos con el mismo nombre pero contenido distinto, el navegador puede servir versiones antiguas. La práctica recomendada es usar “versionado” en nombres (por ejemplo app.v123.js) o querystrings controlados.
Caché en servidor con mod_cache (básico y conservador)
Si quieres cachear respuestas en el servidor, empieza por contenido claramente cacheable (por ejemplo, páginas públicas que cambian poco) y evita rutas con sesión, personalización o cookies.
Paso 1: habilita módulos (según disponibilidad):
a2enmod cache cache_diskPaso 2: configura un caché en disco y limita su alcance:
<IfModule mod_cache.c> CacheQuickHandler Off CacheLock On CacheLockPath /tmp/mod_cache-lock CacheLockMaxAge 5 <IfModule mod_cache_disk.c> CacheRoot /var/cache/apache2/mod_cache_disk CacheDirLevels 2 CacheDirLength 1 </IfModule> # Ejemplo: cachear solo una ruta pública CacheEnable disk /public/</IfModule>Paso 3: evita cachear contenido con cookies o autenticación (enfoque simple):
<LocationMatch "^/"> CacheDisable /</LocationMatch> <Location "/public/"> CacheEnable disk /public/</Location>Precauciones importantes:
- Si tu aplicación envía
Set-Cookieo varía por usuario, no caches esas respuestas. - Respeta cabeceras de origen (
Cache-Control,Expires) si estás detrás de un proxy/app server. - Revisa el tamaño del caché en disco y permisos del directorio.
Monitoreo operativo: qué mirar cada día
Consumo de CPU y RAM
- CPU alta sostenida: puede indicar compresión agresiva, demasiada concurrencia, o backend lento (si Apache actúa como proxy).
- RAM creciendo: revisa tamaño de procesos/hilos; considera
MaxConnectionsPerChildsi hay crecimiento continuo.
Comandos útiles:
tophtopfree -hvmstat 1Conexiones activas y estados
Para ver conexiones TCP y su estado (útil para detectar muchas conexiones en ESTABLISHED o TIME_WAIT):
ss -sss -tanp | grep -E ':(80|443)\s' | headSi hay muchas conexiones abiertas y pocos workers disponibles, revisa KeepAliveTimeout y MaxRequestWorkers.
Estado interno de Apache (mod_status)
Para operación diaria, mod_status permite ver workers ocupados, cola y métricas. Debe exponerse de forma restringida (por IP interna o localhost).
Ejemplo de configuración segura (solo localhost):
<IfModule status_module> ExtendedStatus On <Location "/server-status"> SetHandler server-status Require local </Location></IfModule>Luego consulta:
curl http://127.0.0.1/server-status?autoIndicadores a vigilar:
- BusyWorkers/IdleWorkers: si BusyWorkers se acerca al límite con frecuencia, falta capacidad o hay requests lentas.
- ReqPerSec/BytesPerSec: tendencia general de carga.
- Scoreboard: muchos workers en estados de lectura/escritura prolongados puede indicar clientes lentos o backend lento.
Límites y señales de saturación
Señales típicas de que MaxRequestWorkers es bajo o hay requests lentas:
- Latencia sube en picos aunque CPU no esté al 100%.
- Muchos workers ocupados y pocos idle en
server-status. - Conexiones acumuladas en el sistema (muchas
ESTABLISHED).
Señales de que MaxRequestWorkers es demasiado alto:
- RAM se agota, aparece swap, el sistema se vuelve lento.
- OOM killer o reinicios inesperados.
- CPU alta por cambio de contexto (muchos procesos/hilos) sin mejora real de throughput.
Flujo seguro de cambios: medir, ajustar, recargar, verificar
Checklist antes de tocar nada
- Define una métrica objetivo: latencia, errores, uso de RAM, throughput.
- Captura un “antes”:
server-status?auto,ss -s, uso de RAM/CPU, y una prueba simple concurlo un benchmark controlado. - Ten un plan de rollback: copia del archivo de configuración o commit en control de versiones.
Aplicar un ajuste por vez (paso a paso)
Elige un único cambio (por ejemplo, bajar
KeepAliveTimeoutde 5 a 2, o ajustarMaxRequestWorkers).Valida sintaxis:
apachectl -tRecarga (si el cambio lo permite):
systemctl reload apache2Si cambias MPM o módulos críticos, probablemente requieras
restart.Verifica estado:
systemctl status apache2 --no-pagerapachectl -M | grep mpmRepite medición con el mismo método del “antes” y compara.
Revisa logs buscando señales de saturación o errores nuevos (por ejemplo, avisos de límite de workers, timeouts o fallos de compresión/caché).
Orden recomendado de ajustes para principiantes
- 1) Ajustar
KeepAliveTimeoutyTimeouta valores razonables. - 2) Ajustar
MaxRequestWorkerssegún RAM real y observación de Busy/Idle. - 3) Activar compresión para tipos de texto.
- 4) Activar caché en navegador para estáticos.
- 5) Considerar
event(si no lo usas) y caché en servidor solo si el caso lo justifica.