Rendimiento y operación diaria de Apache: MPM, compresión y caché

Capítulo 9

Tiempo estimado de lectura: 11 minutos

+ Ejercicio

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

MPMModeloVentajasRiesgos/precaucionesRecomendación para principiantes
preforkProcesos (sin hilos)Compatibilidad amplia; aislamiento por procesoConsume más RAM; menos eficiente con muchas conexionesÚsalo si necesitas módulos no thread-safe o dependencias legacy
workerProcesos + hilosMejor uso de memoria; buena concurrenciaRequiere módulos thread-safe; cuidado con límites de hilosBuena opción general si no hay requisitos especiales
eventProcesos + hilos + gestión eficiente de KeepAliveExcelente con muchas conexiones persistentes; reduce hilos “ocupados” esperandoIgual que worker respecto a thread-safetyPreferido 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 mpm
apachectl -M | grep mpm

Deberí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.

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

  • Debian/Ubuntu (ejemplo típico):
a2dismod mpm_prefork mpm_worker mpm_event
a2enmod mpm_event
apachectl -t
systemctl reload apache2

Si 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 con apachectl -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.
  • ServerLimit y ThreadsPerChild (worker/event): definen el máximo estructural de procesos/hilos. MaxRequestWorkers no puede exceder ServerLimit * 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 | head
ps -o pid,ppid,cmd,%mem,rss -C httpd --sort=-rss | head

Observa 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 (antes MaxRequestsPerChild) ayuda a mitigar fugas de memoria reciclando workers. Para empezar, puedes dejar 0 (ilimitado) y, si sospechas crecimiento de memoria, probar valores como 5000–20000.
  • En event/worker, si subes MaxRequestWorkers, revisa que ServerLimit * ThreadsPerChild lo 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 60

Si 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 deflate

Paso 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 apache2

Paso 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 headers

Paso 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_disk

Paso 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-Cookie o 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 MaxConnectionsPerChild si hay crecimiento continuo.

Comandos útiles:

top
htop
free -h
vmstat 1

Conexiones activas y estados

Para ver conexiones TCP y su estado (útil para detectar muchas conexiones en ESTABLISHED o TIME_WAIT):

ss -s
ss -tanp | grep -E ':(80|443)\s' | head

Si 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?auto

Indicadores 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 con curl o 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)

  1. Elige un único cambio (por ejemplo, bajar KeepAliveTimeout de 5 a 2, o ajustar MaxRequestWorkers).

  2. Valida sintaxis:

    apachectl -t
  3. Recarga (si el cambio lo permite):

    systemctl reload apache2

    Si cambias MPM o módulos críticos, probablemente requieras restart.

  4. Verifica estado:

    systemctl status apache2 --no-pager
    apachectl -M | grep mpm
  5. Repite medición con el mismo método del “antes” y compara.

  6. 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 KeepAliveTimeout y Timeout a valores razonables.
  • 2) Ajustar MaxRequestWorkers segú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.

Ahora responde el ejercicio sobre el contenido:

Al ajustar la concurrencia en Apache, ¿cuál es el enfoque más seguro para elegir un valor inicial de MaxRequestWorkers sin provocar falta de RAM?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

Un ajuste seguro parte de medir el consumo (RSS) por worker y definir un presupuesto de RAM para Apache. Con eso se calcula MaxRequestWorkers ≈ RAM_para_Apache / RSS_promedio y luego se afina con monitoreo para evitar swap u OOM.

Siguiente capítulo

Mantenimiento y despliegue seguro de sitios en Apache

Arrow Right Icon
Portada de libro electrónico gratuitaApache desde Cero: Guía Práctica para Principiantes
90%

Apache desde Cero: Guía Práctica para Principiantes

Nuevo curso

10 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.