Archive for marzo, 2009

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

Apache Felix Web Console

En este blog ya ha aparecido Apache Felix en varias de las entradas relacionadas con OSGi. Hemos visto varios de sus comandos e instalado y arrancado módulos. Siempre con su interfaz de línea de comandos que es la que se utiliza normalmente.

Pero dando una vuelta por la web de Felix, he visto el subproyecto Apache Felix Web Console, que como su nombre indica pretende ser una interfaz web para Felix. En esta entrada os cuento cómo la he hecho funcionar. Para abrir boca os muestro el resultado final.

felixwebconsole_1_640x470

En la página del subproyecto aparece casi toda la información necesaria. Se nos indica que la única dependencia obligatoria es tener un Http Service instalado y nos muestra algunas alternativas. El Http Service de Felix todavía no tiene una versión publicada por lo que yo me decidí por OPS4J Pax Web (por cierto, curioso e interesante el proyecto OPS4J en su conjunto).

Tras descargar pax-web-service-0.5.2.jar (como se explica en su sitio web, el pax-web-service incluye ya el jetty y todo lo necesario), lo instalé en Felix (install file:////d:/felix-1.4.0/bundle/pax-web-service-0.5.2.jar) y lo intenté arrancar, pero me apareció el siguiente error:

org.osgi.framework.BundleException: Unresolved constraint in bundle 22: package; (package=javax.servlet)

Esto se soluciona si descargamos e instalamos el módulo org.osgi.compendium-1.2.0.jar desde la web de Felix. Este módulo es sólo una agrupación de clases de OSGi. De hecho es casi lo mismo que contiene el módulo osgi.cmpn.jar descargable desde la web de OSGi (requiere registro). Tras instalarlo tendremos esa dependencia cumplida y podremos arrancar el OPS4J Pax Web.

Ahora podemos descargar el módulo con la consola web (org.apache.felix.webconsole-1.2.2.jar), instalarlo y arrancarlo. Un apunte respecto a la configuración del módulo. En el archivo config.properties de nuestra instalación de Felix, aparece una propiedad (org.osgi.service.http.port) que realmente es configuración del servicio de Http. En ella se indica el puerto a escuchar (el 8080 por defecto).

Yo no he dado valor a ninguna otra de las propiedades de configuración, ni de Pax Web Service ni de We Console.

Ahora apuntamos nuestro navegador a http://localhost:8080/system/console (la ruta se podría modificar mediante configuración) y entramos con admin/admin (también modificable por configuración) y ya vemos el aspecto de nuestra consola web.

En la pestaña de módulos («bundles») vemos que podemos parar, arrancar, instalar actualizar o desinstalar módulos. También podemos ver información detallada sobre cada módulo (versión, paquetes exportados e importados, etc.). En otras pestañas podemos ver el estado de la configuración («Configuration Status»), ver la licencia de los módulos instalados («Licenses»), tener acceso a una línea de comandos en la página («Shell») o ver información y controlar el sistema en sí («System Information»).

También tenemos una pestaña para la gestión de repositorios de módulos. En el mismo archivo config.properties que hemos comentado con anterioridad se añade el repositorio de Felix (propiedad obr.repository.url). Yo para que se pudiera conectar al servidor he tenido que añadir durante el arranque las propiedades del proxy tras el que estoy (-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttp.proxyAut=user:pass), tal como se explica en la página del OSGi Bundle Repository de Felix. Desde esta pestaña se pueden añadir nuevos repositorios o instalar módulos desde los repositorios instalados.

felixwebconsole_2_640x472

Por último, señalar que tenemos otras pestañas («Configuration», «Deployment Packages» o «Event Admin») cuya funcionalidad se ve limitada si no tenemos el servicio correspondiente instalado. Pero para hablar de esos servicios ya habrá otras entradas.

16 marzo 2009 at 9:49 pm Deja un comentario

Personalizando Blueprint CSS

Hace ya un tiempo escribí una pequeña iniciación a Blueprint en este blog. Blueprint es un framework CSS que nos facilita el diseño sencillo de nuestras páginas web. En dicha entrada ya comenté que se podía modificar la configuración por defecto de Blueprint y en esta entrada voy a explicar cómo hacerlo.

Para poder llevar a cabo esta tarea necesitamos tener instalado Ruby. Yo he utilizado la versión 1.8.6, en concreto la 1.8.6-25 que es la que tengo instalada.

En una consola nos situamos en el directorio lib dentro del de instalación de Blueprint. Si tecleamos ahora ruby compress.rb -h obtenemos una pequeña ayuda.

blueprint2_1_480x238

Podemos ver que hay opciones para indicarle el directorio de salida o el número y tamaño de las columnas. Ejecutamos ahora el comando:

ruby compress.rb -o "d:/tmp/testblueprint" --column_count=10 --column_width=60 --gutter_width=20

Con este comando se nos crean los archivos de Blueprint (screen.css, print.css e ie.css) en la carpeta destino (d:/tmp/testblueprint), utilizando los tamaños indicados. Debemos tener en cuenta que el ancho total responde a la fórmula siguiente, en la que Ncol es el número de columnas, Wcol el ancho de dichas columnas y Wgut el ancho de las separaciones.

ancho = (Ncol * (Wcol + Wgut)) - Wgut

Sobre el comando, destacar que la ruta de salida se la he tenido que pasar sin el «=» aunque la ayuda lo pone con «=».

Otra opción que podemos utilizar es pasarle un «namespace», de forma que si le pasamos el nombre «tcymu-» por ejemplo (mediante la opción -n tcymu- en la que también he tenido que quitar el «=»), los nombres de las clases generadas pasan de ser del estilo de «span-3» a «tcymu-span-3», es decir les añade como prefijo el nombre pasado, lo que puede sernos útil para evitar conflictos con otros css.

También hay que tener en cuenta, que a la hora de crear los archivos css, Blueprint buscará en el directorio destino (d:/tmp/testblueprint en nuestro ejemplo) los archivos my-screen.css, my-print.css y my-ie.css y añadirá su contenido a screen.css, print.css y ie.css respectivamente.

Por último, vamos a ver la otra opción que nos indica la ayuda del script, que es -p o --project. Para utilizar esta opción necesitamos un archivo settings.yml en el directorio en el que se encuentra el compress.rb.

En ese archivo (que sigue el formato YAML) se definen una o más configuraciones con las que ejecutar el compress. Se pueden definir todas las características vistas anteriormente. Por ejemplo:

tcymu:
  path: d:/tmp/testblueprint
  namespace: tcymu-
  custom_css:
    screen.css:
      - tcymu.css
	  - tcymu_2.css
  custom_layout:
    column_count: 10
    column_width: 60
    gutter_width: 20
  plugins:
    - fancy-type
    - buttons

Esta configuración hace casi lo mismo que las opciones de línea de comandos utilizadas hasta ahora. Vemos el directorio de salida (path), el prefijo (namespace) y las dimensiones de la rejilla (custom_layout, que engloba a column_count, column_width y gutter_width).

Las diferencias son:

  • La opción custom_css mediante la que modificamos el archivo css que se busca para agregar a cada opción. En este caso el contenido de tcymu.css y de tcymu_2.css (en el directorio de salida) se añade al final de screen.css en lugar del my-screen.css por defecto.
  • La opción plugins añade el css que compone los plugins indicados (se encuentran en blueprint/plugins dentro del directorio de instalación de Blueprint). Además de los que aparecen en el directorio señalado, podemos ver el listado de plugins de Blueprint.

Sin duda esta personalización hace mucho más flexible este ya de por sí buen framework.

9 marzo 2009 at 7:56 pm Deja un comentario

Entradas anteriores


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