sábado, 28 de marzo de 2015

Explotación teórica de la distribución funcional de la aplicación

He pasado unos días leyendo y poniendo en práctica código RMI de java y de aspectj.

Con respecto a aspectj tuve que actualizar mi NetBeans 7.3 al 8.2 porque el único plugging que encontré no era compatible. Aún sigo luchando ya que el código fuente de varios ejemplos, copiados tal cual, no los compila. Aunque el concepto me está gustando.

Y con RMI pues algo parecido. Una vez programé un ejemplo de forma tosca (editor de texto y consola para compilar,  sin NetBeans), y me funcionó a la perfección. Sin embargo, otro día fui a ejecutarlo y ya no funcionaba. No comprendía el motivo si el código era el mismo, asi que me puse a burcar información sobre los posibles errores típicos al desarrollar sobre rmi.
  • Se ha de ejecutar la aplicación pasándole un parámetro de seguridad:
          java -jar -Djava.security.policy=~/.java.policy gr5.jar

Este fichero específica los permisos de acceso al servidor: aplicaciones, usuarios, puertos ... Pero por ahora simplemente le daremos todos los permisos.

Unas páginas web decían que este fichero debería de ir en la aplicación, otros en el directorio raíz de la aplicación. Opté por la segunda opción pero seguía sin funcionar. Por lo menos ya no me denegaba el acceso a los recursos.
  • Olvidar generar los ficheros por RMIC:
Otro error típico era olvidar ejecutar rmic a todos los archivos .class que entendiesen en su código de java.rmi.remote. Es decir, aquellos que se compartirían entre los servidores y clientes. No encontré manera para hacerlo automáticamente con NetBeans con lo que hay que hacerlo manualmente archivo a archivo. Tampoco funcionaba.

  • Se debe estar ejecutando el servidor RMISERVICE:
Comprobaba que el servidor de nombres rmiservice estuviera en funcionamiento. Nada.

  • RMISERVICE debe ejecutarse en el mismo directorio que se depositan los archivos generados por RMIC.
Ese era el problema.

Estas complicaciones me dieron por pensar que cara a un usuario inexperto simplemente ejecutar la aplicación ya supondría ser un lío.

Normalmente las aplicaciones que comparten información entre sí lo hacen siguiendo el protocolo cliente-servidor. Un único servidor e infinitos clientes. Yo no quiero eso. Quiero que todos puedan ser servidores y clientes a la vez.

Para poder coordinarlos y saber qué servicios presta cada aplicación remota y qué clientes esperan objetos remotos, hace falta un servicio coordinador. Pues incluso este servicio no puede ser asignado explícitamente a un pc (más adelante explico cómo se pasan el testigo).

Mentalmente tengo la estructura de como implementarlo.


La nueva versión:

Dos jar. Uno es el proyecto gr de siempre aunque reprogramado en módulos independientes de servicios y clientes. Y el otro es su lanzador y configurador.


Lanzador:

  1. Se encargará de abrir y cerrar los puertos que precisen los jar.
  2. De definir el perfil de ejecución (cliente, participante pasivo, participante activo y desarrollador).
  3. De lanzar en el directorio correcto rmiservice y pararlo al terminar.
  4. De escribir el fichero .java. policy en el directorio raíz.
  5. De lanzar gr con -Djava.security. policy
  6. De centro unificado de configuración como puede ser de la base de datos (usuario, contraseña, ip, puerto) y rutas.
  7. De actualizar los jar y archivos de rmic (según el perfil)
  8. De comunicarse con gr.
Como trabaja con puertos deberá ejecutarse como root.


La aplicación Gr:

Como dije, en cada pc habrá el mismo código. La misma aplicación, solo que, en unas máquinas se ejecutan unos servicios ofreciendo recursos y otras máquinas ejecutan otros servicios. Se comunicarán entre sí mediante rmiservice.

Para hacerlo dinámico, cuando se conecte otro pc se deberán redistribuir los servicios repartiendo el trabajo entre todos los computadores conectados al sistema, deberá haber una sincronización entre ellos, existencia de la función salida programada para reubicar los servicios entre los restantes, etc., debe de haber un servicio coordinador que controle todo esto entre todos los participantes.

Servicios:

Entre muchos más que irán apareciendo podría mencionar:
- Coordinador.
- Actualizador del software.
- Diccionarios de listas.
- Grafo de dependencias.
- Procesado de Er.
- Diccionario de Er.
- Diccionario de Nombres.
- Autómata.
- Almacén procesado er.
- Generador de código java.
- Gestor de funciones autoprogramadas.
- Etc., junto con sus réplicas.

Peefiles:

- Desarrollador: ejecuta directamente archivos class desde el directorio del proyecto de NetBeans. Sólo puede haber uno. Genera los archivos de rmic. Puede ejecutar servicios como uno más.

- Participante activo: ejecuta la aplicación ya empaquetada en jar. Puede ejecutar servicios y para ello necesita de los archivos generados por rmic.

- Participante pasivo: también ejecuta jar pero siempre como cliente de los servicios.

Estos tres necesitan ser root al ejecutar el lanzador para poder abrir y cerrar los puertos.

- Cliente: este operaría a través de un servicio web que se conectaría al sistema.   Sólo puede hacer consultas y no podrá insertar datos.

Comunicaciones:

Entre el lanzador y el Gr la comunicación es local. No puedo decir que uno sea servidor del otro o cliente. Los dos esperarán peticiones del otro. Por ello lo harán a través de dos sockets. En uno escucha el lanzador y en otro el Gr. Serán únicos. Un lanzador y un gr por máquina conectada.

El servicio coordinador se ejecuta en el Gr. RMI ofrece tanta transparencia que no he llegado a comprender cómo podría un servidor comunicarse con un cliente concreto, con lo que recurro de nuevo a dos sockets. Los demás servicios que se ejecutan sí se comunican con rmiservice.

Los puertos que utilizan para comunicarse entre el lanzador-gr y el coordinador-todos los pcs son dinámicos. Me refiero a que cada lanzador administra estos puertos en función de que si los tiene libres ese computador en concreto y busca otros si no fuese así.

Sin embargo debe de existir un puerto fijo en los que todos los participantes del proyecto estarán a la escucha. Lo denomino puerto oyente. Su única función será la de facilitar la ip y puerto del pc que esté ejecutando en ese momento el servicio coordinador a cualquiera que se conecte. Inmediatamente se desconectarán.

Al querer conectar un pc no podremos saber quién es el coordinador en un momento contreto ya que este servicio no tiene un pc fijo.

Si el que se conecta es nuevo en el sistema distribuido, sólo podrá unirse al grupo si cualquiera de los demás pcs solicitan al coordinador que incluya al pc nuevo con ip x. X estará escuchando por su puerto oyente. Al ingresar recibirá del coordinador una lista de sus compañeros.

Si se trata de un pc que se fue y ahora regresa, cogerá su lista de compañeros y probará si hay alguno conectado y a través del puerto oyente le preguntará que quién es el coordinador actual y le solicitará ingreso.

Funcionamiento:

La idea fundamental es que el sistema (me refiero a todos los pcs ejecutando sus aplicaciones) estén siempre en marcha. Si un pc se conecta (y es participante activo) adquirirá servicios que ejecutará y liberará a otro pc que hasta ese momento lo estaba haciendo. Cuanto más pcs estén conectados más distirbuión habrá con lo que si uno cae la recuperación del sistema es más rápida.

Como comenté hay dos tipos de salidas de un pc del sistema: salida programada y la salida inesperada.

- Salida programada: un participante activo decide que deja el sistema y lo comunica al coordinador. El coordinador pasará todos sus servivios a los demás miembros (junto con sus datos) y una vez terminado comunicará a todos que esos servicios los han asumido otros, para que a partir de ese momento cambien sus configurarciones (ips y puertos). Es ahora cuando se puede marchar el solicitante de la salida.

- Salida inesperada: un participante activo desaparece. El coordinador detecta que se ha perdido la conexión y tiene que conseguir que los datos que poseía se recuperen. El coordinador sabe los servicios que estaba ejecutando, los lanza entre los demás miembros del sistema. El problema son los datos. Al no haber sido una salida programada no se han podido pasar los datos procesados al pc que ha asumido el servicio. Si el servicio que murió contaba con servicio réplíca en otro pc, el coordinador les comunicará a todos que el servicio réplica se ha convertido en el servicio principal y otro tomará el rol de réplica. El nuevo servidor pricipal sí posee los datos y los mandará al nuevo réplica. Sin embargo, si no se cuenta con réplica irremediablemente los datos se han perdido. Dependiendo del servicio se podrá recuperar o no usando el resto de los servicios que lo generaron, por ejemplo, los datos del servidor de diccionarios de listas se generaron a través del servidor autómata, éste último volverá a generarlos y mandarlos. En el peor de los casos el coordinador tendrá que mandar el alto a todos los miembros y reiniciarse desde cero TODO EL SISTEMA.

La primera vez que se ejecute sólo habrá un pc trabajando y será el mío, el desarrollador. Al ser sólo uno y no tener nadie en su lista de compañeros asumirá el rol de coordinador automáticamente. Todos sus servicios tabajarán de forma local y será cliente de sí mismo.

Ahora se van conectando participantes, siempre que el coordinador los ingrese. Se irán actualizando las listas de compañeros a todos según los ingresos. Todos deberán de saber quien es el siguiente candidato a coordinador, lo explico: si yo retiro el pc, se quedan los demás conectados entre ellos pero sin coordinador. Si yo hago una salida programada, los servicios que estuvieran ejecutándose en mi pc los asumirian los demás y pasaría el testigo al siguiente PARTICIPANTE ACTIVO y ahora sería el nuevo coordinador. Si la salida es inesperada todos se conectarán al siguiente participante activo de su lista de compañeros y recuperarán la estabilidad del sistema como se comentó anteriormente.

Como sólo hay un desarrollador y soy yo, cuando compile deberán  mandarse al pc coordinador los jar y ficheros rmic para que éste los distribuya como actualización a todos los miembros del sistema.

El que me vuelva a conectar como desarrollador no implica que recupere el rol de coordinador. Como se ha visto, este servicio se va moviendo entre participantes activos del sistema. Y tienen que ser entre participantes activos porque son los que además de estar actualizados, poseen los archivos generados por rmic y al asumir la coordinación, deberá distribuirlos a los nuevos miembros hasta que el desarrollador genere nuevos archivos.

No hay comentarios:

Publicar un comentario