lunes, 7 de marzo de 2011

Instalación y primeros conceptos. MPM de Apache 2.2.14 en Ubuntu Server LTS 10.04.2.

Vamos a ver la configuración de Apache 2.2.14 en un Ubuntu Server LTS 10.04.2 en varios posts. Este primero nos muestra como se instala y las características iniciales del servidor, en especial MPM (Multi-Processing Module).

Instalación e Instalación

Para instalar Apache 2 con soporte PHP 5, Ruby 1.8 y MySQL 5 solo debemos poner este comando.

$ sudo aptitude install apache2 apache2-utils libapache2-mod-ruby libapache2-mod-php5 php5 php5-mysql ruby libapache2-mod-ruby

Listo. Lo demás es la configuración del servidor. Lo primero que tenemos que ver es que se ha instalado, incluidos módulos. Para ello tenemos la utilidad apache2ctl.

Vamos a ver las características del servidor instalado.

$ apache2ctl -V
Server version: Apache/2.2.14 (Ubuntu)
Server built:   Nov 18 2010 21:19:09
Server's Module Magic Number: 20051115:23
Server loaded:  APR 1.3.8, APR-Util 1.3.9
Compiled using: APR 1.3.8, APR-Util 1.3.9
Architecture:   64-bit
Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/prefork"
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT=""
 -D SUEXEC_BIN="/usr/lib/apache2/suexec"
 -D DEFAULT_PIDLOG="/var/run/apache2.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_LOCKFILE="/var/run/apache2/accept.lock"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="/etc/apache2/mime.types"
 -D SERVER_CONFIG_FILE="/etc/apache2/apache2.conf"

Nos indica las características que usa por defecto en la instalación, también por defecto, de Ubuntu Server. Vemos que usa un fichero de configuración /etc/apache2/apache2.conf. El MPM o Módulo de Multi-Proceso que usa es Prefork. Además es una arquitectura de 64 bits.

Con el siguiente comando podemos ver una lista de los módulos cargados por el servidor apache. Los módulos estáticos (static) son los que se han compilado con apache y no se pueden descargar o cargar dinámicamente sin recompilar, mientras que los módulos compartidos (shared) podemos cargarlos si los necesitamos o descargarlos a voluntad si no los necesitamos sin recompilar. Según la documentación de Apache, este, con los módulos compilados puede obtener hasta un 5% más de rendimiento aunque también indica que no suele valer la pena no tener ninguna flexibilidad en la configuración y si poder cargar y descargar módulos de forma dinámica. Como vemos tiene cargados de forma compartida el módulo de ruby y el de php.

$ apache2ctl -t -D DUMP_MODULES
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
Loaded Modules:
 core_module (static)
 log_config_module (static)
 logio_module (static)
 mpm_prefork_module (static)
 http_module (static)
 so_module (static)
 alias_module (shared)
 auth_basic_module (shared)
 authn_file_module (shared)
 authz_default_module (shared)
 authz_groupfile_module (shared)
 authz_host_module (shared)
 authz_user_module (shared)
 autoindex_module (shared)
 cgi_module (shared)
 deflate_module (shared)
 dir_module (shared)
 env_module (shared)
 mime_module (shared)
 negotiation_module (shared)
 php5_module (shared)
 reqtimeout_module (shared)
 ruby_module (shared)
 setenvif_module (shared)
 status_module (shared)
Syntax OK

El siguiente comando nos indica los Hosts virtuales que está sirviendo el servidor Apache. Como está recién instalado no nos mostrará más que el que usa por defecto. Nos muestra el archivo de configuración que usa cada virtual host, la IP y el puerto usados. Información interesante vamos.

$ apache2ctl -t -D DUMP_VHOSTS
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
VirtualHost configuration:
wildcard NameVirtualHosts and _default_ servers:
*:80                   is a NameVirtualHost
         default server 127.0.1.1 (/etc/apache2/sites-enabled/000-default:1)
         port 80 namevhost 127.0.1.1 (/etc/apache2/sites-enabled/000-default:1)
Syntax OK

El siguiente comando nos indica si tenemos errores en la sintaxis de la configuración de apache y los errores. Vemos que tenemos la sintaxis correcta pero nos indica que no hemos definido un nombre de dominio cualificado para la directiva ServerName del servidor.

$ sudo apache2ctl -t
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName
Syntax OK

Módulo de Multi Procesamiento

Los MPM son módulos como cualquier otro. Estos módulos son los que se encargan de los aspectos más básicos de un servidor web apache como encargarse de enlazar las direcciones IP y puertos del servidor donde se sirve apache, procesar las peticiones y generar procesos hijo para manejar esas peticiones. SOLO puede haber un tipo de módulo MPM cargado en el servidor ya que se compila con el mismo. Apache tiene diferentes tipos de MPM. Al instalar apache2 se instala el MPM prefork por defecto pero podemos especificar un paquete concreto, en vez de apache2 a secas, para instalar otro. En Ubuntu disponemos de apache2-mpm-worker, apache2-mpm-event y apache2-mpm-itk.

Mientras que prefork es más estable y compatible con programas antiguos, event y worker funcionan mejor en entornos escalables.

Prefork

Es el MPM por defecto instalado como hemos visto con los comandos anteriores. Es el mejor para procesar peticiones (requests) aisladas. Si hay problemas con alguna petición no afectaran a otra petición. No usa hilos de ejecución (Threads). Es el más conservador. Es el que configuraremos ya que se instala por defecto.

$ ps auxf
...
root       622  0.0  1.6 147816  8284 ?        Ss   11:02   0:00 /usr/sbin/apache2 -k start
www-data   628  0.0  1.2 148604  6528 ?        S    11:02   0:00  \_ /usr/sbin/apache2 -k start
www-data   630  0.0  1.2 148604  6528 ?        S    11:02   0:00  \_ /usr/sbin/apache2 -k start
www-data   631  0.0  1.2 148604  6528 ?        S    11:02   0:00  \_ /usr/sbin/apache2 -k start
www-data   632  0.0  1.2 148604  6528 ?        S    11:02   0:00  \_ /usr/sbin/apache2 -k start
www-data   634  0.0  1.2 148604  6528 ?        S    11:02   0:00  \_ /usr/sbin/apache2 -k start
...

Vemos como un proceso de control creado por root con PID 622 genera procesos hijo con el usuario www-data (usuario de apache en ubuntu) En concreto hay creados 5 procesos hijo. La diferencia entre un proceso hijo (fork) y un hilo de ejecución (thread) es que los procesos no comparten ciertos recursos entre si, son independientes entre si y se comunican mediante IPC, normalmente pasando por el núcleo, mientras que los threads si comparten recursos como la memoria del proceso que los genera, un proceso multihilo genera threads y hace que compartan estos recursos y se comuniquen entre si, normalmente sin pasar por el núcleo. Los threads o hilos de ejecución son más rápidos que los procesos independientes pero, la ventaja de los procesos hijo es esa, que son independientes. Los procesos hijos en MPM Prefork son los que aceptan las peticiones al servidor. Comprendiendo esto podemos configurar más correctamente las directivas de apache relacionadas con el servidor y MPM (o elegir otro MPM para nuestro caso particular)

En el fichero de configuración principal de apache2 de ubuntu podemos configurar las directivas MPM de todos los tipos de MPM. En este caso vemos las que trae por defecto para MPM Prefork. Más abajo están las de worker y event.

He traducido y explicado un poco cada directiva.

$ sudo vim /etc/apache2/apache2.conf
...
##
## Server-Pool Size Regulation (MPM specific)
## 

# prefork MPM

# StartServers: Número de procesos hijo de servidor que inicia el proceso padre al
# arrancar el servidor. No suele ser necesario cambiar esta directiva ya que Apache
# cambia los valores dependiendo de la carga. Como veíamos en la salida del comando
# ps auxf anterior el proceso padre PID 622 creo 5 hijos (como pone en esta directiva)
#
# MinSpareServers: Número mínimo de procesos que no están manejando una petición, es 
# decir, inactivos (idle) y que están en espera de que lleguen peticiones. Como mínimo
# habrá 5 procesos inactivos en espera. Si, debido a una gran cantidad de peticiones,
# se requiere la creación de nuevos procesos hijo inactivos en espera, el proceso de
# control padre (622) los irá creando a razón de 1 por segundo hasta alcanzar los 5 
# mínimos.
# 
# MaxSpareServers: Número máximo de procesos inactivos en espera. Como máximo 
# tendremos 10 procesos apache hijos inactivos en espera. Si hubiera más de 10
# el proceso padre (622) los mataría hasta obtener el máximo. No puede ser menor que
# MinSpareServers+1. Si, por ejemplo, tenemos miles de peticiones que hacen que se 
# generen muchos procesos hijo (hasta MaxClients) cuando esos procesos hijo queden
# inactivos porque se han satisfecho las peticiones, el proceso padre de control (622)
# eliminara todos los procesos hijo inactivos hasta que queden solo 10 como máximo.
#
# MaxClients: Número máximo de procesos hijo de servidor que se permite iniciar para
# atender peticiones simultaneas. Ha de ser los suficientemente grande como para 
# manejar todas las peticiones simultáneas que esperemos tener y lo suficientemente
# pequeño como para asegurar que tenemos suficiente memoria RAM para todos los procesos
# y evitar el swapping. En este caso, como máximo se crearán 150 procesos hijo lo que
# nos garantiza la atención de 150 peticiones simultaneas o conexiones. Si hay más 
# peticiones se encolarán hasta el máximo de la directiva # ListenBackLog (número 
# máximo de conexiones pendientes en cola) Como máximo puede ponerse 256. La directiva
# ServerLimit puede configurarse para admitir más de 256 procesos hijos simultáneos.
#
# MaxRequestsPerChild: Número máximo de peticiones que un proceso hijo puede servir
# durante su tiempo de vida. No conexiones simultaneas si no el limite de peticiones
# que servirá el proceso hijo antes de ser morir. En nuestro caso tenemos 0 que 
# indica que los procesos hijo no expirarán por el número de peticiones. Si pusiésemos
# 10000, por ejemplo, cuando el proceso hijo sirva 10000 peticiones morirá 
# automáticamente y, si es necesario, el proceso padre generará otro hijo.

<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxClients          150
    MaxRequestsPerChild   0
</IfModule>
...

Worker

El MPM Worker es un híbrido que usa procesos hijo y threads. Un proceso padre puede lanzar varios procesos hijo y estos lanzan hilos de ejecución (threads) para atender peticiones, además de un hilo que se encarga de escuchar las peticiones y pasarlas a otros hilos de ejecución. Como apache mantiene un mínimo de procesos hijo inactivos esperando peticiones, los clientes no esperan la creación de un nuevo proceso hijo fork para atenderle sino que el proceso hijo usa un thread que se encarga de la petición. Al instalar apache2-mpm-worker nos desinstalará el modulo php5 que no es compatible con ese módulo y nos instalará php5-cgi.

$ sudo /etc/apache2/apache2.conf

# worker MPM
#
# StartServers: Número inicial de procesos multihilo de servidor arrancados. El
# número máximo de procesos hijo que se arrancarán será MaxClients/ThreadsPerChild,
# es decir, 150/25 = 6 procesos hijo (con 25 threads cada uno) Inicialmente 2.
# MaxClients: Número máximo de conexiones simultaneas (número máximo de threads en
# todos los procesos)
# MinSpareThreads: Número mínimo de hilos inactivos en espera. 
# MaxSpareThreads: Número máximo de hilos inactivos en espera.
# ThreadsPerChild: Número constante de hilos en cada proceso hijo de servidor. Cada
# proceso hijo de servidor creará 25 hilos en el arranque y no creará más.
# MaxRequestsPerChild: Número máximo de peticiones que un servidor puede servir antes de
# morir. 0 no muere nunca.
# ThreadLimit: Número máximo de threads.

<ifmodule mpm_worker_module="">
    StartServers          2
    MinSpareThreads      25
    MaxSpareThreads      75
    ThreadLimit          64
    ThreadsPerChild      25
    MaxClients          150
    MaxRequestsPerChild   0
</ifmodule>

Event

Este MPM es experimental así que es mejor no usarlo. De hecho, el comando benchmark del siguiente punto hace que el servidor con MPM Event casque con el error apr_socket_recv: Connection reset by peer (104) cuando había procesado 6689 peticiones de 50000.

Se basa en el MPM Worker y sus directivas son iguales. Intenta solucionar el problema HTTP de Keep alive. Cuando un cliente completa la primera petición, el cliente puede mantener abierta la conexión y enviar más peticiones usando el mismo socket. Esto puede mejorar el rendimiento en la creación de conexiones TCP, sin embargo, Apache, tradicionalmente mantiene un hijo completo process/thread esperando los datos de un cliente lo que tiene sus propias desventajas. Para resolver este problema MPM Event usa un único thread dedicado a manejar tanto los sockets de escucha como todos los sockets que están en un estado Keep alive.

ITK

En Ubuntu también podemos instalar MPM llamado ITK que no sale en la documentación de Apache ni que viene normalmente con Apache. Funciona de forma similar a Prefork (sin Threads) La diferencia es que permite limitar cada host virtual (vhost) a un usuario del sistema. Esto nos permite tener varios sitios web en el mismo servidor pero cada uno se ejecutará con su propio usuario del sistema. Así no tenemos que preocuparnos de que un sitio pueda alcanzar archivos de otro sitio web en el mismo servidor. Es un MPM de terceros y es experimental.

Las directivas son iguales a las de Prefork pero añade las siguientes.

  • AssignUserID: Toma dos parámetros uid y gid (o, en realidad, nombre de usuario y nombre de grupo) Especifica con que uid y gid se ejecutara vhost (después de analizar la solicitud, etc.) Si no asignamos un uid se usará el que tenga apache 2 por defecto.
  • MaxClientsVHost: Una directiva MaxClients para el vhost. Maximo de conexiones simultaneas para un único host virtual.
  • NiceValue: Permite bajar la prioridad a algunas peticiones para asignarles menos tiempo de CPU.

AssignUserID y NiceValue pueden ser asignados en cualquier parte de la configuración de apache menos en un .htaccess. MaxClientsVHost solamente se puede asignar dentro de una directiva VirtualHost.

Un poco de testeo

He lanzado contra el mismo servidor, pero con un MPM diferente cada vez, el mismo comando de benchmarking ab. He hecho que se lanzaran 50000 peticiones al servidor con 100 peticiones concurrentes o simultaneas.

$ sudo ab -v -k -n 50000 -c 100 http://localhost/

En MPM Prefork, el test tardo en ejecutarse 102 segundos aproximadamente. En MPM Worker tardó 21 segundos aproximadamente. En ITK 142 sg y Event cascó. Todos los servidores en el mismo hardware. Como vemos hay una diferencia significativa de MPM Worker con los demás MPM.

Ver que directivas tenemos aplicadas al servidor

Para ver cuales son las directivas aplicadas a un servidor podemos usar el módulo info. Para habilitarlo ejecutamos el siguiente comando y reiniciamos el servidor.

$ sudo a2enmod 
Your choices are: actions alias asis auth_basic auth_digest authn_alias authn_anon authn_dbd authn_dbm authn_default authn_file authnz_ldap authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cern_meta cgi cgid charset_lite dav dav_fs dav_lock dbd deflate dir disk_cache dump_io env expires ext_filter file_cache filter headers ident imagemap include info ldap log_forensic mem_cache mime mime_magic negotiation php5 proxy proxy_ajp proxy_balancer proxy_connect proxy_ftp proxy_http proxy_scgi reqtimeout rewrite ruby setenvif speling ssl status substitute suexec unique_id userdir usertrack version vhost_alias
Which module(s) do you want to enable (wildcards ok)?
info
Enabling module info.
Run '/etc/init.d/apache2 restart' to activate new configuration!
$ sudo service apache2 restart

Después, si no estamos en el servidor localhost debemos permitir que se puedan ver los datos en el navegador a nuestro host. Yo tengo el servidor de prueba en 192.168.1.60 y la dirección IP que quiero habilitar es la 192.168.1.35 y solo esa para acceder a la información (a parte de localhost, claro). Para ello configuramos el archivo de configuración del modulo info, así.

$ sudo vim /etc/apache2/mods-available/info.conf

<IfModule mod_info.c>
#
# Allow remote server configuration reports, with the URL of
#  http://servername/server-info (requires that mod_info.c be loaded).
# Uncomment and change the ".example.com" to allow
# access from other hosts.
#
<Location /server-info>
    SetHandler server-info
    Order deny,allow
    Deny from all
    Allow from localhost ip6-localhost
    Allow from 192.168.1.35
</Location>

</IfModule>

Como vemos, denegamos el acceso a todos menos a los permitidos por la directiva Allow from.

Recargamos el servidor, no hace falta reiniciarlo.

$ sudo service apache2 reload

Ahora podemos ir a la dirección server-info del servidor en un navegador y ver la información completa sobre el servidor. Directivas, módulos cargados, opciones de la compilación, etc. como vemos en las pantallas siguientes.



NOTA: A partir de la versión 2.4 de Apache será posible cargar y descargar el MPM de forma dinámica ya que no tendrá que ir compilado junto con el servidor de forma obligatoria, haciendo posible cambiar de uno a otro sin recompilar o reinstalar.
Related Posts with Thumbnails