February 3rd, 2010 Category: Programacion SOA Zend Framework
4 Comments »

En esta serie de artículos voy a tratar de explicar como hacer para que nuestros sitios web sean escalables. Trabaje en varios proyectos donde inicialmente eran webs para unos pocos usuarios pero con el tiempo fueron tomando fuerza y hoy tienen grandes cantidades de visitas y consumo de recursos. El problema es que estos sistemas no tuvieron una gran inversión y no están preparado para el consumo que generar.

Esta situación es muy común hoy en dia. En cualquier libro de escalabilidad, o web, foros, etc. uno de los puntos mas recurrentes es tratar de que las tareas que no requieran una interacción directa con el usuario se ejecuten en segundo plano. También podríamos agregar que lo ideal es que para ejecutar estas acciones en segundo plano se ejecuten a través de un único proceso, la centralización de estas acciones nos permite migrar a otro servidor el dia de mañana en caso de que sea requerido o si el servidor se  cae y poder retomar las acciones sin procesar una vez que el servidor vuelva, y sin que el usuario se haya enterado de este problema. Para hacer esto vamos a aplicar la teoría de colas.

Teoria de colas.

La teoría de colas es según la wikipedia, el estudio matemático de las lineas de espera. Básicamente se encolan procesos en orden de llegada, cuando la aplicacion libera un proceso toma el que entro después, y así sucesivamente. En todos los aspectos de la vida podemos encontrar colas, en el supermercado, cuando vamos a pagar impuestos, cuando vamos a la cancha a ver a Boca, etc.

En nuestro caso, supongamos que tenemos recursos limitados en nuestro hardware y nuestro servidor mysql solo atiende 10 conexiones simultaneas, cuando la visita 11 se conecte a la base de datos, el servidor de mysql hara esperar al proceso hasta que se termine de procesar alguno de los anteriores 10 procesos. En el caso que tengamamos muchas mas visitas el cuello de botella seria mas grande, y puede pasar que no podamos alcanzar a procesar todos los pedidos.

La forma ideal de evitar estos cuellos de botella y evitar que el usuario espere inecesesariamente, es enviar todos los procesos a una cola, esta cola podría contener un objeto serializado, que al correr el proceso que desencole deserealizaria el contenido pudiendo ejecutar la acción del usuario, sin que el usuario tenga que esperar a que se desencolen todos los procesos anteriores, o sobrecargar el servidor.

Podemos usar una única cola. O crear una cola para cada tarea diferente. Una cola para el envió de mails, otra para subir los comentarios de un producto, otra para procesar visitas en el sitio, etc.

Por que usar Colas.


amazon_simple_queue_service

La idea de usar colas es para evitar usar insert/update/delete en la base de datos en tiempo real haciendo al usuario esperar que se termine este proceso antes de mostrarle la pagina cargada para que pueda seguir usando el sitio. Que este encolado no significa que tengamos que esperar 10 minutos para correr un cron y ejecutar los cambios estos cambios pueden demorar un minuto o quizás menos. Pero todo varía dependiendo de la velocidad que necesitemos esa información. También podemos evitar el cron y correr un deamon que ejecute un evento cada vez que recibe un nuevo evento encolado.

Lo ideal seria reemplazar todos los insert/update/delete a la base por un envió a una cola x, para ser procesada en segundo plano. Esto a veces no es posible, en este caso podemos ver otras opciones.

Las colas simplifican nuestro trabajo. Supongamos que tenemos un proceso que envía mails. Este proceso (mailer) recibe un mail de envio, uno de respuesta, un asunto, y mensaje. Con estos datos que recibe el mailer envia mails, sin importar que sea de registro, de recuperación de clave, de aviso que un usuario le envió un correo interno, etc.. Esto hace que un unico lugar tengamos la logica necesaria para enviar un mail.

Supongamos que tenemos 3 servidores en nuestra red. Y solo uno esta configurado para enviar mails correctamente usando sendmailpostfix, da la casualidad que por necesidad el frontend del sitio tuvimos que moverlo o inicialmente esta en un servidor diferente. En nuestro caso lo unico que tenemos que procurar es instalar el mailer en nuestro servidor que si puede enviar mail. Sin importar en que servidor esta instalado el frontend.

Lo mismo podemos aplicar para diferentes procesos. El calculo de estadísticas del sitio, la carga de datos de nuestro backoffice, etc. No tienen porque compartir la misma base, ni el mismo servidor. El proceso de sincronización se puede hacer mediante colas.

Esto nos permite evitar la recarga de la base de datos, cuando la gente de administración necesita saber cuantos usuarios se registraron a las 16:45 del martes anterior, o alguna de esos reportes extraños que a ellos les encanta pedir, y que generalmente significan querys con un costo altísimo en cuanto a procesos. Procesos que necesitamos libres en nuestro frontend para que el usuario navegue sin problemas.

Distintos tipos de colas disponibles para nuestros sistemas web.

En la actualidad existen muchas formas de implementar un servicio de cola en el desarrollo web, los mas comunes son ActiveMq de apacheMemcacheqGearman, etc. Tambien podriamos usar la base de datos para encolar tareas, pero la verdad es que mientras menos abusemos del motor de la base de datos mejor.

apache-activemq-logo

Un sistema de colas con ActiveMq es mas rapido que hacer una conexion y un insert en la base de datos, y consume menos recursos. Despues de todo lo unico que hace es abrir un socket para recibir un string, y guardarlo con un nombre x.
He probado Activemq con mucho exito, pero actualmente estoy usando el servicio de Amazon SQS, el cual esta dentro del abanico de servicios de Amazon AWS, en proximos capitulos espero poder hablarles sobre Amazon S3Amazon cloudfront.
Amazon SQS
amazon_web_services

Con Amazon SQS tenemos nuestro sistema de colas alojado en un servidor de alto rendimiento sin limites de espacio o de procesos a costos bajisimos. Muy facil de implementar y mucho mas facil de usar gracias a Zend Framework, que trae un componente Zend_Services_Amazon_Sqs, con el cual podemos encolar, desencolar de forma muy facil. Por el tema de costo para que se den una idea, yo voy un mes de uso, y no llego a u$d 1 de costo.
Ejemplo de uso con Zend_Service_Amazon_SQS

Encolar un tarea.
$key = 'Mi Clave provista por Amazon';

$secretKey = 'Mi Clave Secreta provista por Amazon';

$data = Zend_Json::encode( $objetoAProcesar );
$sqs = new Zend_Service_Amazon_Sqs($key, $secretKey );
$queueUrl = $sqs->create( 'to_process_message' );
$sqs->send($queueUrl, $data);

Desencolar y procesar.

$config = Zend_Registry::get("config");
$sqs = new Zend_Service_Amazon_Sqs($key, $secretKey );
$queues = $sqs->receive( $queueUrl );
foreach ($queues as $message) {
    // Aca procesamos el mensaje. Si el objeto esta serializado lo deserializamos, y ejecutamos el proceso correspondiente.
    // Si usamos un proceso unico para desencolar todas las colas. No estaria de mas establecer una interfaz para pasar estos objetos.
    $data = Zend_Json::decode( $message );
    print_r($data);
    // Terminado de procesar lo borramos, asi no volvemos a traerlo
    $sqs->deleteMessage( $queueUrl, $message['handle']);
}

Este es un inicio al escalamiento de sistemas web. En el proximo capitulo contenido estatico en un dominio y servidor diferente.

Seguir leyendo