Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

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:

  • Identificar las areas susceptibles de ser distribuídas.
  • Estudiar un esquema de distribución lo más óptimo posible.
  • Desarrollar las herramientas necesarias para cumplir esta tarea.
  • Desplegar dichas herramientas en la red.


¿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:

  • El uso de los nodos de control en caso de lag es, como poco, penoso.
  • Si hay un split y tenemos la mala suerte de estar separados de los nodos de control, nos quedamos sin canales y nicks registrados, control de clonos, etc.
  • Si existe algún problema en los nodos de control, repercute en toda la red.
  • Los nodos de control son puntos de ataque apetecibles.
  • Los servidores en los que residen los nodos de control tienen el dominio de la red, y el resto de sistemas deben confiar en su "saber hacer" y buen criterio.
  • La presencia de los nodos de control puede generar un tráfico considerable en la red. Un caso paradigmático es el control de clonos: la entrada de un clon prohibido es propagada por toda la red, seguida del consiguiente kill global por parte del nodo de control. Este tipo de eventos deberían gestionarse de forma local y no propagar información al resto de los nodos.

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

  • Cualquier bug o actualización en el software puede corregirse o instalarse inmediatamente.
  • Los servidores IRCd no necesitan modificarse.
  • Al existir un único punto de control, la auditoría y la detección y control de abusos es simple. Siempre y cuando se pueda confiar, claro, en el "saber hacer" y la profesionalidad de sus operadores.
  • Los cambios en cualquier servidor, en principio, afectan poco o no afectan al resto de la red.
  • No es necesario, en principio, que todos los nodos de la red tengan la misma versión del IRCd o los mismos parches.
  • Es muy difícil que un nodo "malicioso" pueda tomar control de la red.
  • La migración de la red a otra versión del servidor IRCd es relativamente rápida, simple, e indolora.
  • No es necesario que los nodos mantengan ninguna base de datos local con información confidencial.
  • La carga de los nodos es la debida exclusivamente al IRCd.

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:

  • Control de clonos: En un esquema distribuído el control de clonos lo realiza cada uno de los nodos. Simplemente no permite conexiones adicionales desde una IP dada si ya se ha alcanzado el número de conexiones máximas permitidas desde esa IP. De esta forma nos ahorramos el tráfico global del alta de un nuevo usuario, seguido del consiguiente kill global por parte del nodo de control y el "notice" enviado a los usuarios con modo "s".

  • Control de Nicks: En el esquema centralizado, los nodos de control sólo advierten el uso de un nick registrado después de que éste se haya propagado por toda la red. Adicionalmente es preciso que exista un proceso que envíe un mensaje al usuario informándole de este hecho y solicitándole la clave correspondiente. Por tanto el usuario será visible para toda la red durante un período determinado (por ejemplo, 60 segundos) aunque no conozca la clave. En caso de lag la cosa se complica todavía más, ya que:

    • Si la ventana de aceptación de la clave no se amplía, puede darse el caso de que un usuario sea expulsado de la red antes de que pueda autentificarse, debido a que su clave llega demasiado tarde al nodo de control.

    • Si la ventana se amplía, el tiempo durante el cual un usuario puede utilizar un nick registrado por otra persona se incrementa.

    Adicionalmente surge el problema de cómo tratar a los usuarios que cambian de nick constantemente intentando evitar la expulsión, por ejemplo.

    Con el esquema propuesto, un usuario nuevo con nick registrado "no existe" mientras no indique su clave. No será visible para ningún nodo o usuario de la red, ni tendrá acceso a ningún servicio. Asímismo cualquier cambio de nick a uno registrado será ignorado a menos que el usuario ponga la clave correcta.

  • Control de Canales: La gestión de canales en un único nodo supone graves problemas en caso de lag o split. ESNET pretende distribuir el control de canales entre todos los nodos de la red, de forma que se pueda seguir trabajando incluso en un nodo aislado. Para reducir al máximo el tráfico de claves en la red, sólo se permitirá que registren canales aquellos usuarios cuyo nick esté registrado y validado.

  • Control IRCops: Muchas de las tareas más frecuentes de un IRCop, como son la entrada en canales "tomados" y el paso de "op" en canales donde se ha perdido, no necesitan gestionarse desde un nodo central, salvo por razones de auditoría. ESNET pretende distribuir estas capacidades entre todos los nodos de la red, aunque manteniendo sistemas de auditoría internos para prevenir los abusos y localizar a los transgresores.


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:

  • Race Conditions

    Es posible que entre el envío del número de versión de la base de datos y la recepción del del otro extremo lleguen nuevos registros. Ello no es problema aunque se trate de un compromiso, porque los netburst se generan de forma atómica (es decir, se mete toda la ráfaga en la cola de salida). Hay que tener en cuenta, eso sí, el enviar siempre la última versión de la base de datos, no hasta la versión que se haya indicado en la negociación inicial.

    Un nodo terminal en sí no tiene problemas, ya que sólo tienen un enlace simultáneo por el que preocuparse; el único riesgo de inconsistencia son los HUBS. Por ejemplo: H1 y H2=hubs; O=Olimpo, T1 y T2=nodos terminales. Topología:

    O-H1-H2
      |  |
      T1 T2
    

    Si el enlace H1-H2 es lento (lag), Olimpo propaga un nuevo registro y T1 se va en split una vez recibido el registro y reconecta vía H2, H2 aceptará el nuevo registro de T1, y un tiempo después le llegará el mismo registro vía H1:

    O-H1-H2-T1
         |
         T2
    

    Es debido a esto por lo que se necesita la regla 6. Un registro duplicado se ignora.

    La cosa se complica si existen compromisos viajando por la red y ocurren reestructuraciones topológicas. Es necesario que los registros marcados como borrados de forma temporal sean comparados también con los registros nuevos que lleguen. Asímismo cualquier registro que llegue con versión inferior al último compromiso, debe ignorarse (regla 6).

    Por último, existe el riesgo de "entrecruzamiento". Supongamos, por ejemplo, que se envía un compromiso a la red, y se produce el cambio topológico anterior. Posibles secuencias de eventos problemáticas:

    • H2 recibe todo el burst de T1 excepto el compromiso. Luego recibe la orden de borrado de H1, seguidamente, la orden de compromiso de T1. H2 se quedaría con una base de datos vacía. Pero en cuanto empiece a recibir los "keep alive" de H1 se disparará la regla 8. De esta forma H2 recibirá una copia "fresca" de la base de datos.

    • En el mismo caso que antes, si hay un split entre H1 y H2 entre el instante del compromiso de T1 y los "keep-alive" de H1, H2 permanecerá con una base de datos borrada o incompleta. Para solucionar este hecho basta con que el registro de compromiso incluya un sistema para valorar la integridad de la base de datos. Este esquema puede ser, por ejemplo, un Hashing de la base de datos. Si el Hash del compromiso no coincide con el Hash de la base de datos, sabemos que ha ocurrido algo catastrófico y adoptamos la regla 8 (borrado de la base de datos y split).

    • Puede darse el caso de que un hub no deje de hacer splits debido a los constantes conflictos y colisiones entre sus diferentes enlaces, según lo explicado en los puntos anteriores. Una posibilidad es sólo permitir una transacción simultanea. Otra, evidentemente más sencilla, es no propagar compromisos con hubs en split. En todo caso, por cuestiones de tráfico, nunca interesará forzar compromisos cuando haya nodos en split, ya que la sobrecarga en el "netjoin" siguiente es elevada.

    Existe una "race condition" adicional, importante: mientras la base de datos viaja en un sentido, en el otro se transfieren nodos, usuarios y canales. Es posible, por ejemplo, que la base de datos transfiera un nuevo registro de nick y que dicho nick ya estuviese conectado en el otro lado. Hay que estudiar las implicaciones caso por caso.

  • Corrupción de la base de datos local

    Una base de datos distribuída es vulnerable a la corrupción de las copias locales. Para prevenir esto en lo posible es necesario que cuando el servidor cargue la base de datos local (reinicio o /rehash) verifique su integridad utilizando un hash de toda la base de datos almacenado en un fichero separado. Si se detecta algún problema, cumplimos la regla 8.

  • Manipulaciones malintencionadas de la base de datos local

    Cualquier manipulación de la base de datos local debe pasar la primera prueba de Hash, tal y como se comenta en el punto anterior. No obstante esta protección no basta contra un administrador malicioso con un mínimo de conocimientos, ya que el código del Hash será público. En todo caso, cualquier intento de propagar los cambios al resto de nodos acabará llegando a oídos del nodo de control, que procedería a tomar las medidas precisas. Asímismo, si no se modifica el servidor, éste detectará la manipulación de la base de datos en cuanto reciba un compromiso externo y si se usa una función hash criptográficamente segura.

    No se puede hacer nada ante un administrador que modifique el servidor, ya que él tiene control total de su máquina. Todo lo que se puede garantizar es que dichos cambios no se propagan a servidores "sanos" y que, si se intenta, sea detectado.

    Detectar la existencia de servidores "rogue" fuera de control implica el uso de un nodo administrativo encargado de supervisar el estado de las bases de datos, clonos existentes, nicks, registrados, etc. El esquema de auditoría propuesto se analizará con posterioridad.

    Podría prevenirse (no simplemente detectarse y corregirse de forma automática) enteramente la difusión de registros maliciosos mediante el uso de firmas digitales en la base de datos, pero resulta completamente impráctico que Olimpo firme todos y cada uno de los registros. Otra posibilidad sería que Olimpo enviase cada registro tantas veces como nodos existan en la red, cada una de ellos cifrado con una clave privada sólo conocida por Olimpo y por cada nodo. De esta forma nadie podría inyectar en ningún nodo un registro que no hubiese sido generado por Olimpo. En vez de criptar cada registro con una clave distinta, se podría criptar hashes del registro y quedarnos, por ejemplo, sólo con un byte del resultado. De esta forma la probabilidad de que un enemigo fuese detectado sería, en el peor de los casos, del 99.61%.

    Hasta qué punto son necesarias medidas tan drásticas es algo que habrá que evaluar a la luz de la experiencia.

  • Privacidad de la base de datos

    Mantener la privacidad de una base de datos distribuída es tarea imposible, ya que los administradores locales tienen acceso al código fuente del servidor. Es necesario, por tanto:

    • Distribuir los registros con el contenido absolutamente mínimo para funcionar. La base de datos completa (cosas como el email de los usuarios, etc.) pueden almacenarse en Olimpo y no propagarse.

    • Las claves contenidas en registros deben enviarse cifradas. De esta forma un sniffer o un administrador malicioso no podrá traficar con ellas.

    • Las claves contenidas en los registros deben ser generadas por Olimpo, y no permitírsele al usuario el elegirlas. Con ello se pretende evitar que se usen claves débiles y, más importante aún, que dichas claves coincidan con las claves que el usuario utiliza para acceder a su ISP, por ejemplo.

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:

  • Cada nodo tiene una copia local de la base de datos.

  • Cada nodo es responsable de validar las acciones de sus usuarios locales contra esa base de datos. En general, un nodo no examina las acciones de los usuarios en otros nodos.

  • Un nodo obtiene versiones actualizadas de la base de datos mediante su propio enlace con la red.

  • Existen varios chequeos de integridad para reducir los riesgos de perder la base de datos local o tenerla corrupta.

  • La base de datos distribuida no contiene otra información considerable sensible o confidencial que la imprescindible para el correcto funcionamiento del sistema.

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]

  • Nodo Origen
    Nodo que remite el registro. Normalmente será Olimpo, pero durante un "netjoin" corresponde al nodo situado al otro lado del enlace.

  • DB
    Comando "DB". Ésta será la única modificación al protocolo Undernet.

  • Nodo Destino
    Normalmente "*". Permitirá diferenciar la base de datos de los diferentes nodos, si es preciso.

  • Número de Serie
    Cada registro de la base de datos tiene un número de serie único.

  • Identificador de la Base de Datos
    En realidad no estamos trabajando con una única base de datos, sino con varias: "I-lines", Nicks, Canales, etc. En este campo se indica un carácter alfabético que identifica la base de datos.

  • Clave
    Identifica el registro a dar de alta, a modificar o a borrar. En cada base de datos, la clave es única.

  • Contenido
    El nuevo contenido a asignar a esa clave. Si este campo no existe, lo que se nos pide es dar de baja ese registro.

Funcionamiento

  • Red en Régimen Estacionario

    En régimen estacionario, todos los servidores tienen la misma base de datos. El único tráfico entre nodos será el habitual de IRC. En un momento dado se modifica la base de datos en Olimpo, y éste envía una línea

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

    Cuando un nodo recibe una línea de base de datos:

    1. Comprueba si el número de serie es CERO

      Los registros con número de serie CERO tienen un tratamiento especial que se detalla más adelante.

    2. Comprueba si el número de serie es igual o inferior al local

      Esto significa que ya tenemos el registro. Lo ignora.

    3. El número de serie es superior al local

      • Actualiza el número de serie local
      • Actualiza el backup de la base de datos en disco
      • Propaga el registro por todos sus enlaces.
      • ¿El destino somos nosotros o es "*"?
        • Actualiza la base de datos en memoria
        • Toma las acciones oportunas

  • Red en "Net Join"

    Cuando se produce un "Net Join" es preciso resincronizar las bases de datos de las dos partes de la red que se fusionan. Para ello cada nodo envía al otro lado una línea de la forma

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

    Un nodo recibiendo un registro de esas características comprueba el número de serie recibido con el suyo. Si el otro lado tiene un número de serie más bajo, le transfiere los registros que le faltan. En caso contrario (número igual o mayor), simplemente no hace nada.

    La transferencia de la base de datos no se realiza toda de una vez, sino que el nodo con mayor número de serie envía sólo los siguientes 100 registros, por ejemplo. Al final de la ráfaga el nodo envía una línea:

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

    Cuando el otro extremo recibe una línea de esta forma vuelve a enviar un comando

    <Nodo Origen> DB <Nodo Destino> 0 J <Nuevo Número de Serie Local>

    solicitando los siguientes 100 registros. De esta forma:

    • Es posible transferir bases de datos muy grandes (por ejemplo, durante la entrada de un nuevo nodo en la red) sin que el enlace se caiga por "Max Sendq".

    • Durante la transferencia de la base de datos, las comunicaciones en los canales no se interrumpen, sino que se transfieren en los huecos.

    Para que el protocolo funcione, los nuevos registros que vaya recibiendo el nodo de mayor número de serie no deben transferirse hasta que la cola de registros para el nodo en "Net Join" se vacíe. Este evento se conoce porque cuando estamos transfiriendo una ráfaga de 100 registros sólo tenemos que transferir 100 registros exactos o menos. En ese momento se puede "Abrir el grifo".

  • Reinicio de un nodo

    Cuando un nodo arranca lee la base de datos en disco y la mantiene en memoria. Seguidamente se abre al servicio y se conecta a la red, dándose una situación de "Net Join". Durante la lectura de la base de datos se realizan diversos chequeos de integridad. En caso de problemas la borra completamente y recurre al "Net Join" para obtener una versión actualizada y correcta.

  • Resincronización de la Base de Datos

    Dado que los números de registro no se reutilizan y que el borrado de un registro se efectúa propagando un registro nuevo, la base de datos crece de forma permanente. Debe existir un método que permita "compactar" la base de datos periódicamente, eliminando los registros borrados y verificando la integridad de las copias locales.

    Ésta es, en principio, la mayor complicación que se vió en el análisis de la sección anterior.

    En esta propuesta se elimina el problema asegurándose de que todos los nodos tienen la misma base de datos antes de proceder a comprometerla. Para ello Olimpo pregunta a cada nodo de la red qué versión tiene:

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

    Cuando un nodo recibe el mensaje correspondiente, comprueba el número de serie con el suyo:

    1. Si el número de serie que llega es CERO, simplemente responde.

    2. Si el número de serie recibido es menor, borra su base de datos y envía un mensaje al nodo que le acaba de pasar la pregunta como si fuera un "Net Join".

    En todo caso responde al nodo de control con un

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

    El "hash" es una especie de "suma de control" de la base de datos. Mediante este intercambio de mensajes, el nodo de control puede:

    • Comprobar qué número de versión de la base de datos tiene cada nodo.

    • Comprobar la integridad de las bases de datos locales.

    • Borrar las bases de datos (de toda la red o de un nodo dado). Para el caso especial de que sólo exista un registro en la base de datos, basta con propagar un segundo registro para poder borrarla.

    Cuando el nodo de control quiere "comprometer" la base de datos actual:

    • Manda un mensaje de sondeo a todos los nodos

    • Si algún nodo responde con una versión antigua de la base de datos, aborta el compromiso.

    • Si algún nodo está actualizado, pero su hash no es correcto, aborta el compromiso y le envía una orden de borrado.

    • Si algún nodo no responde en un tiempo prefijado (dos minutos, por ejemplo), aborta el compromiso.

    • Si todos los nodos responden y todos ellos tienen una versión actual y correcta de la base de datos, el nodo de control envía el siguiente registro:

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

      Los nodos que reciben esta orden "limpiarán" sus bases de datos locales, y la graban en disco actualizadas, comprobando el nuevo hash.

    Es importante que el compromiso de la base de datos se efectúe con todos los servidores manejando el mismo número de serie. En particular ello obliga a que durante un compromiso no se pueda actualizar la base de datos en Olimpo. Una posibilidad es obviar este problema y simplemente contrastar las respuestas que se reciben con la versión de Olimpo. En el momento que Olimpo vea que alguno de los nodos no está actualizado, abortará el compromiso y lo intentará más tarde. Esto causa problemas si el rastreo no sigue un orden topológico inverso, ya que pueden llegar registros nuevos a un nodo que ya hemos rastreado.

    Una solución simple es abortar la transacción si se recibe algún registro nuevo (lo que puede ocasionar "starvation" si la base de datos es muy activa) o bien encolar los registros nuevos hasta que se resuelva la transacción (lo que puede ocasionar retardos muy importantes en la actualización de la base de datos en situaciones de lag).


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

  • 25/Mar/99: Cambios añadidos con el parche DB8, que impide que un nodo que no sea HUB propage cambios en la base de datos distribuída.

  • 01/Jul/98: Lista de formatos de la Base de Datos Distribuída.

  • 19/Jun/98: La primera implementación de la Base de Datos Distribuída se realizó para 2.10.04.

  • 26/May/98: Corregidos tres problemas en el esquema propuesto:

    • Posibilidad de superar el "Max Sendq" en el "Net Join".
    • Durante un compromiso de la base de datos, no se pueden modificar los registros existentes.
    • Durante un "Net Join" podrían llegar registros nuevos antes de solicitar el número de versión de la base de datos, por lo que la actualización sería ignorada debido a que su número de serie es inferior al que ya hemos recibido.

  • 22/May/98: Tras un largo paréntesis, se hace una propuesta formal de distribución de la base de datos.

  • 12/Dic/97: Añadida la sección de problemas.

  • 11/Dic/97: Primera versión de este documento.



Python Zope ©1997-99 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS