Tunear Apache con cabeza

Voy a cambiar un poco de temática, ya que no solo de MySQL vive el mundo 2.0 😉 Apache, el servidor web estándar en el ecosistema LAMP es uno de los grandes olvidados a la hora de hacer un buen tuning de nuestra plataforma. A continuación voy a explicar una serie de pasos recomendados para lograr el máximo rendimiento de nuestra máquina y al mismo tiempo evitar que esta se caiga bajo un gran pico de visitas. Ni copiar configuraciones de internet ni dejar los valores por defecto son buenas ideas 😉

A la hora de instalar Apache debemos elegir entre dos versiones, aunque generalmente lo elegirá nuestro gestor de paquetes.

  • Apache Worker

Incluido desde Apache 2.0. Utiliza menos memoria y tiene un mejor rendimiento. Se lanzan múltiples procesos y cada uno de estos pueden correr múltiples threads.

  • Apache Prefork

Es el MPM por defecto en Apache 1.3 y Apache 2.0. Es el instalado por defecto si hacemos uso de mod_php, ya que algunos módulos de PHP no son "thread safe". Tiene un rendimiento ligeramente peor que Worker y más consumo de memoria, pero se considera más seguro y estable. En este MPM se lanzan múltiples procesos y se ejecuta un thread por proceso.

Lo lógico sería utilizar Worker, pero vamos a basarnos en el típico ejemplo LAMP que incluye el soporte mod_php, aunque esto no sea lo más óptimo. Por dicha razón vamos a ver como deberíamos ajustar la configuración para un Prefork.

El principal parámetro hardware de nuestros frontales Apache será la memoria RAM. Aquí está todo claro, a más memoria RAM, más procesos se podrán lanzar y más peticiones se podrán atender. Por lo tanto, en primer lugar debemos saber el número de procesos que nuestra máquina puede llegar a soportar. Para ello podemos hacer uso de esta fórmula:

MaxClients = (RAM - tamaño_del_resto_de_procesos)/(tamaño_de_procesos_apache)

Para conocer el tamaño de los procesos de Apache podemos ejecutar un ps:

ps -ylC httpd --sort:rss

Es recomendable que los procesos de Apache ya hayan atentido algunas peticiones, de forma que podamos observar no solo el valor mínimo de memoria de los procesos, si no el máximo que alcanzan una vez atendidas las peticiones.

Entonces, pongamos el siguiente ejemplo:

  • El mayor tamaño que alcanza un proceso de Apache son 98 megas
  • El resto de procesos ocupan 250 megas.
  • Tenemos 32 gigas de ram
MaxClients = (32768 - 250) / 98

Por lo tanto, el número máximo de procesos Apache que se pueden arrancar son 331. Hay que tener en cuenta que esto sería un límite teórico antes de empezar a swapear. Para no estar rozando el límite recomiendo poner algo menos, 310. Con esto definimos claramente cuantos procesos podrán lanzarse para atender a las peticiones y será en función de la RAM que tengamos. Si reducimos el tamaño de los procesos de Apache podremos también aumentar el número de procesos que se pueden lanzar. Para ello, lo mejor es desactivar todos los módulos que no se vayan a utilizar.

En caso de recibir más peticiones de las que pueda atender las encolará y evitaremos que comience a swapear tirando la máquina abajo. Esta cola está definida por el parámetro ListenBacklog que tiene como valor por defecto 511. Como bien dice el manual de Apache, no se recomienda cambiar este valor a no ser que estemos sufriendo un ataque de flood SYN.

Asociado a este parámetro también tenemos ServerLimit, que viene a indicar el valor máximo que podremos poner en MaxClients. ServerLimit tiene por defecto 256, por lo que si aumentamos MaxClient a 310 también tendremos que aumentar ServerLimit al mismo número. De lo contrario el cambio en MaxClients no servirá de nada y estaremos limitados.

Además, tenemos que configurar los siguientes valores:

  • StartServers

Indica el número de procesos que arranca al iniciar el servicio. Este valor no se debe poner demasiado elevado o ralentizará mucho la puesta en marcha del servicio. Como modificar este valor no da ninguna mejora de rendimiento, lo dejamos en el valor por defecto 5.

  • MinSpareServers

Son el número de procesos IDLE que deben existir como mínimo en el servidor. Según vayan recibiendo peticiones Apache lanzará nuevos procesos para mantener este número mínimo. De esta forma los nuevos usuarios que se conecten a la web no tendrán que esperar a que Apache lance un proceso para ellos, si no que siempre se garantizará un mínimo, mejorando la respuesta del servicio. Aún así no es recomendado poner un valor exageradamente grande. Con 30 es suficiente.

  • MaxSpareServers

Es el número máximo de procesos IDLE que existirán en el servidor. Si este número se supera, Apache empezará a cerrar procesos. Poner un valor que sea el doble de MinSpareServers suele dar buenos resultados, siempre y cuando MinSpareServers no tenga un valor absurdamente grande. 60 será suficiente.

  • MaxRequestsPerChild

Con el fin de evitar posibles posibles fugas de memoria en la programación, se suele establecer el número de peticiones máximas que atenderá un proceso antes de morir. Poner un valor pequeño reducirá el rendimiento, ya que Apache tendrá que estár continuamente matando y lanzando nuevos procesos. Un valor recomendado por defecto es 100000, el cual es correcto.

Por lo tanto, el tuning quedaría de la siguiente manera:


StartServer 5
MinSpareServer 30
MaxSpareServer 60
MaxClients 310
MaxRequestsPerChild 10000

Además es recomendable bajar los timeous para evitar tener procesos sin hacer nada.

Timeout 30

Timeout esperará 30 segundos antes de cerrar una petición. Esperará para tres cosas (copy/paste del manual):

1- La cantidad de tiempo que tarda en recibir una petición GET.

2- La cantidad de tiempo entre la recepción de paquetes TCP packets en una petición POST o PUT.

3- La cantidad de tiempo entre ACKs en transmisiones de paquetes TCP en las respuestas.

Por defecto el valor es 300, el cual bajo mi experiencia es realmente exágerado.

KeepAliveTimeout 5

Muchos clientes no ven con buenos ojos la bajada del KeepAliveTimeout, pero tiene una buena razón. En prefork, una petición se queda asociada a un proceso durante todo el KeepAlive, por lo que tener un valor muy alto terminará por agotar las conexiones en algunos picos de carga. En algunos casos incluso es posible aumentar el rendimiento deshabilitando por completo el KeepAlive, pero eso ya dependerá de la página y la programación de la misma. El valor por defecto es 15.

Con estos consejos tendrás una configuración mucho mejor que la de defecto y completamente ajustada a tu máquina. Si ves que el número máximo de clientes es muy poco y no puedes atender todas las peticiones, no lo aumentes a lo loco, mete más máquinas en el balanceador o aumenta la RAM. Lo más importante como ya he indicado es poner valores realistas. En sistemas con mucha carga evitar la swap es la diferencia entre poder acceder a la máquina por SSH o tener que ir al centro de datos a dar un botonazo.

Además es importante tunear los frontales teniendo en cuenta el backend. Si tu MySQL no puede gestionar por memoria más de 200 conexiones, es una estupidez poner en apache 310. Todo tiene que estar equilibrado.