Posts tagged ‘Terracotta’

Introducción a Terracotta (y 2)

En la anterior entrada sobre Terracotta pusimos un pequeño ejemplo con un servidor y tres clientes (un productor de tareas y dos consumidores), aunque todo corriendo en la misma máquina. Además también dejamos el ejemplo dando un feo aviso porque todos los clientes intentaba utilizar el mismo archivo de log.

En esta pequeña continuación vamos a utilizar el mismo ejemplo pero lo iremos mejorando, primero eliminando el aviso de los logs y después utilizando varias máquinas.

terracotta

Para llevar a cabo esta tarea vamos a utilizar un único tc-config.xml, que lo cargará el servidor y los clientes lo tomarán de él. Para ello es necesario arrancar el servidor (start-tc-server) desde el directorio en el que tenemos el tc-config.xml o mediante la opción -f:

start-tc-server.bat -f /ruta/al/fichero/tc-config.xml (será .bat o .sh según estemos en Windows o Unix)

Pero antes vamos a hacer unos cambios en el archivo de configuración. Le vamos a añadir la lista de servidores y le vamos a configurar el directorio de logs en función de una variable de entorno. En la web de Terracotta tenemos una guía y referencia de la configuración en la que podemos ver las descripciones de esos campos y muchos otros.

<?xml version="1.0" encoding="UTF-8"?>
<tc:tc-config xmlns:tc="http://www.terracotta.org/config">
  <servers>
    <server host="169.254.122.220"/>
  </servers>
  <clients>
    <logs>logs-%(tcymu_name)</logs>
  </clients>
  <application>
    <dso>
      <roots>
        <root>
          <field-name>org.tcymu.terracotta.TasksQueue.queue</field-name>
        </root>
      </roots>
      <instrumented-classes>
        <include><class-expression>org.tcymu.terracotta.Task</class-expression></include>
      </instrumented-classes>
    </dso>
  </application>
</tc:tc-config>

Como vemos hemos añadido la sección de servidores y la de clientes. En la de servidores ponemos la dirección IP de nuestro único servidor. En la parte de clientes configuramos el nombre del fichero de logs en función de la variable de entorno tcymu_name.

Ya podemos arrancar el servidor como hemos visto un poco más arriba. También arrancamos el generador de tareas con el comando mostrado a continuación:

dso-java.bat -Dtc.config=169.254.122.220:9510 -Dtcymu_name=creator -cp classes org.tcymu.terracotta.TaskCreator

Las diferencias con respecto al que utilizamos en la primera parte son:

  • Se le pasa la dirección del servidor (con su puerto por defecto en este caso) de la que va a tomar el tc.config.xml.
  • Se le pasa la variable de entorno que se utiliza para nombrar el archivo de logs.

Utilizaremos un comando similar para arrancar el primero de los consumidores de tareas, variando sólo la clase a arrancar y el valor de la variable de entorno para el fichero de logs.

Por supuesto al tomar el tc.config.xml de un servidor a través de una dirección IP podemos arrancar el segundo consumidor en otra máquina (en este caso un openSUSE virtualizado sobre VirtualBox):

dso-java.sh -Dtc.config=169.254.122.220:9510 -Dtcymu_name=resolver2 -cp classes org.tcymu.terracotta.TaskResolver

terracotta2_1

Con esto terminamos esta pequeña continuación.

16 abril 2009 at 12:39 pm Deja un comentario

Introducción a Terracotta: cluster a nivel máquina virtual

En esta entrada voy a presentaros Terracotta. Terracotta se distribuye bajo una doble licencia libre-comercial. Terracotta es una herramienta de cluster a nivel de máquina virtual Java (JVM) o como dicen en su web una memoria distribuida en red o NAM (Network Attached Memory por similitud con Network Attached Storage). Esto quiere decir que podemos compartir objetos o parámetros de objetos entre distintas máquinas virtuales Java, incluso corriendo en distintas máquinas. Esto se logra mediante una arquitectura cliente-servidor (transparente a nuestra aplicación) por un lado y un cargador de clases (ClassLoader) especial. Terracotta también permite “clusterizar” ese servidor que hemos nombrado para entornos de alta disponibilidad. Señalar también que Terracotta no utiliza la serialización Java si no un intercambio de los parámetros que se modifican en cada caso, de forma que se minimice el tráfico en la red. Tras esta pequeña introducción teórica vamos a ver un pequeño ejemplo. Creamos una pequeña clase que representa una tarea a realizar por nuestra aplicación:

package org.tcymu.terracotta;

public class Task {
	private long duration;
	private long id;

	public Task(long id, long duration) {
		this.id = id;
		this.duration = duration;
		System.out.println("Nueva tarea " + id + " de duracion " + duration);
	}

	public void run() {
		System.out.println("Iniciando tarea " + id + " de duracion " + duration);
		try {
			Thread.sleep(duration);
		} catch (Exception e) {}
		System.out.println("Finalizando tarea " + id);
	}

}

y una que representa la cola con las tareas que hay que realizar:

package org.tcymu.terracotta;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TasksQueue {
	private static TasksQueue instance;
	private BlockingQueue queue = new LinkedBlockingQueue(5);

	public static TasksQueue getInstance() {
		if (instance == null) {
			instance = new TasksQueue();
		}
		return instance;
	}

	private TasksQueue() {
	}

	public BlockingQueue getQueue() {
		return queue;
	}
}

Finalmente, creamos otras dos clases, una crea tareas y otra las resuelve:

package org.tcymu.terracotta;

import java.util.Random;

public class TaskCreator {
	private static long id = 1;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Random random = new Random();
		TasksQueue tasksQueue = TasksQueue.getInstance();
		tasksQueue.getQueue().clear();
		while (true) {
			//Duracion aleatoria 1 a 10 segundos
			long duraction = (random.nextInt(10) + 1) * 1000;
			try {
				tasksQueue.getQueue().put(new Task(id++, duraction));
				Thread.sleep(3000); //Una tarea cada 3 segundos
			} catch (InterruptedException e) {}
		}
	}
}
package org.tcymu.terracotta;

public class TaskResolver {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TasksQueue tasksQueue = TasksQueue.getInstance();
		while (true) {
			try {
				Task task = tasksQueue.getQueue().take();
				task.run();
			} catch (InterruptedException e) {}
		}
	}
}

Como podemos ver, son clases normales, sin nada especial que resaltar. Eso sí, si ejecutamos el creador de tareas o el consumidor, lógicamente vemos que no se relacionan entre ellas. Las vamos a relacionar mediante Terracotta, y el vínculo entre ellas será la cola que es el elemento común.

Lo primero que necesitamos es descargarnos la edición libre (ES) desde la sección de descargas de Terracotta. Yo he utilizado la versión ES 2.7.3. Aparte de eso, lo único que he hecho es añadir el directorio bin de Terracotta al path para poder utilizar sus comandos más cómodamente. Como hemos dicho, Terracotta necesita un servidor y es el momento de arrancarlo. Para ello abrimos una consola y ejecutamos el script start-tc-server (está en el directorio bin que hemos añadido al path y existe en versión windows y versión unix/linux).

terracotta_1

Ahora creamos el archivo de configuración que le indica a Terracotta cuáles son los que se guardan en la memoria de red. El fichero lo llamo tc-config.xml y lo voy a poner en el raíz  de mi proyecto Eclipse, aunque podría ir en cualquier sitio:

<?xml version="1.0" encoding="UTF-8"?>
<tc:tc-config xmlns:tc="http://www.terracotta.org/config">
  <application>
    <dso>
      <roots>
        <root>
          <field-name>org.tcymu.terracotta.TasksQueue.queue</field-name>
        </root>
      </roots>
      <instrumented-classes>
        <include><class-expression>org.tcymu.terracotta.Task</class-expression></include>
      </instrumented-classes>
    </dso>
  </application>
</tc:tc-config>

Primero le indicamos el objeto raíz que forma el cluster (cualquier cosa que se obtenga a partir de ese objeto también forma parte del cluster). También le indicamos las clases que Terracotta tiene que controlar (instrumented-classes), la clase Task al formar parte del cluster debe ser instrumentalizada. Para arrancar el creador de tareas ejecuto el siguiente comando en una consola situada en el raíz del proyecto:

dso-java -cp classes org.tcymu.terracotta.TaskCreator

El comando dso-java es un comando de Terracotta que tras preparar el entorno para la ejecución en cluster llama al comando java de manera normal. Por eso con esa línea estamos fijando el classpath (a classes en este caso) y ejecutando la clase TaskCreator.

Hay que señalar que dso-java (y también  start-tc-server) toman el fichero tc-config.xml del directorio desde el que se llama (aunque hay otras opciones de trabajar con los ficheros de configuración de Terracotta). Por eso ejecuto el comando lo he ejecutado en el raíz del proyecto donde está el tc-config y el directorio classes con la compilación de las clases que hace Eclipse. Sin embargo el servidor lo he ejecutado desde cualquier consola, de forma que arranca sin tomar ese tc-config. El resultado de la ejecución en el que podemos ver cómo se crean tareas es:

terracotta_2

Y ahora arrancamos el consumidor de tareas, también desde una consola situada en el raíz del proyecto. Utilizamos el siguiente comando:

dso-java -cp classes org.tcymu.terracotta.TaskResolver

terracotta_3

Podemos ver que lo único que cambia es la clase a ejecutar. Nos aparece un aviso respecto a que el archivo de logs está en uso, lo que se debe a que hemos arrancado varios nodos en la misma máquina. De momento no me preocupo por ello.  Nuestro consumidor empieza a resolver tareas, aunque muy probablemente no a una velocidad suficiente. Es el momento de escalar nuestra aplicación y arrancar un segundo consumidor. Abrimos otra consola nuevamente en el directorio raíz y volvemos a ejecutar el comando de arranque del consumidor. Ahora vemos que los consumidores van resolviendo tareas simultáneamente, lo que sin duda es una forma bastante fácil de escalar.

Con esto termino este pequeño ejemplo que no pretende nada más que mostrar las bondades de Terraccotta con un ejemplo funciona. Más adelante ya lo complicaremos.

31 marzo 2009 at 6:31 pm 1 comentario


Mi perfil

View Miguel Orbegozo's profile on LinkedIn

Feedjit

Feeds

Otros…

BlogESfera Directorio de Blogs Hispanos - Agrega tu Blog

Bitacoras.com

Add to Technorati Favorites