Cambios en la configuración de nginx y php5-fpm en Debian 8 (Jessie)

nginx Hace unos días, tras actualizar la versión de Debian a Jessie, nginx dejó de funcionar correctamente. Servía sin problemas las páginas estáticas pero cuando trataba de interpretar una página php devolvía una página en blanco sin, aparentemente, ningún error. Ni en ficheros de logs, ni por pantalla, ni nada de nada. Parecía más bien un error de php5-fpm que de nginx o, tal vez, de la forma en que se comunican ambos. Probé la comunicación por puertos TCP en lugar de hacerlo por sockets como lo tenía por defecto y el resultado era el mismo… Así que como me pilló entre semana y con mucho trabajo hice una migración de urgencia a apache y lo dejé pendiente hasta que tuviera un ratito libre.
Hoy ya tocaba y la solución ha sido rápida puesto que el “problema” estaba reportado en la bendita lista de bugs de debian desde hace meses, cuando se detectó durante el testing de la nueva versión. Y pongo “problema” entre comillas porque en realidad se trata de un cambio de estructura a partir de la versión 1.6.2 de nginx (la que acompaña a Jessie) y que viene perfectamente documentado en el fichero index.html que se crea por defecto en el directorio /var/www/html (si, esto también cambia y es la nueva ubicación por defecto para las páginas web).
Existe algún otro cambio pero, para resumir, ahora cuando creas un virtual host que necesita usar php en lugar de usar el bloque de configuración que vimos por aquí hace unas semanas tendrás que usar este:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    }

Migrando de Apache 2 a nginx: Virtual Hosts

nginxLos ficheros de definición de Virtual Hosts en nginx se almacenan en directorios muy similares a los de apache. Tenemos un directorio llamado sites-available y otro que se llama sites-enabled y ambos están bajo el directorio principal de configuración que es /etc/nginx. En el primero se deberían de guardar todos los virtual hosts del servidor (estén disponibles o no) y en el segundo aquellos que están activos. La forma correcta de activar o desactivar un Virtual Host debería de ser crear un enlace en el segundo directorio al archivo correspondiente del primero, al igual que en Apache. Para desactivarlo temporal o definitivamente borraríamos ese enlace. La diferencia aquí con apache es que no contamos con comandos similares a los a2ensite y a2dissite que hacen estas operaciones de forma cómoda, pero tampoco se nos van a caer los anillos por hacer un enlace manualmente en línea de comando a estas alturas ¿verdad? Bueno, por si acaso, el siguiente comando realizaría un enlace del fichero de definición de Virtual Host llamado miweb del directorio sites-availabe en el directorio sites-enabled:

ln -s /etc/nginx/sites-available/miweb /etc/nginx/sites-enabled/

Veamos ahora el “esqueleto” de configuración más básico en Apache:

<VirtualHost *:80>
	ServerName www.miweb.com
	ServerAlias blog.miweb.com *.miweb.es
	DocumentRoot /var/www/miweb/
	DirectoryIndex index.php index.html index.htm;
</VirtualHost>

Y su equivalente en nginx:

server {
        listen 80;
        server_name www.miweb.com blog.miweb.com *.miweb.es;
        root /var/www/miweb/;
        index index.php index.html index.htm;
}

Puesto que partimos de que conocemos la sintaxis en Apache no deberíamos de encontrar problemas en entender la de nginx ¿verdad? Sólo un detalle adicional sobre estas líneas. Si tenemos un servidor con más de un interfaz y/o dirección IP y queremos que el servidor web sólo atienda a una de ellas en Apache sustituiríamos la primera línea del ejemplo anterior por esta:

<VirtualHost 123.45.67.89:80>

En nginx haríamos lo propio modificando así la segunda línea:

listen 123.45.67.89:80;

Cualquier configuración adicional del Virtual Host se realizaría incluyendo las directrices adecuadas en el interior del bloque de definición. Veamos algunas de las más comunes. Por ejemplo, si queremos dar una ubicación concreta y separada del lugar donde se almacenan los logs de acceso y error, en Apache lo hacíamos con estas líneas:

CustomLog /var/log/apache2/miweb-access.log combined
ErrorLog /var/log/apache2/miweb-error.log
LogLevel warn

Y en nginx lo haríamos así:

access_log /var/log/nginx/miweb-access.log;
error_log /var/log/nginx/miweb-error.log warn;

El formato del log de accesos por defecto en nginx es idéntico al modo combined de Apache. No obstante, tenemos un montón de opciones adicionales que puedes consultar aquí. Los niveles permitidos para el log de error son, además de warn, error, crit, alert, y emerg.

¿Cómo redefinimos las páginas de error que nos mostrará el servidor web? En Apache usábamos la directiva ErrorDocument:

ErrorDocument 404 /errores/404.html
ErrorDocument 500 /errores/500.html
ErrorDocument 502 /errores/502.html
ErrorDocument 503 /errores/503.html
ErrorDocument 504 /errores/504.html

En nginx usamos error_page:

error_page 404 /errores/404.html;
error_page 500 /errores/500.html;
error_page 502 /errores/502.html;
error_page 503 /errores/503.html;
error_page 504 /errores/504.html;

Si queremos redireccionar varios errores a una misma página podemos hacerlo de esta forma:

error_page 500 502 503 504 /errores/500bis.html;

Veamos ahora como se restringe el acceso a ciertos directorios. En Apache, para denegar el acceso a todo el mundo a un directorio del servidor web lo hacíamos de esta forma:

<Directory /secreto>
        Deny from all
</Directory>

Mientras que en nginx haríamos lo mismo así:

location /secreto {
        deny all;
}

Para restringir el acceso a determinados clientes, en Apache “jugamos” con las directrices Order, Deny y Allow. En nginx no existe ninguna directiva similar a Order. Debemos de poner una a una todas las instrucciones deny y allow que necesitemos. El servidor las analizará una a una y en orden hasta encontrar la primera que “cuadre” con la petición que está atendiendo de forma similar a como se comportaría un cortafuegos. Las siguientes reglas son todas válidas:

location /secreto2 {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

Si lo que queremos es restringir el acceso mediante usuario y contraseña con un fichero generado con htpasswd como hacíamos habitualmente con Apache, podemos hacerlo de forma fácil. El fichero de contraseña lo generamos de la misma forma que ya sabemos (tienes que tener instalado el paquete apache2-utils para contar con esta utilidad) e incluir las siguientes directivas:

location /secreto3 {
    auth_basic "Control de Acceso";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

La línea auth_basic sólo aporta un mensaje de texto que aparecerá en la ventana en la que se nos pide el usuario y contraseña. La directiva auth_basic_user_file es la que marca el lugar y el nombre del fichero que contiene los usuarios y las contraseñas (las hashes de estas, en realidad) autorizadas para acceder al directorio /secreto3 de nuestro Virtual Host.

Si nuestro Virtual Host necesita interpretar páginas en PHP, debemos de pasar estas peticiones al módulo adecuado y tenemos que expecificarlo aquí, y no como ocurría en Apache que se hacía de forma automática con sólo tener activo el módulo php5. Yo uso php5-fpm (aunque existen otras alternativas) y para que funcione debemos de incluir un bloque como este:

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
ACTUALIZACIÓN MUY IMPORTANTE: A partir de la versión 1.6.2 de nginx en Debian 8 (Jessie) el anterior bloque de configuración para php ya no es válido y habría que usar en su lugar este otro.
ACTUALIZACIÓN: PHP-FPM puede usarse con puertos TCP o con sockets. Las ventajas de usar sockets te las cuenta brevemente aquí Javier Terceiro.

En Debian hay que instalar el paquete correspondiente (apt-get install php5-fpm) y asegurarse de que el módulo aceptará las peticiones en la dirección que hemos indicado con la directiva fastcgi_pass. Esto lo comprobamos en el fichero de configuración /etc/php5/fpm/pool.d/www.conf y buscando la línea siguiente:

listen = /var/run/php5-fpm.sock
IMPORTANTE: Si necesitas usar de forma imprescindible ficheros .htaccess este no es tu servidor web. nginx está diseñado para ser rápido y eficiente y no soporta nada parecido. Los .htaccess son cómodos para permitir pequeñas personalizaciones de configuración en servidores compartidos, pero en cualquier otro caso son absolutamente prescindibles y desde el punto de vista de la eficiencia son tremendamente negativos. Piensa que por cada petición que se hace al servidor web, este tiene que recorrer todos los directorios del Virtual Host uno por uno en busca de ficheros de este tipo. Aquí te lo explican muy bien y en este enlace y en este otro tienes herramientas automáticas para ayudarte a migrar las reglas que tengas en ellos a nginx.

Año nuevo, servidor web nuevo. Migrando a ningx

nginx Por aquello de terminar un año y empezar el siguiente con cambios y nuevos propósitos, ayer comencé a migrar la infraestructura que da soporte a este blog a nginx. Si has pasado por aquí en las últimas horas habrás podido experimentar problemas debido a los cambios. Ahora parece ya casi totalmente estable pero dista aún de estar optimizado y habrá que trabajar un poco mas en ello… Y bueno, ya que estamos, feliz año y tal 😉

Apache Tunning (y II). Ajustando el parámetro MaxClients

apache Como ya habíamos hablado por aquí, uno de los parámetros críticos en un servidor Apache es MaxClients, el número máximo de conexiones que es capaz de manejar simultaneamente. Es crítico porque cada tarea de Apache consume una determinada cantidad de memoria y si la suma de la memoria que consumen todos de forma simultanea es mayor que la memoria RAM que la máquina tiene libre comenzará a hacer swapping a disco y, si esta situación se mantiene, corremos un riesgo importante de que se nos quede virtualmente congelada. Una instalación de Apache por defecto toma un valor de 150 para este parámetro y esto es una verdadera burrada para casi cualquier servidor web con menos de 1 Gbytes (o incluso con bastante mas) que use contenidos dinámicos medianamente pesados.

Hace bien poco, buscando por ahí algún enlace para profundizar un poco más en estos temas, me encontré con este artículo de una empresa de hosting donde te proponen un script para ajustar el valor más adecuado a tus necesidades. Había dos cosas que no me gustaban en él script propuesto. Por un lado, tomaban el valor más conservador, es decir, el resultante de dividir la memoria libre entre lo que ocupa el proceso de Apache mayor. En segundo lugar, hacen el cálculo de la memoria libre sin tener en cuenta la que está ocupada por cache o buffers y que podría liberarse en caso de necesidad. Yo le he hecho algunos cambios para salvar ambos puntos y dejarlo un poco más bonito e informativo y me ha salido esto:

#!/bin/bash
clear

# Primero analizamos los procesos de apache funcionando actualmente
LISTA=`ps -aylC apache2 |grep apache2 |awk '{print $8'} |sort -n`

echo "Lista ordenada de la memoria, en bytes, ocupada por los procesos de Apache corriendo en este momento:"
COUNT=0
SUMA=0
for ITEM in $LISTA
do
        COUNT=`expr $COUNT + 1`
        SUMA=`expr $SUMA + $ITEM`
        echo "$COUNT -> $ITEM"
        if [ $COUNT -eq 1 ]
        then
                MENOR=$ITEM
        fi
done

MAYOR=$ITEM
MEDIA=`expr $SUMA / $COUNT`

# Pasamos las cantidades a Kbytes
MENOR=`expr $MENOR / 1024`
MAYOR=`expr $MAYOR / 1024`
MEDIA=`expr $MEDIA / 1024`

echo "El proceso de Apache más grande ocupa" $MAYOR "Kbytes y el menor" $MENOR "Kbytes"
echo "La media de la memoria ocupada por un proceso es de $MEDIA Kbytes"

echo "Detenemos Apache..."
apache2ctl graceful-stop > /dev/null

# Limpiamos los caches y buffers del servidor
sync
echo 3 > /proc/sys/vm/drop_caches

# Calculamos la memoria libre del sistema
FREEMEM=`free -m |head -n 2 |tail -n 1 |awk '{free=($4); print free}'`
echo "La memoria libre del servidor, después de liberar cache y buffers, es de $FREEMEM Kbytes"

echo "Arrancamos Apache de nuevo..."
apache2ctl start > /dev/null

echo "MaxClients debería de estar entre" `expr $FREEMEM / $MAYOR` "y" `expr $FREEMEM / $MENOR`
echo "Usando el valor medio de la memoria ocupada, un valor recomendable de MaxClients sería de" `expr $FREEMEM / $MEDIA`

El script de aquí arriba imprime una lista de la memoria ocupada por todos procesos de Apache activos en el momento de ejecutarlo. Luego toma el mayor, el menor y la media de todos ellos y calcula la memoria libre del sistema. Para ello, antes detiene Apache (con un graceful-stop para no fastidiar a nadie que esté viendo nuestra web en ese momento) y libera los buffers y caches de memoria. Por último, arranca de nuevo Apache y nos da como salida dos valores: una horquilla entre el valor que debería de tomar MaxClient usando el menor y el mayor valor de los procesos tomados en la instantánea anterior y un valor recomendado que sale de usar el valor medio de todos ellos.

Evidentemente no se trata de algo matemático. Como es lógico, ejecutado en diferentes momentos obtendremos valores distintos ya que ni la RAM que usa nuestro servidor es inmutable ni el tamaño de los procesos de Apache es siempre el mismo ni siguen la misma distribución. Pero para darnos una primera idea del valor con el que tenemos que empezar a jugar creo que es bastante válido. Ya me contáis.

NOTA: En algunas instantáneas el valor de memoria ocupado por el proceso más pequeño de Apache puede ser cero, seguramente porque o está creándose o está destruyéndose en ese momento. En ese caso el valor de la horquilla pierde uno de sus extremos. Sería muy fácil modificar el script para que en ese caso tome el segundo valor y divida por un elemento menos, pero ocurre en tan pocas ocasiones que no creo que merezca la pena hacerlo. Al menos no hoy 😉

Instalando memcached en Debian y habilitando su uso con WordPress

herramientas memcached es uno de los sistemas de caché para servidores web más usado. Usa una zona de la memoria RAM del servidor web de tamaño configurable como caché y funciona bien tanto en sitios pequeños y discretos como en grandes sistemas con múltiples servidores. Facebook, Twitter o Youtube, por ejemplo, usan este sistema de cacheado. El 85% de los 20 sitios con más tráfico de Internet lo usan, en realidad. Nada mejor, pues, para estrenar una pequeña sección acerca de sistemas y extensiones de cacheado para apache ¿no?

Partimos para la instalación de una Debian en la que ya tenemos un servidor web apache y la versión 5 de php (paquetes apache2 y php5). Para instalar memcached en una Debian he tenido que recurrir a usar “paquetería” de wheezy (testing) porque parece que hay algún problema de dependencias en la versión estable (squeeze) y la librería de extensión para trabajar con PHP no compilaba correctamente. Así que manos a la obra. El primer paso es instalar el servidor de memcached:

apt-get install memcached

El servicio se instala, como es habitual, en el directorio /etc/init.d y responde a los argumentos start, stop, restart, force-reload y status. En el directorio /usr/share/memcached/scripts existe un script llamado start-memcached que es el encargado de realizar el inicio automático y que toma la configuración del archivo memcached.conf en el directorio /etc. Dentro de este fichero de configuración una de las opciones más interesantes es la que dice a memcached cuanta RAM va a usar como caché. Por defecto son 64M, pero en sistemas con muy poca RAM tal vez nos convenga bajarlo. Mi VPS tiene sólo 512M de RAM y yo he bajado esos 64M a la mitad. Para ello basta con cambiar la línea -m 64 por -m 32 y reiniciar el servicio.

Otra de las opciones interesantes en ese archivo de configuración es la posibilidad de habilitar un archivo de logs que, por defecto, viene deshabilitado. Para ello basta con quitar el comentario a una de las dos opciones que aparecen el el fichero según el nivel de detalle que queramos: -v o -vv. El log se grabará en el fichero /var/log/memcached.log. Esto también es configurable modificando la línea que aparece en el mismo fichero. Y no olvides que para que la opción tome efecto haz de reiniciar de nuevo el servicio de memcached.

El segundo paso sería instalar la extensión de memcached para PHP. Para ello tenemos que instalar los siguientes paquetes:

apt-get install php-pear php5-dev php5-memcached libmemcached10 libmemcached-dev libmemcachedutil2 libhashkit2 libhashkit-dev

Y, a continuación, ejecutar lo siguiente:

pecl install memcached

Si todo sale bien, al final del proceso se nos mostrará un mensaje similar a este:
Instalación del módulo PHP de memcached

La librería debería de haberse creado en el directorio de extensiones de php que se indica al final del proceso y que puedes ver en la imagen anterior (/usr/lib/php5/20100525+lfs) y ya sólo nos resta hacerle caso al mensaje final y añadir la línea extension=memcached.so al final de nuestro fichero php.ini que debería de estar en el directorio /etc/php5/apache2. Reiniciamos apache y, si ejecutamos la función phpinfo veremos una nueva sección:
phpinfo con información del módulo memcached

Para ver información acerca de como está funcionando nuestra cache tenemos un par de opciones más atractivas que inspeccionar el fichero de log que hemos mencionado antes. Una de ellas es usar el script memcached-tools que encontraremos en el directorio /usr/share/memcached/scripts/.

/usr/share/memcached/scripts/memcached-tool 127.0.0.1:11211

El comando anterior muestra información sobre el estado del servicio memcached que hemos instalado en nuestra máquina. Añadiendo al final el argumento stats nos mostrará estadísticas de uso y con el argumento dump realizará un volcado del contenido de la caché por pantalla.

La segunda opción que tenemos es bajarnos de aquí un script hecho en perl y llamado memcache-top. Tienes distintos argumentos para modificar la salida que puedes consultar en la web desde la que te has bajado el script. En la imagen siguiente se muestra con las opciones --cumulative y --commands
ejecución de memcached-top

Y ya sólo nos queda habilitar el uso de memcached desde wordpress. Para ello usaremos Memcached Object Cache que, aunque aparece como cualquier otro en el repositorio de plugins de wordpress, en realidad precisa de una sencilla instalación manual para que funcione. Bajamos el archivo, lo descomprimimos y copiamos el archivo object-cache.php en el directorio wp-content de nuestra instancia de wordpress.

Apache Tunning. Ajustando recursos en un servidor web con poca memoria

apacheInstalar un servidor Apache en un entorno Linux debe de ser lo más fácil del mundo. Configurarlo para que funcione de forma aceptable sirviendo una o dos instancias web también es sencillo. Ajustarlo para que funcione de forma eficiente en entornos escasos de recursos o para que escale bien ante grandes cargas ya es algo en lo que muy pocos se meten. Si siempre has trabajado con servidores compartidos no te habrás dado cuenta de esto último porque alguien te lo ha dado ya hecho. Pero tanto si has tenido que gestionar servidores propios y/o dedicados o pequeños VPS posiblemente hayas tenido algún problema en este sentido. Y si no, creeme: los vas a tener…

La forma en que Apache gestiona la multitarea a la hora de atender a los clientes del servidor web se configura mediante los módulos MPM. Los dos más comúnmente usados son Prefork y Worker pero existe por ahí alguno más. Al instalar apache2 en Debian (y en todas las distribuciones, me atrevería a decir) se instala por defecto el paquete apache2-mpm-prefork y este es el módulo MPM que funcionará por defecto. Para probar con worker basta con instalarlo (apt-get install apache2-mpm-worker en una Debian) y automáticamente desinstalará el otro mpm (sólo puede haber uno en cada momento) y reiniciará el servicio de apache para que los cambios tomen efecto.

La primera pregunta que se nos plantea es, lógicamente, cual elegir. A grandes rasgos la principal diferencia entre ambos es que Prefork crea siempre nuevos procesos para gestionar las conexiones entrantes mientras que con Worker los procesos hijos, a su vez, crean múltiples hebras cada uno de ellos para esta tarea. Tienes información más precisa de como funcionan en los enlaces de hace unas líneas. Prefork tiene a gala ser más estable y funcionar mejor en máquinas escasas de recursos, mientras que Worker presume de ser más escalable y eficiente para servidores más ambiciosos. Para novatos o instalaciones sin necesidades especiales es mejor quedarse con la opción por defecto (Prefork) puesto que, además, incluso algo tan simple como instalar PHP es trivial y habitual con este módulo mientras que hay que “enredar” bastante más para hacerlo funcionar con Worker.

Si el servidor no lo hemos instalado nosotros y queremos saber que MPM está activo basta con recordar que sólo puede haber uno, así que podemos mirar que paquete está instalado (aptitude search apache2-mpm-* en Debian, de nuevo) o interrogar directamente a apache con la opción -l:

root@invernalia:/etc/apache2# apache2 -l
Compiled in modules:
  core.c
  mod_log_config.c
  mod_logio.c
  prefork.c
  http_core.c
  mod_so.c

Pero independientemente del módulo que escojamos, el comportamiento final del servidor web será muy parecido. Pensemos que se trata de un servicio diseñado para atender múltiples peticiones simultaneas de decenas (o centenares, si tenemos una web con éxito) de clientes y hacerlo de forma eficiente y en el menor tiempo posible. Nuestro servidor permanecerá a la espera de estas peticiones y, cuando vayan llegando, destinará a un proceso (o a una hebra de un proceso) a atenderlas. Cuantos más peticiones se cursen de forma simultanea, más procesos/hebras necesitaremos y consumiremos más recursos de la máquina. Sobre todo memoria. Un servidor web se comporta como un insaciable devorador de RAM. Este va a ser el recurso que debemos de aprender a gestionar: la RAM que no se usa cuando se necesita se desperdicia y nos hace perder visitantes o que estos sean atendidos más lentamente. Pero si no controlamos el consumo y el servidor la agota comenzará a hacer swapping a disco y evitar esto es la regla de oro: Si llegamos a este punto lo habremos perdido y, posiblemente, tendrás que reiniciar el servicio (o la máquina, si no tienes tiempo o paciencia) para volver a tomar el control.

Los principales ajustes que necesitamos hacer se encuentran en nueve líneas del archivo /etc/apache2/apache2.conf. A continuación tienes los valores por defecto en una instalación básica de Debian 6: Ten cuidado porque las cinco últimas se encontraran duplicadas en el interior de sentencias condicionales segun el módulo MPM que estemos usando. Las que nos interesan hoy son las que están tras la sentencia <IfModule mpm_prefork_module>.

Timeout 		300
KeepAlive 		On
MaxKeepAliveRequests	100
KeepAliveTimeout   	15
StartServers        	5
MinSpareServers     	5
MaxSpareServers     	10
MaxClients		150
MaxRequestsPerChild	0

Timeout, el primero de ellos, define el tiempo en segundos que Apache esperará a determinados eventos antes de cerrar o abortar una conexión. En servidores con pocos recursos 300 segundos puede ser una cantidad bastante elevada. Reducir ese tiempo sustancialmente ayudará a gestionar mejor la memoria del servidor. Valores de 30 o 40 son adecuados en servidores con pocos recursos. Un valor de 10, incluso, podría mejorar el rendimiento en determinados entornos.

Los tres parámetros siguientes (KeepAlive, MaxKeepAliveRequest y KeepAliveTimeout) definen la posibilidad de usar conexiones persistentes y la forma de tratarlas. En concreto, el número de peticiones que se permitirán sobre cada conexión (MaxKeepAliveRequest) y el tiempo de espera sin peticiones antes de abortarlas. Tener habilitadas este tipo de conexiones reduce sustancialmente la carga del servidor y los tiempos de respuesta y el número de peticiones se puede mantener en torno a 100 en casi cualquier entorno. Es, de nuevo, el Timeout por defecto de 15 segundos el que puede resultar demasiado elevado en servidores con poca RAM y podríamos reducirlo a un valor de 5 segundos o incluso menos.

Los cinco parámetros restantes son los que definen el comportamiento del módulo Prefork. StartServers, MinSpareServers y MaxSpareServers ajustan, respectivamente, el número de procesos apache que se crearan inicialmente, y el mínimo y máximo de estos que mantendremos inactivos a la espera de que lleguen peticiones de posibles clientes. Los procesos inactivos definidos por estos parámetros estarán consumiendo memoria pero nos permitirán dar una respuesta más rápida a los clientes (los procesos están ya listos para usarse cuando llegan peticiones y no hay que perder tiempo en crearlos), así que en un servidor con grandes recursos y que espera cargas elevadas querríamos tener valores más elevados de los que vienen por defecto mientras que en un servidor pequeño podríamos reducirlos todos a, por ejemplo, 3 o 4.

MaxClients es, posiblemente, el parámetro más importante. Define el máximo número de procesos simultaneos que nuestro servidor podrá crear para atender peticiones. Un número más pequeño del que podemos permitirnos desperdiciará memoria y ralentizará las peticiones de muchos clientes (que permanecerán a la espera de que uno de estos procesos se libere para atenderle) mientras que un número demasiado elevado agotará la memoria del servidor y lo obligará a hacer swapping a disco. Y aquí no hay fórmulas mágicas. Lo primero que se nos puede ocurrir es que dividiendo la memoria que tenemos disponible entre lo que ocupa cada proceso de Apache obtendríamos el número que necesitamos, pero el problema es que la memoria disponible es difícil de calcular de forma exacta (ya que, posiblemente, tendremos también un servidor mysql, servicios de correo, etc). Además, los procesos de apache no consumen todos la misma cantidad de memoria. Si tenemos distintas instancias de apache con características muy diferentes la diversidad será aún mayor. Podemos verlo en el siguiente pantallazo de htop tomado de un servidor apache funcionando con varias instancias web diferentes:
Vista de htop en un servidor apache que estamos monitorizando

La columna MEM% nos da el porcentaje de memoria que está ocupando el proceso de apache y, como vemos, tenemos cifras entre 0.5% y 4.2%, es decir, entre 4 y 32 Mbytes (la máquina es un VPS con 768Mbytes). Si aproximamos que disponemos de 600Mbytes disponibles para que apache los use nos saldrían cifras de entre 150 y 18 procesos simultaneos. Una horquilla demasiado grande. Si somos muy, muy conservadores podemos irnos al borde inferior de la horquilla y asegurar que nunca entraremos en zona de riesgo. Podemos también dedicarle tiempo a estudiar el comportamiento medio de nuestros clientes y hacer medias de la utilización de memoria por los procesos de Apache. Lo más rápido para empezar es tomar un valor medio, por ejemplo de un 2.5% o un 3% y ajustar por ahí el número máximo de procesos. Entre 25 y 40 en este caso. El hecho de que hayamos bajado mucho los Timeouts ayudará a que los procesos se liberen rápidamente y se turnen atendiendo a los clientes que están a la espera con lo que no deberíamos de notar demasiado la espera.

Tenemos aún otro parámetro más. MaxRequestsPerChild marca el número de peticiones que atenderá cada proceso antes de reciclarse. El valor por defecto es cero que indica un número indefinido. Poner un número elevado pero no ilimitado ayudará también a que nuestro servidor libere y sanee su memoria de forma regular. Un valor de entre 500 o 1000 podría ser adecuado para nuestra pequeña máquina. Nuestra configuración final podría quedar así:

Timeout 		10
KeepAlive 		On
MaxKeepAliveRequests	100
KeepAliveTimeout   	5
StartServers        	3
MinSpareServers     	3
MaxSpareServers     	4
MaxClients		30
MaxRequestsPerChild	600

No olvides que hay que reiniciar el servicio de apache (service apache2 restart) después de realizar cualquier modificación en este fichero de configuración para que los cambios tomen efecto.

QZHTTP, un servidor web desconocido con 20 millones de sitios

la tierra Todos hemos oído esa cita que dice algo así como que si todos los chinos diesen un salto al mismo tiempo sacarían a la Tierra de su órbita. Pues casi de eso se trata. En el boletín de febrero de Netcraft aparece, así de repente, un servidor web al que llaman QZHTTP y que parece estar relacionado con qq.com la web detrás del, aunque también casi desconocido para nosotros, tercer programa de mensajería instantanea más utilizado. Y aparece con nada más y nada menos que 20 millones de sitios web, situándose como el tercero con más instancias y casi el 10% del total a nivel mundial. Para que os hagais una idea, supone aproximadamente un tercio del total de sitios hechos con IIS, la quinta parte de los implementados con Apache y tres veces más de los que usan el servidor de Google.

Es evidente que estos 20.000.000 de webs no se han migrado así, de la noche a la mañana y en las cifras que publica Netcraft queda claro que no son sitios “robados” a otros servidores. La espectacular irrupción se debe, al parecer, a que hasta ahora Netcraft no incluía en sus estadísticas a QZone, un servicio de Blogs similar a MySpace muy popular en el país.

ACTUALIZACI?N: En los comentarios de este post de Open se ha abierto una interesante conversación acerca de la procedencia de este servidor (un derivado de Apache como ocurre con el de Google, de thhtpd,…) y alguien que se identificó como un empleado de Tencent, la empresa propietaria de qq.com y qzones, afirma que se trata de un servidor web propietario y que nada tiene que ver con ningún proyecto libre.