Get Firefox

Firefox 3.5

stopsoftwarepatents.eu petition banner Manifiesto por la liberación de la cultura 
No a la traza privada
Últimos cambios
Últimos Cambios
Vote for Public Maps - Reject INSPIRE! Geocaching
Mi estado actual en Jabber/XMPP: - jabberES - jabber.org

Fase 2: Despliegue de la Gestión Distribuída

Última Actualización: 26 de Marzo de 1.999 - Viernes

La fase 2 del proyecto ESNET consiste en:


¿Qué significa "distribuir" y por qué es necesario?

Tal y como se explica en el Libro Blanco de IRC ESNET, una red de IRC típica suele tener una estructura centralizada desde un punto de vista administrativo y de control, con un único nodo de control -o, como mucho, dos- encargado de supervisar toda la red. Este esquema plantea numerosos problemas, muchos de ellos ya comentados en el citado documento:

Disponer de nodos de control centralizados tiene, no obstante, una serie de ventajas a destacar:

Sopesando pros y contras parece razonable el intentar, al menos, la adopción de un esquema distribuído en aquellas áreas que más lo necesitan:


Distribución de la Base de Datos

Un esquema distribuído de las características propuestas implica replicar las bases de datos básicas. Dicha replicación puede hacerse de varias formas, que se describirán dentro de un momento.

En el diseño inicial de la Fase UNO de ESNET se contemplaba la posibilidad de instalar ya en ese paso un control de clonos distribuído, cuyo funcionamiento se explicará en una sección posterior. En ESNET el número de clonos está limitado a DOS (y es posible que se limite a UNO en el futuro, si el esquema de control de nicks funciona como debe). No obstante siempre existen casos, como los cibercafés o las máquinas multiusuario de las universidades, donde hay que permitir un número mayor de conexiones simultaneas. Dichas "excepciones", en la terminología de IRC-Hispano, se denominan "I-Lines".

Es previsible que el número de "I-lines" que el sistema tenga que manejar sea reducido (menos de 50), al menos en una primera fase. Dado esto, sería posible utilizar el siguiente esquema de replicación:

  1. No es necesario que los nodos almacenen ninguna base de datos en disco.

  2. Cuando hay un "netjoin" (se une un servidor que estaba en split), ambos pasan al otro lado del enlace todas sus "I-lines" durante el "NetBurst".

  3. Cuando algún IRCop da de alta una nueva "I-Line", lo hace sobre el nodo de control central OLIMPO. Dicho nodo recibe el comando, lo valida, comprueba que el usuario tenga privilegios para efectuar ese alta, guarda un log, actualiza su base de datos en disco, y propaga el alta hacia su HUB.

  4. Las bajas de "I-Lines" se gestionan de la misma manera. Tanto altas como bajas serán operaciones muy infrecuentes.

  5. Cuando un nodo recibe una "I-Line" que ya tiene en su memoria, la ignora.

  6. Cuando un nodo recibe una "I-Line" que NO tiene en memoria, almacena una copia, y la propaga por el resto de sus enlaces.

  7. Si un nodo recibe el borrado de una "I-Line", la propaga a todos sus enlaces y, si la tenía, borra la "I-Line" local.

  8. Si el nodo de control recibe una "I-Line" que no consta en su base de datos en el disco, envía una cancelación. Esto puede darse, por ejemplo, cuando se ha borrado una "I-Line" pero había servidores en split.

Estudiando la casuística se puede comprobar que el esquema propuesto funciona perfectamente. Cuando un servidor arranca no tiene ninguna "I-Line" definida, por lo que no permitirá más de dos clones, pero en cuando se enlace con otro nodo, éste le suministrará la base de datos actual. Cualquier desincronía en la base de datos se soluciona tras un "netjoin" y la consiguiente cancelación por el nodo de control.

Aquellos famirializados con el mundo de las redes, reconocerán en este esquema un protocolo muy similar al protocolo de rutado RIP.

Lamentablemente este esquema, aunque muy elegante, no se presta al manejo de grandes bases de datos. Cualquier "netjoin" implica el viaje de la base de datos completa en ambas direcciones durante el "netburst", y cuando ésta crece en tamaño (por ejemplo, porque contiene también la base de datos de nicks), la sobrecarga lo convierte en inviable.

Cualquier "netjoin" empieza con un intercambio de claves y una identificación mutua. Es posible, por tanto, que en esa etapa se intercambien también el número de versión de sus bases de datos respectivas. Cada registro de la base de datos se numera en una sucesión estrictamente monótona creciente. Nunca se borran registros: el borrado de un registro consiste en la entrada de un registro posterior que indica el borrado del primero. Los mismo para las modificaciones.

Según esto es posible que el nodo con la base de datos más moderna actualice al otro sin más que enviar los registros nuevos (dichos registros pueden incluir, como se ha comentado, modificaciones y bajas de los ya existentes). Para evitar un crecimiento ilimitado de la base de datos, se realizarán operaciones de "compromiso" de forma periódica.

El funcionamiento actualizado sería el siguiente:

  1. En un "netjoin", ambos extremos intercambian su número de versión de la base de datos.

  2. El extremo con el valor más bajo inicia su parte del "netburst" normal, sin transferir la base de datos.

  3. El extremo con el valor más alto comprueba el valor del otro extremo con el registro correspondiente al último compromiso. Si el otro lado es más reciente, transfiere los registros nuevos en el "netburst".

  4. Si hay un compromiso más reciente (el otro extremo se lo habrá perdido en un split), envía al otro extremo:

    1. Una orden de borrado de la base de datos.
    2. La lista de registros inferiores o igual a la versión del otro extremo que siguen activas en la base de datos.
    3. Los registros posteriores a la versión del otro extremo (ello incluye también el registro de compromiso).

  5. Si un nodo recibe un registro con indice superior al último suyo, lo guarda en memoria y en disco. Revisa también si ese nuevo registro afecta en algo a los usuarios conectados. Si es así, toma las medidas que correspondan según el caso. Propaga dicho registro a todos sus enlaces.

  6. Si el registro tiene un índice igual o inferior al último suyo, comprueba el registro que le llega con el que ya tiene. Si son iguales, lo ignora. Si son diferentes o no lo tiene, lo propaga a todos sus enlaces, pero no se lo guarda. Esto se supone que no debería ocurrir nunca, y el objetivo de esta actuación es que dicho registro acabe llegando al nodo de control, que procedería a grabarlo en un log y a dar la voz de alarma. Cualquier registro con número de versión inferior al último compromiso que tengamos, se ignora.

  7. Si un nodo recibe una petición de borrado de la base de datos, la recorre entera en memoria y marca todos los registros como borrados, con un flag. No obstante esta operación no impide que dichos registros sigan siendo válidos hasta que la operación se comprometa.

  8. Si un nodo recibe una lista de registros activos, los va marcando como "desborrados", en memoria. Ello no afecta en absoluto al funcionamiento de dichos registros hasta que la operación se compromete. Si alguno de los registros indicados no existe en la base de datos local, algo que no debería ocurrir nunca, el nodo debe:

    1. Enviar un aviso al nodo de control, informando del problema.
    2. Borrar toda su base de datos local (su número de versión será cero).
    3. Provocar un split para recibir una versión actualizada de la base de datos en el próximo "netjoin".

  9. Si un nodo recibe un registro de compromiso, borra su base de datos en disco, y va volcando en él todos los registros que tiene en memoria que no están marcados como borrados. Ello incluye también el registro de compromiso. Por ser éste un registro más de la base de datos, se propaga al resto de nodos.

  10. Si el nodo de control recibe un registro de cualquier tipo, lo guarda en un log e informa del hecho. No envía un borrado porque podría borrar un registro verídico por error.

El estudio casuístico de este protocolo es bastante más complejo que el basado en RIP, sobre todo debido a los registros de compromiso utilizados para compactar la base de datos. Indudablemente resulta más sencillo enviar periódicamente a todos los nodos una copia de la base de datos por mail compactada hasta, por ejemplo, el mes anterior.

Es mi intención que los compromisos se utilicen de forma muy esporádica, y sólo cuando el espacio desperdiciado en la base de datos tenga una importancia significativa (por ejemplo, 25% de espacio desperdiciado). Idealmente, también, deberían expedirse compromisos cuando no haya nodos en split.

En principio existen varios posibles problemas con este esquema:

Otro esquema de distribución posible, aparentemente muy sencillo, consiste en que cada nodo IRC abra una conexión directa con Olimpo y sólo reciba actualizaciones de la base de datos procedentes de él. Evidentemente ello garantiza que los registros no han sido manipulados, a menos que se hagan cosas como DNS Spoof, hijack y similares (contrarrestable usando criptografía). Por lo demás la reglas de actualización de la base de datos son virtualmente iguales (servirían las mismas, de hecho).

Como problemas tenemos el synflood, el connect flood, los conflictos con cortafuegos y demás, y la necesidad de coordinar dos conexiones independientes pero interrelacionadas. Algunos problemas se aminoran si es Olimpo quien se conecta a los nodos y no al revés.

La decisión de qué esquema implantar finalmente se tomará en los próximos días.


Esquema Propuesto

El esquema propuesto para desplegar en ESNET tiene las siguientes características:

La base de datos, por tanto, se gestiona y distribuye dentro de los propios enlaces IRC de la red, sin necesitar el despliegue de una red de control paralela. El formato de los mensajes intercambiados entre los nodos es el siguiente:

<Nodo Origen> DB <Nodo Destino> <Número de Serie> <identificador de la Base de datos> <Clave> [[:]Contenido]

Funcionamiento


Base de Datos

A continuación se detalla el formato de mensajes intercambiados entre servidores utilizando los parches hasta DB3:

<Nodo Origen> DB * 0 J <Número de Serie Local>.
Mensaje intercambiado entre nodos adyacentes en un "NetJoin" o entre ráfagas "DB Burst" como respuesta a un registro "B".

<Nodo Origen> DB * 0 B <Número de Serie Local>
Mensaje intercambiado entre nodos adyacentes al final de una ráfaga "DB Burst", para indicar que todavía quedan más registros por transferir. En el caso de que el otro extremo no lo consideremos HUB, se ignora debido al parche DB8. De otra forma se crearía un bucle infinito, ya que no estamos actualizando nuestra base de datos.

<Nodo Origen> DB <Nodo Destino> 0 Q <Número de Serie Global>

Mensaje rutable en la red IRC. Permite que un nodo pregunte a otro qué versión tiene de la Base de Datos y/o borrarla. En el caso de que el otro extremo no lo consideremos HUB, se ignora debido al parche DB8. De otra forma un nodo arbitrario podría borrar cualquier base de datos de la red.

<Nodo Origen> DB <Nodo Destino> 0 q <Número de Serie Local> <Hash>

Mensaje rutable en la red IRC. Respuesta al mensaje anterior.

<Nodo Origen> DB <Nodo Destino> <Número de Serie> N <Nick> [Clave]

Mensaje rutable en la red IRC. Registro de nick. Normalmente el Nodo Destino es "*". En el caso de que el otro extremo no lo consideremos HUB, se ignora debido al parche DB8. De esta forma evitamos que un servidor arbitrario pueda modificar bases de datos remotas.

Nodo Origen:
Identificador Numérico.

Nodo Destino:
Identificador Alfanumérico.

Número de Serie:
Valor decimal.


Historia



Get Firefox Python Zope ©1997-99 jcea@jcea.es