Debido a mis limitaciones técnicas, voy a utilizar lo siguiente:
- nginx como balanceador web
- php como lenguaje de programación
- apache como servidor web
- memcached, la estrella en todo esto.
todo esto sobre Debian Wheezy.
Cuando se tiene una granja de servidores web para una aplicación, se requiere que la información almacenada en la sesión de usuario se mantenga y pueda ser accedida por cualquiera de los servidores, incluso, cuando alguno de ellos falla. Existen varias técnicas, algunas más complicadas que otras. Yo voy a hablar de como hacerlo con memcached.
Escenario
El escenario descrito como bloques funcionales será el siguiente:- Un balanceador web (nginx)
- Dos servidores web (apache + php)
- Tres instancias de memcached
El blanceador (nginx) tendrá como servidores de backend a los dos apaches que son los que alojarán el código php del supuesto sitio web. Para efectos de esta demostración de concepto, todos estos bloques funcionales estarán corriendo en la misma máquina :) Espero que esto no lleve a confusión.
Comenzamos con la instalación y configuración de los bloques funcionales.
Balanceador web (nginx)
Instalamos nginx de la siguiente manera:# aptitude install nginx
Nos vamos al directorio /etc/nginx/sites-available y creamos el archivo mem-test que tendrá la configuración de nuestro balanceador. Este es el contenido del archivo:
upstream mem-test { server 127.0.0.1:8081; server 127.0.0.1:8082; } server { listen 8080; location / { proxy_pass http://mem-test; } }
Como se aprecia, voy a tener dos servidores web escuchando en los puertos 8081 y 8082. Será mi "granja" que después configuraré. La sección siguiente le dice a nginx que escuche en el puerto 8080 (mi blanceador) y que todo lo que llegue lo pase a los servidores descritos arriba.
Nos vamos al directorio /etc/nginx/sites-enabled, creamos un link simbólico que apunte al archivo creado
# cd /etc/nginx/sites-enabled # ln -s /etc/nginx/sites-aviable/mem-test
y borramos el link "default".
Listo, ya tenemos nginx configurado como balanceador, nos queda arrancarlo:
# service start nginx
No deberían salir errores si se siguieron los pasos descritos.
Servidores web (apache + php)
Instalamos apache y php de la siguiente manera:# aptitude install apache2 libapache2-mod-php5
Configuramos dos virtualhosts en apache añadiendo
NameVirtualHost *:8081 NameVirtualHost *:8082 Listen 8081 Listen 8082
al archivo /etc/apache2/ports.conf y creamos dos archivos de configuración llamados server01 y server02 en /etc/apache2/sites-available. Estos son los que yo creé:
server01
<VirtualHost *:8081> ServerAdmin webmaster@localhost DocumentRoot /var/server01 <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/server01> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
server02
<VirtualHost *:8082> ServerAdmin webmaster@localhost DocumentRoot /var/server02 <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/server02> Options Indexes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>Creamos los directorios /var/server01 y /var/server02 que alojarán las páginas de nuestros sitios web
# mkdir /var/server01 /var/server02
Activamos los sitios:
# a2ensite server01 server2
Memcached
Instalamos memcached y el soporte de php para memcache# aptitude install memcached php5-memcache
Creamos los tres archivos de configuración de las instancias de memcached
cp /etc/memcached /etc/memcached_inst01.conf cp /etc/memcached /etc/memcached_inst02.conf cp /etc/memcached /etc/memcached_inst03.conf
En mi escenario, estos son los puertos en los que escuchan las diferentes instancias de memcached:
- inst01: 11211
- inst02: 11212
- inst03: 11213
Eso se hace modificando la línea donde dice "-p" en cada archivo de configuración y colocando el valor correspondiente.
Arrancamos memcached
/etc/init.d/memcached start Starting memcached: memcached_inst01. Starting memcached: memcached_inst02. Starting memcached: memcached_inst03.
Podemos comprobar que están corriendo con un ps.
php5-memcache
Para que php use memcache para almacenar las sesiones, hay que realizar lo siguiente:En el archivo /etc/php5/apache2/php.ini colocar:
session.save_handler = memcache session.save_path = "tcp://127.0.0.1:11211,tcp://127.0.0.1:11212,tcp://127.0.0.1:11213"
y en el archivo /etc/php5/apache2/conf.d/20-memcache.ini añadir:
memcache.session_redundancy=4
Nota muy importante, el valor de memcache.session_redundancy debe ser igual al número de instancias de memcached +1.
Reiniciamos el apache:
# service apache2 stop # service apache2 start
Solo falta escribir un código de prueba. En cada uno de los DocumentRoot de los virtualhosts, creamos un archivo llamado index.php como el siguiente para comenzar:
<?session_start() ?> <html> <head> <title>Server01</title> </head> <body> Server01 <? if(empty($_SESSION['contador'])) {?> <p>El contador está vacío</p> <? }else {?> <p>Valor actual del contador: <? echo $_SESSION['contador'];?></p> <p>Sumamos 1 al contador</p> <? $_SESSION['contador'] = $_SESSION['contador'] + 1;}?> </body> </html>
Hay que tener en cuenta que cada index.php debe reflejar el nombre de su respectivo servidor virtual.
Ahora, con cualquier navegador (yo usé lynx) podemos probar con la URL
http://localhost:8080
y recargamos la página varias veces.
Esta prueba debe mostrar _siempre_ que la variable "contador" está vacía lo cual es lógico. Lo único que debería variar es el nombre del servidor, que debe alternarse entre server01 y server02 con lo que sabemos que el balanceador está funcionando.
Una vez confirmado esto, modificamos el index.php de server02 para que quede de esta manera:
<? session_start() ?> <html> <head> <title>Server02</title> </head> <body> Server02 <? if(empty($_SESSION['contador'])) {?> <p>El contador está vacío</p> <? $_SESSION['contador'] = 1; }else {?> <p>Valor actual del contador: <? echo $_SESSION['contador'];?></p> <p>Sumamos 1 al contador</p> <? $_SESSION['contador'] = $_SESSION['contador'] + 1;}?> </body> </html>
Al recargar la URL debemos observar como el contador comienza a incrementarse después de haber contactado a server02.
Para probar que se mantienen las sesiones al ocurrir un fallo, procedemos a parar las instancias de memcached teniendo en cuenta que hay que dejar el menos una corriendo.
# /etc/init.d/memcached stop inst01Al recargar la URL deberíamos observar que el contador se sigue incrementando demostrando así que tenemos alta disponibilidad con las sesiones web.
Esto es solo una demostración de concepto pero se evidencia la flexibilidad y redundancia de memcached para guardar y mantener la información de las sesiones web.