Registro clave-valor distribuido con Akka Clustering

Hace casi un año, quise poner a prueba cómo de bueno era Akka y lo sencillo que sería crear un registro distribuido con Akka Clustering…

De modo que creé un proyecto de prueba para cacharrear un poco con ello (https://github.com/roclas/akka-distributed-hash – de hecho, he cambiado un par de cosas para dar forma a este post).

Se trata de un registro clave-valor distribuido quese apoya en distintas instancias de Akka con el mismo código, lanzadas en diferentes nodos.

39a0aab0c5b10c7204bc38788dfac55d02140c91f8b07ea4f036d673eec97379

La idea, en esencia, es muy sencilla: lanzas varias instancias de la aplicación al mismo tiempo (especificando puertos distintos como parámetros) y, una vez el primer nodo (se se encuentra en la lista de nodos semilla) ha empezado, puedes conectar tantos nodos del cluster como quieras. Los nodos (en este caso, actores) tienen una clave o hash que se modifica a través de peticiones HTTP, y dichos cambios se propagan por el cluster, de manera que todo nodo acaba por tener la misma información replicada.

Los nodos semilla se especifican en src/main/resources/application.conf

Cuando la aplicación ha arrancado, una de las primeras cosas que hace es intentar unirse al cluster. Para hacer esto, comprueba la lista de nodos semilla e intenta conectarse al primer nodo disponible.

Un dato muy interesante es que si el nodo se encuentra en la primera posición de la lista de semillas, si no es el primer nodo que arrancamos, es muy probable que acabe por generar una isla en el cluster (cuando se encuentra a si mismo como el primer nodo disponible en la lista de semillas sin ser el primero de dicha lista, se conecta a sí mismo creando así una isla). Los nodos que hayan arrancado previamente se encontrarán en su propio subcluster, y los nodos creados a partir de entonces se conectaran a este último, creando así un segundo sub-cluster aislado.

akka clustering graph

He evitado este problema usando un pequeño truco (es probable que haya una forma más elegante de hacerlo):

val selfAddress = Cluster(system).selfAddress
val seeds= system.settings
  .config.getList("akka.cluster.seed-nodes")
System.setProperty("akka.cluster.seed-nodes",
seeds filter(!_.toString.contains(selfAddress.toString)) toString)

Como normal general, podríamos decir que no es una mala idea eliminar la propia dirección de la lista antes de unirse al cluster (así evitamos el problema, pero sin tener que mantener un fichero de configuración distinto por cada nodo que cree, eliminándose a sí mismo de manera programática de la lista).

Una vez que el actor se ha conectado al cluster, pueden recibirse mensajes como:

MemberUp (when a new node joins the cluster)
MemberRemoved (when a node leaves the cluster)

Cada actor tiene un objeto registro y un servidor HTTP ligero (que responderá a peticiones de GET, PUT y DELETE. Las peticiones PUT añadirán elementos al registro interno del actor y las peticiones DELETE los eliminarán.

Y a partir de este punto, podéis hacer tanto como os imaginéis:

  • Cada vez que se modifique el registro de un actor, enviar un mensaje a los compañeros para notificarles el cambio y que así modifiquen su registro interno
  • Después de actualizar el registro, mediante otra petición de actor, mandar un mensaje de vuelta con su md5 para que el actor original compruebe si los cambios se han realizado correctamente.
  • Cuando un nuevo miembro se una al cluster, sincronizar su estado (su registro) con el resto de nodos.

Podéis descargaros el zip  o clonar (git@github.com:roclas/akka-distributed-hash.git) el proyecto, y probarlo por vosotros mismo; es muy sencillo cacharrear con ello y se puede usar como código base para proyectos más complejos (se explica todo en el fichero README.md.

Por último, contadnos que cosas útiles se podrían hacer con Akka Clustering. Forkead, usad y mejorad el proyectoFork, use and improve the project, y sugeridnos que cosas se podrían hacer con esta tecnología tan alucinante.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s