SlideShare une entreprise Scribd logo
1  sur  37
Unidad 2 - La Comunicación en los Sistemas Distribuidos

2.1 comunicacion sod

2.1 Llamada a procedimiento remoto (RPC)
En el anterior epígrafe hemos estudiado un modelo de interacción entre los procesos de un sistema distribuido que es el
modelo cliente-servidor. Para implementarlo, el sistema dispone de dos llamadas al sistema, send y receive, que las
aplicaciones utilizan de forma conveniente. Estas primitivas, a pesar de constituir la base de la construcción de los
sistemas distribuidos, pertenecen a un nivel demasiado bajo como para programar de forma eficiente aplicaciones
distribuidas.
2.1.1 La operación RPC básica
La llamada a procedimiento remoto constituye un mecanismo que integra el concepto cliente-servidor con la
programación convencional basada en llamadas a procedimientos. La idea surgió en 1984 y consiste en que el cliente se
comunica con el servidor mediante una llamada ordinaria a un procedimiento.
Esta llamada se denomina a procedimiento remoto porque el procedimiento invocado se encuentra en otro espacio de
direccionamiento, en la misma o en distinta máquina que el cliente. La información se transporta en los parámetros de
la llamada y el resultado es devuelto en el retorno de la llamada. El cliente no tiene que utilizar las primitivas send y
receive como en el modelo cliente-servidor puro, de modo que la programación de aplicacio-nes distribuidas se hace
más sencilla.

2.1.2 El paso de parámetros
La función del cabo cliente es empaquetar los parámetros en un mensaje y enviarlo al cabo servidor. Este examina el
código del procedimiento en una sentencia tipo switch e invoca el procedimiento de forma local. El resultado es de
nuevo empaquetado en un mensaje y enviado al cabo cliente. Esta interacción, que parece directa, no es tan simple
como aparenta ser. Mientras las arquitecturas del cliente y del servidor sean iguales no se presenta ningún problema
especial. En un entorno distribuido, sin embargo, cada arquitectura tiene su propia representación de números,
caracteres, etc. Por ejemplo, los mainframe IBM utilizan el código EBCDIC para los caracteres en lugar del código ASCII,
como el IBM PC. Problemas similares ocurren con la representación de coma flotante o los enteros negativos
(complemento a 1 o complemento a 2).
Otro problema surge con la forma de almacenar un entero. La arquitectura PC mantiene una representación “little
endian”, a saber, el byte menos significativo en el byte más bajo de memoria. La arquitectura SPARC utiliza un
almacenamiento “big endian”, es decir, el byte más significativo en el byte más bajo de la memoria. Un 486 operando en
modo protegido representa un entero con cuatro bytes, de modo que el 5 lo representa como 0005.
Un mecanismo adicional de paso de parámetros es denominado de copia-restauración. Consiste en realizar una copia
del parámetro en la pila. Si esta copia parámetro es modificada en el procedimiento, se restaura su nuevo valor a la
variable original. Algunos compiladores de Ada utilizan este mecanismo en parámetros in out, si bien ello no está
especificado en la definición del lenguaje. La estrategia de copia con restauración puede ser utilizada para pasar
punteros a procedimientos remotos. Supongamos la invocación del procedimiento remoto
          cuenta = read(df, buf, nbytes);

La implementación más directa consiste en copiar al buffer del mensaje local un vector de “nbytes” caracteres en lugar
de buf, que es la referencia al vector. El mensaje es entonces enviado al cabo servidor. Ahora el buffer del mensaje se
encuentra en el espacio de direccionamiento de este último, invocará la rutina de servicio read con la referencia al
vector recibido en el mensaje, es decir de forma convencional por referencia. Ahora el mensaje es devuelto con su
contenido actualizado a la rutina cabo del cliente, que restaura el vector del mensaje a su vector original. Para optimizar
este mecanismo eludimos en el cabo cliente la copia del vector al mensaje en caso de lectura. En el caso de la escritura,
prescindiremos de restaurarlo. Como vemos, es posible pasar punteros a procedimientos remotos siempre que sean
referencias a estructuras sencillas como vectores. No obstante, no podemos enviar a procedimientos remotos
referencias a estructuras de datos complejas como listas o árboles.
2.1.3 Especificación de interfase
El servidor RPC puede ser considerado como un módulo u objeto que implementa unas operacio-nes sobre datos
ocultos. El servidor da a conocer estas operaciones a los clientes mediante lo que se denomina su interface, constituida
por las declaraciones de los métodos que soporta.
Como sabemos, el objetivo del mecanismo RPC es lograr que un programa tenga acceso a los servicios de uno de estos
módulos, aunque residan en otro espacio de direccionamiento, posiblemente remoto. La figura 2.8 muestra los
componentes de una implementación RPC. La mitad rayada constituye el software adicional de empaquetamiento y
desempaquetamiento de parámetros y primitivas de comunicación que debe ser ocultado al programador. Por brillante
que sea la idea de la interacción cliente-servidor a través de RPC, si el programador debe encarar la construcción de los
cabos, el progreso de los sistemas distribuidos se verá comprometido por la falta de uso en la práctica. Es preciso que la
generación de cabos en el cliente y el servidor se realice de forma automática. Pues bien, la interfaz del servidor se
utiliza como la base de esta generación automática de cabos.
El primer paso es definir el interfaz, es decir, el conjunto de los prototipos de los procedimientos de servicio, mediante
un lenguaje determinado, denominado lenguaje de interfase. La figura 2.8, a) muestra un ejemplo de servidor. La figura
2.8, b) su definición de interfaz. Un compilador especial toma como entrada el fichero escrito en el lenguaje de interfase
y como salida genera el código objeto de los procedimientos que constituyen el cabo cliente, por una parte, y el cabo
servidor, por la otra. El programa cliente se enlaza con estos procedimientos objeto para generar el ejecutable. En
cuanto al servidor, los procedimientos de servicio, escritos por el programador, se compilan previamente a lenguaje
objeto y, a continuación, se enlazan con los procedimientos cabo, entre los que figura el procedimiento principal del
servidor RPC.
    1. include <header.h>
void main(void) {
           struct mensaje m1, m2; /* Mensajes entrante y saliente */
           int r;

           while(1)
           {
                      receive(FILE_SERVER, &m1);               /* El servidor se bloquea esperando un
mensaje */
                      switch(m1.opcode)
                      {
                              case CREATE:             r   =   do_create(&m1, &m2); break;
                              case READ:               r   =   do_read(&m1, &m2); break;
                              case WRITE:              r   =   do_write(&m1, &m2); break;
                              case DELETE:             r   =   do_delete(&m1, &m2); break;
                              case DELETE:             r   =   E_BAD_OP; break;
                      }
                      m2.result = r;
                      send(m1.source, &m2);
           }
}
                                                                  a)

       1. include <header.h>
specification of file_server, version 3.1
            long read(in char name[MAX_PATH], out char buf[BUF_SIZE],
                                    in long bytes, in long position);
            long write(in char name[MAX_PATH], in char buf[BUF_SIZE],
                                    in long bytes, in long position);
            int create(in char[MAX_PATH], in int mode);
            int delete(in char[MAX_PATH]);

end;
                                  b)

2.1.4 Enlace dinámico

No es conveniente que un servicio esté ligado a una máquina. A veces las máquinas no están operativas, de modo que
los servicios se mueven a otra máquina. El cliente está interesado en el servicio, no en qué máquina ejecuta el servidor.
Para solicitar un servicio, un cliente podría enviar un mensaje en una sentencia como la siguiente
            send(33.33.33.33@20, &mens);

en el código fuente que implementa la llamada RPC. Esta solución es inflexible, puesto que, si dentro de la máquina
33.33.33.33 el servidor pasa a escuchar en otro puerto distinto del 20, el cliente debe ser recompilado. Lo mismo ocurre
si el servidor cambia de máquina.
En contraste, el cliente debería invocar el servicio por su nombre, sin hacer referencia a dirección alguna. La figura 2.8 b)
muestra la especificación formal del servidor de ficheros 2.8 a). En la especificación formal del servidor intervienen el
nombre del servidor y su número de versión. Ambos datos identifican un servidor. Un servidor con el mismo nombre y la
misma versión, no obstante, pueden estar replicados en dos o más máquinas a fin de mejorar el servicio o propor-cionar
tolerancia a fallos. El cliente debe solicitar un servicio invocando su nombre y versión, sin citar dirección alguna. El
número de versión es conveniente a fin de que un servidor que evoluciona conserve su nombre. Un servidor puede
evolucionar ofertando nuevos servicios, cancelando otros y modificando otros. A pesar de esta evolución, es preciso que
clientes antiguos, desconocedores de los cambios, sigan obteniendo el mismo tipo de servicio. Es preciso compren-der,
no obstante, que un servidor con el mismo nombre pero con número de versión distinto es un servidor diferente.
Las ventajas de identificar al servidor por su nombre son evidentes, pero, ¿cómo el cliente localiza al servidor? ¿Quién le
proporciona su dirección? Este es un problema al que algunos sistemas RPC, entre ellos Sun RPC, dan respuesta
mediante lo que se llama el enlace dinámico, que no es sino averiguar la dirección del servidor en tiempo de ejecución.
El enlace dinámico está basado en un tercer proceso denominado el enlazador. Cuando el servidor arranca, en su código
de inicialización previo al bucle principal, envía un mensaje al enlazador a fin de registrarse como un proceso que presta
un servicio. El enlazador es, al fin y al cabo, un registrador de servicios, un servidor de nombres. El servidor entrega su
nombre, su número de versión y su dirección. Se dice que el servidor exporta su interfaz. No sería extraño que dos
programadores diesen el mismo nombre a dos servidores distintos, de modo que, a pesar de que no aparezca, cada
servidor RPC tiene asociado, además del nombre y la versión, un identificador numérico, generalmente de 32 bits, que
también entrega en la operación de registro. Dos servidores distintos deben tener identificadores distintos (se entiende
aquí servidor como programa, no como proceso). Si bien sería raro, es posible que dos programadores que terminan dos
servidores RPC, coincidan en darles el mismo identificador. Lo que ocurra cuando ambos traten de registrarse depende
de cada implementación particular del software RPC, pero es lógico pensar que el enlazador rechazaría la segunda
petición de registro.
2.1.5 Semántica RPC en presencia de fallos

El objetivo de la llamada a procedimiento remoto es conseguir la ejecución de procedimientos en otras máquinas sin
cambiar la forma en que se invoca el procedimiento en el código fuente. Salvo algunas excepciones como que un
procedimiento remoto no puede usar variables globales, el objetivo ha sido alcanzado plenamente. Mientras no se
produzcan errores la transparencia de la llamada remota está conseguida, ya que el programador no necesita saber que
la llamada que realiza es a un procedimiento remoto. Los problemas llegan cuando bien cliente o bien servidor dejan de
operar correctamente, ya que las diferencias entre llamadas locales y remotas no son fáciles de enmascarar. Vamos a
considerar cinco situaciones de fallo:
1. El cliente no es capaz de localizar al servidor. 2. El mensaje del cliente al servidor se pierde. 3. El mensaje de réplica de
servidor a cliente se pierde. 4. El servidor se cae tras recibir el mensaje del cliente. 5. El cliente se cae tras recibir la
réplica.
El cliente no puede localizar al servidor Puede haber varias causas. Una es que el servidor se cae. Otra es que el servidor
se actualiza y un cliente antiguo invoca una versión del servidor que ya no ejecuta. Una solución es que la llamada
devuelva −1 como código de error. Sin embargo, −1 puede ser un resultado válido como en la llamada RPC de suma.
Otro intento de solución es escribir un manejador de excepción (señales en C) para los errores producidos en las
llamadas RPC. Sin embargo, esta solución acaba con la transparencia respecto a las llamadas locales. Lo mejor es recibir
el resultado en parámetros de salida de la llamada RPC y que esta devuelva 0 en caso de ejecución con éxito y un código
de error en otro caso.
La petición del cliente se pierde Este caso tiene un tratamiento sencillo. El núcleo del cliente arranca un temporizador
cuando envía el mensaje al servidor. Si al cabo de un plazo no ha llegado réplica o reconocimiento del servidor, el cliente
da el mensaje por perdido y lo reenvía. Si todos los reenvíos se pierden, el kernel del cliente considera que el servidor no
está activo y devuelve un error al cabo cliente, que lo pasa a la aplicación. Estamos en el caso anterior.
La réplica del servidor se pierde Este problema es más complejo. Cuando en el caso anterior venció el plazo sin que
llegase la respuesta del servidor, asumimos que se había perdido el mensaje enviado por el cliente. Pero existe la
posibilidad de que el mensaje perdido fuese la réplica. De cualquier forma, establecimos que lo que había que hacer era
el reenvío del mensaje. En el primer caso, el servidor recibe el mensaje reenviado por primera vez. Todo vuelve a
funcionar correctamente. En el segundo caso el servidor recibe el mensaje por segunda vez. Sirve la petición dos veces,
como si en el programa cliente hubiésemos invocado la llamada una segunda vez. En algunos casos, la repetición de una
operación en el servidor no causa ningún daño. Por ejemplo, el leer los 20 primeros bytes de un fichero. Las peticiones
que tienen esta propiedad se dicen que son idempotentes. Otras veces, la re-petición sí ocasiona perjuicios, como puede
ser el añadir 20 bytes a ese fichero o retirar de una cuenta bancaria 500 millones de pesetas. La solución a este
problema pasa por numerar las peticiones. Las retransmisiones llevan el mismo número de secuencia que la transmisión
original. Entonces el kernel del servidor detecta que la réplica se ha perdido y la reenvía, sin operar sobre el servidor.
Una versión distinta de esta solución es introducir en la cabecera de la petición un bit de retransmisión.
El servidor se cae La figura 2.10 a) muestra la secuencia de eventos producidos en un servidor en el servicio de una
petición. El sistema operativo del servidor recibe el paquete entrante con el mensaje, que entrega al cabo para que
invoque la ejecución del procedimiento que sirve la petición. A continuación, el cabo pasa la réplica al sistema operativo
que lo envía en un paquete al cliente. Ahora bien, tras haberse ejecutado el procedimiento de servicio, el servidor puede
sufrir una caída que impide la emisión de la réplica al cliente. Es el caso b) de la figura. Por el contrario, la caída puede
producirse tras la recepción del paquete, pero previamente a la ejecución del procedimiento de servicio. Es el caso c).
Las consecuencias de los casos b) y c) es diferente. Supongamos que la operación remota es escribir un texto en la
impresora. El servidor primero carga el texto en la memoria interna de la impresora y después escribe en un registro de
la misma para iniciar la impresión. El servidor puede caerse antes de establecer el bit o después de establecer el bit. En
el primer caso, la operación no será realizada. En el segundo caso, sí, ya que la impresora continúa su trabajo con
independencia de que el servidor esté activo o no lo esté.
Podemos pensar que este caso tiene la misma complejidad que la pérdida de la réplica, examina-da en el caso anterior.
No es así. La pérdida de la réplica supone un reenvío de la solicitud de impresión. El núcleo del servidor se dará cuenta
de que el mensaje tiene un número de secuencia repetido y enviará de nuevo la réplica si repetir la impresión. En
contraste, la caída del servidor supone la pérdida del registro de los números de secuencia de mensajes del cliente. Por
esta razón, tras un rearranque, el servidor no puede saber si la re-petición de impresión ha sido servida con
anterioridad, de modo que volverá a ser servida. Si la caída se produjo en el caso c) la impresión no se hizo, de modo que
reiniciar la operación es lo correcto. Sin embargo, si la caída se produjo en el caso b) reiniciar la operación supone
repetirla. Lo peor del caso b) es que ni cliente ni servidor sabrán nunca si la operación se realizó con anterioridad o no.
2.1.6 Implementación de software RPC

El éxito o el fracaso de un sistema operativo distribuido radica en sus prestaciones. Si un sistema es lento, no tiene éxito.
Las prestaciones de un sistema operativo distribuido radican en gran parte en la velocidad de las comunicaciones, y esta
velocidad depende fundamentalmente de la implementación del protocolo de comunicación más que en sus principios
abstractos. En esta sección vamos a discutir la implementación de software RPC.
Protocolos RPC En los sistemas comerciales actuales, el software RPC está implementado como una biblioteca de
funciones que el programa de usuario invoca. Tanto el cabo cliente como el cabo servidor no son sino un conjunto de
llamadas a funciones de la biblioteca RPC. Veamos el ejemplo de Sun RPC. El siguiente mandato UNIX es el que se utiliza
para compilar el programa cliente rdate de la figura 2.9.
           # cc -o rdate rdate.c date_clnt.c -lrpclib

donde se aprecia el enlace de la biblioteca de Sun RPC, rpclib. El mandato para generar el servidor RPC es similar. La
aplicación de usuario rdate invoca funciones RPC del cabo que, a su vez, invocan las llamadas al sistema de
comunicaciones del sistema operativo para enviar los mensajes al servidor RPC. Así, el software RPC puede entenderse
como un nivel de servicio entre cliente o servidor y el sistema operativo, tal como ilustra la figura 2.11. Generalmente,
las llamadas al sistema de comunicaciones de los sistemas UNIX están implementadas mediante la pila de protocolos
TCP/IP, que forman parte del núcleo de UNIX. IP es el protocolo de nivel de red (nivel tres en la pila OSI).
TCP es uno de los protocolos de transporte de la pila TCP/IPTCP es un protocolo del nivel de transporte (nivel cuatro en
la pila OSI), orientado a conexión. La comunicación entre dos procesos mediante conexión se basa en establecer un
circuito virtual entre ambas máquinas antes del hacer envío alguno. El establecimiento de una conexión es costoso en
tiempo y recursos, pero garantiza la fiabilidad total de la comunicación.
2.2 Comunicación de grupos

La comunicación RPC tiene dos partes, una, el cliente, dos, el servidor. Hay situaciones en que este modelo no es el
idóneo en un sistema con un conjunto de servidores de ficheros replicados a fin de proporcionar tolerancia a fallos. Un
programa cliente que hace una escritura a disco debe hacer llegar la petición simultáneamente a todos los servidores y
no a uno de ellos únicamente. El problema puede solucionarse invocando tantas llamadas RPC como servidores
existentes. Existe, sin embargo, otro paradigma de comunicación disponible para los sistemas distribuidos que es la
comunicación de grupos, más apropiado en casos como este.
2.2.1 Introducción a la comunicación de grupos
La característica principal de un grupo de procesos es que cuando se envía un mensaje al grupo, todos sus componentes
lo reciben. Por otra parte, los grupos son dinámicos. Los grupos nacen y mueren y en cada grupo terminan algunos
procesos y se incorporan otros. Por lo tanto es necesario un mecanismo de gestión de grupos. Un proceso puede
pertenecer a más de un grupo y abandonar un grupo para unirse a otro. Un grupo es una abstracción cuyo propósito es
evitar, en las llamadas de comunicación con grupos de procesos, parámetros molestos como el número de elementos en
el grupo o la localización de cada proceso del grupo y proporcionar primitivas más potentes y transparentes, como el
ejemplo anterior de envío de un mensaje a un conjunto de servidores de ficheros. El cliente no debería saber cuantos
servidores están disponibles en cada momento ni en qué máquinas concretas han sido arrancados.
La implementación de grupos depende mucho del hardware de comunicación disponible. En algunas redes, como
ethernet, existen unas direcciones especiales en las que pueden escuchar más de una máquina. Para ello es necesario
configurar el adaptador de red ethernet en cada máquina. Un único marco o enviado a esta dirección es leído por todas
las máquinas que escuchan en ella. Estas direcciones se denominan multicasting. Si el nivel de enlace de la red soporta
multicasting, como es el caso de ethernet, la implementación de grupos es sencilla. Basta asignar a cada grupo una
dirección multicasting diferente. Existen redes que si bien no admiten multicasting, sí admiten difusión. Marcos ethernet
con la dirección de destino 111…111 son recibidos por todas las máquinas de la red. La difusión puede ser utilizada para
implementar grupos, pero es menos eficiente, porque el marco se envía a todas las máquinas, tanto las que pertenecen
al grupo como las que no. De todas formas, el envío al grupo de procesos requiere de un solo paquete. Si el nivel de
enlace no proporciona multicasting ni difusión, aún es posible la implementación de grupos. Para ello, el emisor debe
enviar un paquete particular a cada miembro del grupo. Por supuesto, esta es la implementación menos eficiente.
2.2.2 Aspectos de diseño
La comunicación de grupos comparte muchos aspectos de la comunicación estándar de paso de mensajes, tales como
primitivas con buffer o sin buffer, bloqueantes o no bloqueantes, etc. No obstante, existen más posibilidades adicionales
a elegir en la comunicación de grupos. En esta sección examinamos algunos de estos aspectos particulares en la
comunicación de grupos.
2.2.2.1 Grupos cerrados frente a grupos abiertos
Los protocolos que soportan comunicación de grupos pueden dividirse en dos categorías. Una es la de los grupos
cerrados. En ellos sólo los miembros del grupo pueden enviarse mensajes entre sí. Procesos que no pertenecen al grupo
no pueden enviar mensajes al grupo como tal, si bien, por supuesto, sí pueden enviar mensajes particulares a cada
miembro del grupo a título particular. Otros protocolos soportan grupos abiertos. Un proceso que no pertenece a un
grupo puede enviar mensajes a este grupo. Los grupos cerrados son utilizados típicamente en procesa-miento en
paralelo, donde los procesos tienen su propio cometido y no interactúan con el mundo exterior. Los grupos abiertos son
apropiados para problemas como el de los servidores replica-dos, donde un cliente envía una petición al grupo. Los
miembros del grupo también necesitan hacer uso de la comunicación en grupo y no sólo un proceso externo, por
ejemplo para decidir quién debe ejecutar una petición dada.
2.2.2.2 Grupos de iguales frente a grupos jerárquicos
En algunos grupos un proceso es el jefe o coordinador y el resto trabajan para él. En otros, todos los procesos tienen la
misma categoría y las decisiones se toman de forma colectiva. En el primer caso, cuando uno de los trabajadores o un
cliente externo solicita una petición, esta es enviada al coordinador, que decide cuál de los trabajadores es el más
apropiado para servirla. Cada una de estas organizaciones tiene sus ventajas y sus inconvenientes. Los grupos pares no
tienen un único punto de fallo. Si un trabajador deja de existir, la carga se reparte en el resto. Sin embargo, incurren en
el retraso que supone el ponerse de acuerdo para decidir quién sirve una petición. Los grupos jerárquicos tienen las
propiedades opuestas.
2.2.2.3 Pertenencia a grupos
Se necesita un método para crear, destruir y modificar los grupos. Una solución es introducir un proceso denominado el
servidor de grupos. El servidor de grupos mantiene tablas con los grupos existentes y sus integrantes. Esta solución es
eficiente y fácil de implementar. El problema es que el servidor de grupos es una técnica centralizadora y, como tal,
constituye un único punto de fallo. La opción opuesta es la gestión distribuida. Un nuevo proceso que se incorpora al
grupo puede enviar un mensaje al grupo y todos los procesos toman nota de su existencia. Cuando un proceso del grupo
termina, envía un mensaje de adiós.
Surge un problema cuando un proceso del grupo termina inesperadamente. El resto del grupo tiene que descubrirlo
experimentalmente, ya que el proceso nunca responde a nada. Cuando todos los miembros lo han constatado, se le da
de baja.
2.2.2.4 Direccionamiento de grupos
Para dirigir un mensaje a un grupo, el grupo debe tener una dirección. Si el nivel de enlace de la red -en adelante, la red-
soporta multicasting, se puede implementar una dirección de grupo como una dirección multicasting. Si la red soporta
difusión, pero no multicasting, el mensaje debe ser recibido por todos los núcleos y extraer de él la dirección del grupo.
Si ninguno de los procesos de la máquina es miembro del grupo, el mensaje es descartado. En otro caso, es pasado a
todos los procesos que pertenecen al grupo. Si la red no soporta ni difusión ni multicasting, el núcleo de la máquina
emisora tendrá que tener una lista de los procesos que pertenecen al grupo y enviar un mensaje a cada uno de los
componentes del grupo.
2.2.2.5 Primitivas send y receive
No es conveniente que los procesos de usuario puedan utilizar las primitivas send y recei-ve por separado. Según
Tanenbaum, send y receive se corresponden en programación distribuida con la construcción “go to” en programación
convencional. Su utilización provoca más trastornos que utilidad. Si RPC es la primitiva de comunicación usada por los
procesos de usuario, la comunicación de grupo debiera poder construirse mediante RPC. El problema es tratar con una
llamada a procedimiento que devuelve tantos valores como procesos tiene un grupo. No parece posible, de modo que
una aproximación común es volver a las primitivas send y receive en los procesos de usuario.
Si se permite send y receive a los procesos de usuario, se pueden aprovechar estas primitivas para realizar la
comunicación de grupo. En el caso de la comunicación convencional cliente servidor, el primer parámetro de send es un
número de puerto en la red y el segundo parámetro es el mensaje. Se puede utilizar send para la comunicación de
grupos empleando como primer parámetro la dirección de un grupo de procesos en lugar de un puerto determinado. Así
unifica-mos la comunicación punto a punto y la comunicación de grupos en una primitiva única. La implementación de
send que haga el núcleo o la rutina de biblioteca puede ser una de las tres citadas en el apartado de direccionamiento de
grupos. send puede ser con buffer o sin buffer, bloqueante o no bloqueante, fiable o no fiable, etc, igual que en la
comunicación punto a punto. La comunicación de grupo no cambia las cosas.
Enviar a un grupo obliga al núcleo del sistema que envía a hacer una comunicación multicasting a todos los miembros
del grupo, pero ¿qué es recibir de un grupo? Puede entenderse que todos los miembros del grupo van a enviar una
réplica diferente y por lo tanto un envío a un grupo debería continuar en el programa de usuario con tantas operaciones
receive como miembros tuviese el grupo. Ello, no obstante, significa una pérdida de transparencia, ya que un proceso
externo no debe conocer la estructura interna de un grupo.
2.2.2.6 Atomicidad de la difusión
Una de las características de la comunicación de grupos es que un mensaje enviado a un grupo debe ser recibido por
todos los miembros del grupo o por ninguno de ellos. A esta propiedad se la denomina la atomicidad de la difusión o
simplemente la atomicidad. La atomicidad facilita en gran medida la programación de sistemas distribuidos.
Supongamos, por ejemplo, una base de datos distribuida. Una base de datos distribuida puede tener una relación cuyos
atributos estén repartidos en máquinas dispersas geográficamente. El acceso a una tupla significa enviar un mensaje a
todas las máquinas. Supongamos la creación de una tupla de estas características. Si uno de los mensajes se pierde, la
base de datos queda en un estado inconsistente. La tupla debe crearse en su totalidad o no crearse y la aplicación ser
informada del éxito o del fracaso de la operación entera, no sólo un éxito parcial. Implementar la atomicidad de la
difusión no es tan simple como parece. Por ejemplo, uno de los adaptadores de red tal vez acaba de recibir un paquete y
antes de que esté preparado para recibir uno nuevo, llega el paquete de difusión, que no puede ser aceptado y
simplemente se pierde. Todas las máquinas del grupo han recibido el paquete excepto una, lo que arruina la difusión
completa. Para cerciorarse de que todo ha ido bien, el emisor de la difusión debe esperar las confirmaciones de los
miembros del grupo. Si una falta, deberá repetir la difusión o reenviar el mensaje en particular.
Puede ocurrir que antes de repetir la difusión o hacer el reenvío, el emisor de la difusión se caiga. En esta situación, el
cliente debe rearrancar, pero nunca sabrá cuántos son los mensajes que realmente han sido enviados y cuántos los que
han fallado. Algunos miembros del grupo han recibido el mensaje y otros no. Una situación inaceptable e ¿incorregible?
No, queda alguna esperanza. Existe un algoritmo que demuestra que la atomicidad es posible. El emisor realiza la
difusión, inicializa temporizadores y realiza los reenvíos necesarios. Cuando un miembro del grupo recibe un mensaje
nuevo, envía el mensaje a todos los miembros del grupo -de nuevo utilizando temporizadores y retransmisiones si son
necesarias-. Si el mensaje no es nuevo, simplemente es descartado. No importa cuantas máquinas caigan en el proceso
de envíos y reenvíos, lo importante es que de los procesos supervivientes en el grupo todos han recibido el mensaje.
2.2.2.7 Ordenación de mensajes
Para que la comunicación en grupo sea fácil de usar y comprender requiere de dos propieda-des. La primera es la
atomicidad, examinada más arriba y la segunda es el orden de los mensajes. Supongamos cinco máquinas, cada una con
un proceso. Los procesos 0, 1, 3 y 4 pertenecen a un grupo de procesos. Supongamos que los procesos 0 y 4 deciden
enviar un mensaje al resto de los procesos del grupo. Supongamos que el proceso 0 lo ha decidido un instante de tiempo
antes. La propiedad de orden temporal global exige que cada miembro del grupo reciba primero el mensaje del proceso
0 y después el mensaje del proceso 4.
Una red local que soporte difusión garantiza el orden temporal global. Todos los mensajes del proceso 0 llegan al resto
del grupo ya que el paquete con dirección difusión es recibido por todos los adaptadores de red de forma simultánea.
Sólo después, cuando el mensaje ha sido enviado y deja libre el canal el proceso 4 puede emitir su paquete de difusión.
Una red sin difusión no garantiza el orden temporal global, que debe implementar la difusión enviando cuatro mensajes
consecutivos que pueden entrelazarse con los del proceso 4. Así, el proceso 1 puede recibir primero el mensaje del
proceso 0 y después el del 4 y el proceso 3 puede recibir primero el mensaje del proceso 4 y después el del proceso 0.
2.2.2.8 Grupos solapados
En el apartado anterior vimos el problema de la ordenación temporal global aplicada a un grupo dado. Dos procesos del
mismo grupo enviaban simultáneamente un mensaje al grupo. Hemos mencionado previamente que un proceso puede
pertenecer a más de un grupo, de manera que los grupos pueden solaparse. Este solapamiento produce un nuevo tipo
de inconsistencia temporal. La figura 2.14 muestra el problema planteado. Los procesos A y D, en distinto grupo, envían
simultáneamente un mensaje a su propio grupo. Como en el caso anterior supongamos que la red no proporciona
difusión y esta se implementa mediante unicasting. El envío simultáneo es consitente si B y C reciben primero el mensaje
del grupo 1 y después el mensaje del grupo 2 (o viceversa). Unicasting no puede garantizar esto, de modo que es posible
el escenario de la figura 2.14. B recibe el mensaje dirigido al grupo 1 y después el mensaje al grupo 2. C, por el contrario,
primero recibe el mensaje dirigido al grupo 2 y después el mensaje al grupo 1.
Fig. 2.14 Cuatro procesos y cuatro mensajes. B y C toman los mensajes de A y D en diferente orden.
Una comunicación de grupo que garantiza que esto no ocurre se dice que tiene la propiedad de orden temporal entre
grupos solapados. La implementación del orden temporal entre grupos solapados es costosa y difícil de implementar, de
modo que algunos sistemas distribuidos la implementan y otros no, actualmente la mayoría de ellos.
2.2.2.9     Escalabilidad

Muchos algoritmos de comunicación de grupos funcionan bien siempre que los grupos sean pequeños y haya pocos
grupos, pero ¿qué ocurre cuando cada grupo tiene muchos procesos y hay miles de grupos? Y ¿qué ocurre cuando los
grupos se extienden geográficamente entre continen-tes? Para ellos es preciso sobrepasar los estrechos límites de la red
local e introducir encaminado-res y muchas redes locales. La presencia de encaminadores afecta a las propiedades de la
comunicación del sistema operativo distribuido, ya que están basadas en la suposición de ausencia de encaminadores.
Un encaminador es básicamente una máquina que pertenece a dos o más redes. Su propósito es unir dos o más redes
locales distantes geográficamente, de distinto nivel de enlace o ambas cosas a la vez, permitiendo que todas ellas
compartan un mismo protocolo de nivel de red. En la definición de grupo nada impide que los procesos que forman el
grupo se encuentren en una misma Inter-red pero en distintas redes locales. Cuando la comunicación de grupo se realiza
mediante unicasting la presencia de gateways no es problemática. Cada mensaje enviado por el proceso emisor llega al
proceso destinatario siguiendo los cauces convencionales del algoritmo utilizado por el protocolo de red. Consideremos
un sistema operativo distribuido en el que las redes locales que abarca soportan multicasting, como ethernet.
3.1   Sincronización de relojes

           Los algoritmos distribuidos tienen las siguientes propiedades:

1. La información relevante está repartida entre múltiples máquinas 2. Los procesos toman decisiones basados
únicamente en información local 3. Es preciso evitar un único punto de fallo 4. No existe un reloj común
        Los primeros tres aspectos dicen que es inaceptable recoger toda la información
en un único punto. El último aspecto es que ahora nos interesa. En un sistema
centralizado, el tiempo se solicita mediante una llamada al sistema, como la llamada UNIX
time. Si un proceso A solicita el tiempo y poco después lo solicita el proceso B, B
obtiene un tiempo posterior al de A, ya que ambos consultan el mismo reloj. En un sistema
distribuido, en que A y B corren en máquinas distintas y consultan distintos relojes, si
el reloj de A es ligeramente más lento que el de B, A puede conseguir un tiempo posterior
al de B a pesar de habero solicitado antes.
3.1.1 Relojes lógicos
                Leslie Lamport, en 1978 ([Les78]), mostró que la sincronización de
relojes para producir un patrón de tiempo común a más de una máquina es posible y
presentó un algoritmo para lograrlo. Lamport afirmó que no es necesario disponer de un
registro común absoluto del tiempo cuando los procesos no interactúan y, cuando lo hacen,
tampoco es necesario en la mayoría de las aplicaciones. Para muchos casos, lo imporante
es que los procesos que interactúan se pongan de acuerdo en el tiempo en que los eventos
ocurren. En el ejemplo de make, lo importante es que pepo.c sea más antiguo que pepo.o,
no el instante preciso de creación de ambos. Así, para ciertas clases de algoritmos, lo
que importa es la consistencia interna de los relojes, no la exactitud particular de cada
uno de ellos. Para estos algoritmos, es conveniente hablar de relojes lógicos. Cuando el
objetivo es mantener todos los relojes dentro de un margen error dado respecto al tiempo
absoluto, es conveniente hablar de relojes físicos.

        Lamport definió la relación ocurre-antes, a m b, leída “a ocurre antes que b”, y
significa que a ocurre antes que b y todos los procesos están de acuerdo en ello. Lamport
definió esta relación como sigue:

1. Si los eventos a y b ocurren en el mismo proceso y a ocurre antes que b, entonces a b. 2. Si a es el evento que
consiste en el envío de un mensaje a otro proceso y b es el evento que consiste en la recepción del mensaje en otro
proceso, entonces a b. 3. Si a e b y b c, entonces b e c.
3.1.2   Relojes físicos

                El día solar es el tiempo que transcurre desde que el sol alcanza su
punto más alto en el horizonte hasta que vuelve a alcanzarlo. Un día tiene 24 horas, de
modo que definimos el segundo solar como 1/(24*60*60) = 1/86400 de un día solar. En 1940
se descubrió que la duración del día no era constante. Estudios actuales sobre coral
antiguo han llevado a los geólogos a pensar que hace 300 millones de años había 400 días
en un año. No es que el año fuera más largo. Es que los días eran más cortos. La tierra
rotaba sobre sí misma más rápido que en la actualidad. Además de esta tendencia a largo
plazo, la tierra experimenta perturbaciones esporádicas en su tiempo de rotación debido a
las turbulencias de su núcleo de hierro. Estas oscilaciones llevaron a los astrónomos a
determinar la duración del segundo como la media de un gran número de ellas. Dividida
esta cantidad por 86400 obtenemos el segundo solar medio.

        Con la invención del reloj atómico en 1948, la medida del tiempo pasó de ser
responsabilidad de los astrónomos a ser responsabilidad de los físicos. Definieron el
segundo atómico como el tiempo que tarda el isótopo 133 del cesio en realizar 9192631770
transiciones. Este número de transiciones fue escogido, por supuesto, porque son las que
igualaban la duración del segundo solar medio el día que el segundo atómico fue
introducido. El segundo atómico es más preciso que el segundo solar, pero no es
absolutamente preciso. En el mundo existen actualmente unos 50 laboratorios que disponen
de un reloj de 133Cs. Cada uno de ellos registra el número de ticks acumulados desde las
cero horas del primero de enero de 1958. En París existe una organización que se llama la
Oficina Internacional de la Hora que promedia los ticks de estos 50 laboratorios. Al
resultado lo divide por 9192631770 para obtener el Tiempo Atómico Internacional (TAI). El
TAI es extrordinariamente estable y está a disposición de cualquiera que lo solicite. Sin
embargo, como el periodo de rotación de la tierra está aumentando continuamente, el
segundo solar aumenta en la misma medida. Así, un día solar, que son 86400 segundos
solares, tiene ahora 86400.003 segundos TAI.

        Usar el tiempo TAI es más exacto, pero llegará un momento que el mediodía no será
a las 12, sino a las doce y cuarto. Los segundos TAI duran menos que los segundos
solares. Para ello, cuando un reloj solar ha perdido 0.8 segundos respecto al tiempo TAI,
por ejemplo, el tiempo es de 4.0 TAI y de 3.2 solar, se extingue ese segundo solar para
que pase directamente de 3.2 a 4.0 y mantener la sincronía con el tiempo TAI. Esto da una
medida del tiempo con intervalos irregulares, llamado el Tiempo Universal Coordinado
(UTC), que es la base actual del registro del tiempo. Ha reemplazado al antiguo estándar
de la medida del tiempo, el GMT (Greenwich Meridian Time), que es tiempo solar.

        Para proporcionar el tiempo UTC, una institución de Estados Unidos, el Instituto
Nacional del Tiempo Estándar (NIST), mantiene una estación de radio de onda corta que
radia un pulso cada vez que comienza un segundo UTC. La precisión de esta estación es de
un milisegundo, pero el ruido atmosférico eleva este error en la práctica a 10
milisegundos. En Inglaterra y otros países existen estaciones similares. También
satélites proporcionan el tiempo UTC, y lo hacen con una precisión de 0.5 milisegundos,
veinte veces mayor que las estaciones de radio de onda corta. El costo de este servicio
varía, según su exactitud, entre 100.000 pts y varios millones de pesetas según su
precisión. Hay un medio más barato, que es obtenerlo del NIST por teléfono. Este es el
método más inexacto, ya que hay que corregir el retraso de la señal en la línea y el
modem.

        Concluyendo, podemos decir que el tiempo absoluto puede ser proporcionado al
computador, pero a un precio alto y siempre con un margen de error no despreciable.
        Mas información: http://www.cstv.to.cnr.it/toi/uk/utctime.html
3.1.3   Algoritmos de sincronización de relojes

                La medida del tiempo en las máquinas se lleva a cabo mediante un
oscilador de cristal. Un chip denominado temporizador recibe la señal periódica del
oscilador e interrumpe la UCP cada cierto número de oscilaciones, previamente programado.
Valores típicos oscilan entre 50 y 100 interrupciones por segundo a la UCP. Por preciso
que sea un oscilador a cristal, siempre existe un margen de error que conlleva la
discrepancia de la medida del tiempo de dos máquinas diferentes. En una red local, por
ejemplo, ninguna máquina tiene el mismo registro del tiempo. Para disminuir la
discrepancia entre relojes, se puede tener acceso a una estación de onda corta de las ya
citadas. El caso general, sin embargo, es que este servicio no está disponible, y el
problema que se plantea es, dado un conjunto de máquinas, mantener sus relojes lo más
cercanos que sea posible mediante software.

        Se han propuesto para ello muchos algoritmos, todos ellos con el mismo principio,
que ahora describimos. Se supone que cada máquina dispone de un temporizador que
interrumpe a la UCP H veces por segundo. El núcleo dispone de una variable que es
incrementada en la unidad por la rutina de interrupción del reloj. Esta variable registra
el número de ticks recibidos desde la puesta en marcha del sistema, por ejemplo. Esta
variable se considera el reloj del sistema y vamos a denominar el valor que almacena como
C. Cuando el tiempo es t, el tiempo registrado por la máquina p es Cp(t). Idealmente
Cp(t) debiera ser igual a t, para todo p y todo t. En otras palabras, dC/dt debiera ser
idealmente 1. Teóricamente, un temporizador con H=60 interrumpe al reloj sesenta veces
por segundo. En una hora interrumpe 60*60*60 = 216000 veces. En la práctica, se puede
contar este número de interrupciones y descubrir que no son exactamente esas, sino que el
dato varía entre 215998 y 216002 ticks en una hora, lo que representa un error relativo
de aproximadamente 10–5. La precisión de un temporizador viene dada por su tasa de deriva
máxima 0, de modo que si


       se dice que el reloj opera dentro de sus especificaciones.

        Dos relojes iguales dentro de sus especificaciones pueden generar una
direferencia máxima en su medida del tiempo cuando la deriva toma en ellos el valor
máximo y de signo opuesto. Así, partiendo ambos de cero, en un intervalo , el reloj uno
toma un valor de   y el reloj dos un valor de 0, obteniendo una diferencia máxima en la
medida de 0. Si los diseñadores del sistema desean que nunca dos relojes muestren
diferencias mayores a una constante 0, 0, de modo que 0, lo que significa que los
relojes deben ser sincronizados cada 0 segundos. A continuación vamos a ver algunos
algoritmos que llevan a cabo esta resincronización.

       3.1.3.1   El algoritmo de Cristian

                Este algoritmo requiere que una de las máquinas disponga de un receptor
de onda corta y el objetivo es lograr que todas las demás operen sincronizadas con ella.
A esta máquina la vamos a llamar un servidor de tiempo. Periódicamente, y siempre antes
de   segundos, cada una de las máquinas envía un mensaje al servidor de tiempo
solicitando el tiempo CUTC, que es servido tan rápido como es posible como indica la
figura 3.5 XX falta XX. El algoritmo tiene dos problemas, uno más leve y otro más serio.
El más serio es que un reloj nunca puede ser retrasado. Si el reloj de la máquina que
solicita el tiempo es rápido, el tiempo CUTC recogido es menor y su reloj debe ser
atrasado. Esto no se puede permitir porque muchas aplicaciones, como make, confían en la
secuencia temporal de eventos en el sistema como la base de su operación. A un evento que
ocurre después de otro, como la generación de un fichero objeto, no se le puede asignar
un tiempo de creación o última modificación inferior al del programa fuente.
La modificación del reloj debe realizarse gradualmente. Una forma de hacerlo es
la siguiente. Supongamos que el temporizador interrumpe la UCP cien veces por segundo, lo
que significa que un tick de reloj es un intervalo de tiempo de diez milisegundos. La
rutina de interrupción incrementa un contador en el núcleo, el reloj, en una unidad, lo
que equivale a sumar al tiempo diez milisegundos. Para retrasar el reloj un segundo se
puede dejar de incrementar el contador una de cada cien interrupciones -por ejemplo, la
décima-, lo que significa que cada segundo retrasamos el reloj diez milisegundos. Para
retrasarlo un segundo necesitamos cien segundos. Para adelantar el reloj se puede
utilizar esta misma técnica. Al cabo de 100 segundos, habremos adelantado el reloj un
segundo. También se puede adelantar el reloj de una sóla vez añadiendo 100 ticks al
reloj, ya que el adelantamiento del tiempo no causa problemas.

        El problema secundario es que desde que una máquina solicita el tiempo CUTC, la
réplica del servidor de tiempo tarda en llegar una cantidad de tiempo no despreciable y,
lo que es peor, que varía con la congestión de la red. El algoritmo de Cristian aborda
este problema intentando medirlo. El cliente registra el tiempo local T0 en que envía el
mensaje y el tiempo T1 en el que llega y estima que la réplica tardó en llegar (T1-T0)/2.
Este tiempo que es local y, por ser pequeño, relativo exacto aunque el reloj se haya
alejado sensiblemente del tiempo UTC. (T1-T0)/2 se suma al CUTC que trae el mensaje y el
resulado es el CUTC que finalmente el cliente adopta. Para mejorar la exactitud se puede
realizar un muestreo entre distintos tiempos de retorno de la petición de tiempo y
realizar una media. Se aconseja descartar los valores que superan un umbral dado para
evitar introducir en la estimación réplicas obtenidas en momentos de congestión.

       3.1.3.2   El algoritmo de Berkeley

         Es el adoptado por UNIX BSD. Frente al algoritmo de Cristian, basado en un
servidor pasivo que responde a las peticiones de clientes, el algoritmo de Berkeley toma
una aproximación activa. Es útil cuando no se dispone del tiempo UTC, vía un receptor de
onda u otro. Un demonio UNIX periódicamente realiza un escrutinio de las máquinas,
aquella en la que reside incluida, a fin de obtener el valor de sus relojes. Realiza una
media de todos ellos y la comunica a todas la máquinas para que avancen o retrasen sus
relojes.

       3.1.3.3   Algoritmos de promediado

        Los algoritmos anteriores tienen la desventaja de su aproximación centralizada y,
por lo tanto, tienen un único punto de fallo. Presentamos a continuación un algoritmo
descentralizado. Las máquinas dividen el tiempo en intervalos de longitud R, de modo que
el comienzo del i-ésimo intervalo comienza en el instante T0+iR se prolonga hasta el
instante T0+(i+1)R, donde T0 es un instante pasado previamente acordado. Cuando comienza
uno de estos intervalos, cada máquina realiza una difusión del tiempo según su reloj.
Debido a la deriba particular de cada reloj, dos difusiones no ocurren simultáneamente.
Después de la difusión de su tiempo, cada máquina establece un temporizador y espera el
mensaje correspondiente al broadcast del resto de las máquinas en un intervalo S. Cuando
han llegado todos los mesajes, un algoritmo de promediado proporciona el nuevo tiempo. El
algoritmo más simple es realizar la media aritmética de los tiempos. Una variación es
descartar previamente los valores extremos a fin de protegernos frente a relojes
defectuosos. Otra variación es estimar el tiempo de propagación de cada mensaje para
añadirlo al tiempo que el mensaje transporta. Esta estimación puede llevarse a cabo a
partir de un conocimiento previo de la topología de la red o realizando mediciones del
tiempo de retorno de algunos mensajes de prueba.

       3.1.4   El empleo de la sincronización de relojes
Hasta hace poco tiempo no se ha presentado la necesidad de sincronizar los
relojes de máquinas en una red de área ancha. Ahora es posible sincronizar relojes
distribuidos a lo largo de toda la Internet en márgenes de precisión de unos pocos
milisegundos respecto al tiempo UTC. La disponibilidad de algoritmos de bajo costo para
mantener la sincronización de relojes ha incitado el desarrollo de algoritmos
distribuidos que explotan esta circunstancia disminuyendo el número de mensajes
implicados en las versiones que no la explotan. A continuación ilustramos el empleo de la
sincronización de relojes en el problema de la consistencia de la caché de un sistema de
ficheros distribuidos. La referencia [Lis93] contiene más ejemplos.

        Un ejemplo de la utilidad de algoritmos basados en el uso de relojes
sincronizados está relacionado con la consistencia de la cache de disco en un sistema de
ficheros distribuido. Razones de prestaciones exigen una caché en el cliente. Dos
clientes operando sobre un mismo fichero mantienen cada uno de ellos una copia del
fichero en su propia máquina. La inconsistencia de las cachés surge cuando uno de los
clientes trata de escribir en el fichero. Tradicionalmente, cuando un cliente deseaba
escribir un fichero de su caché solicitaba permiso al servidor. Inmediatamente, el
servidor está obligado a solicitar permiso al proceso o procesos que están leyendo del
fichero para que dejen de hacerlo (y lo descarten de la caché), y esperar a que todos los
permisos lleguen antes de conceder el permiso de escritura, lo que introduce una fuerte
sobrecarga en tiempo y ancho de banda en la red.

La introducción de los relojes sincronizados agiliza este tipo de protocolos de los sistemas de ficheros distribuidos. La
idea básica es que cuando un cliente solicita un fichero, el servidor le otorga una concesión en la que detalla el tiempo
de expiración de la misma E. Como cliente y servidor tienen los tiempos sincronizados, el plazo es el mismo en ambos.
Mientras dura la concesión, el cliente tiene la garantía de que opera sobre el fichero de forma consistente. Un cliente no
necesita comunicar al servidor que ha terminado la operación de lectura.
        Si un cliente solicita la escritura de un fichero, el servidor debe pedir a los
clientes lectores la terminación prematura de la concesión. ¿Qué ocurre cuando no hay
respuesta por parte del cliente lector? El servidor no sabe si el cliente simplemente se
ha caído. En este caso, el servidor no obtiene respuesta, lo que plantearía un problema
en el algoritmo tradicional. Con los relojes sincronizados, simplemente espera a que
cumpla el plazo de la concesión del fichero.


          3.2    Exclusión mutua

Cuando dos o más procesos comparten una estructura de datos, su lectura o actualización no debe ser simultánea. Para
evitar la simultáneidad de acceso, y con ello la incosistencia de la estructura, el código de acceso y actualización de la
misma se denomina región crítica y su ejecución es protegida mediante construcciones como semáforos, monitores, etc.
En esta sección examinamos algunos ejemplos de cómo construir regiones críticas en sistemas distribuidos.
          3.2.1     Un algoritmo centralizado

        La forma más directa de conseguir la exclusión mutua en un sistema distribuido es
simular al mecanismo de los sistemas centralizados. Se requiere de un proceso que actúa
como coordinador. Este registra las regiones críticas de los procesos. Cuando un proceso
desea entrar en una región crítica envía un mensaje al coordinador con el número de la
región crítica. Si ningún otro proceso está ejecutando la región crítica, el coordinador
envía una réplica al proceso con la concesión de entrada, tal y como muestra la figura
3.5. Cuando la réplica llega, el proceso entra en la región crítica.
Fig. 3.5 a) Solicitud y concesión de entrada en región crítica. b) La concesión se retrasa hasta mientras la región crítica
esté en uso. c) Concesión tras ser liberada
        Supongamos que el proceso 3 de la figura desea entrar en la misma región crítica
antes de que el proceso 2 salga. La petición llega al coordinador, que sabiendo que el
proceso 2 está dentro, no envía réplica alguna al proceso 3, que permanece bloqueado
esperándola -también se puede implementar la denegación mediante un mensaje-, pero lo
registra en la cola de la región como solicitante. Cuando el proceso 2 sale de la región
crítica lo comunica al coordinador mediante un mensaje de liberación. El coordinador
procesa el mensaje determinando si existe en la cola de la región recién liberada algún
proceso esperando. En nuestro caso, efectivamente lo hay. Es el proceso 3, que por fin
recibe el mensaje de concesión de entrada.

        Este algoritmo garantiza la exclusión mutua. Primero, el coordinador sólo permite
entrar en la misma a un proceso. Segundo, es justo, ya que las peticiones son atendidas
en el orden en que llegan. Tercero, ningún proceso espera indefinidamente por la entrada.
El esquema es fácil de implementar y es eficiente, ya que requiere tres mensajes para
usar una región crítica. El defecto principal del algoritmo, como todos los algoritmos
centralizados es la existencia de un único punto de fallo.

            3.2.2    El algoritmo distribuido de Ricart y Agrawala

        Ricart y Agrawala           presentaron en 1981 un algoritmo de exclusión mutua
distribuido. Consideramos           un conjunto de N procesos con una esctructura sencilla en la
que alternan los cálculos           fuera de la región crítica y dentro de la región crítica. Las
condiciones del algoritmo           son las siguientes:

1. Los procesos se comunican mediante mensajes de capacidad no nula. 2. Los mensajes pueden llegar a un proceso en
cualquier punto de la ejecución, bien dentro o bien fuera de la región crítica. De cualquier modo una interrupción,
excepción, manejador de señal, etc, se encarga de procesar la llegada del mensaje. 3. Se asume que la comunicación es
fiable y los mensajes entre dos procesos son entregados en el orden en el que fueron enviados. 4. Es preciso una
relación de orden total entre los eventos de todo el sistema.
        Consideramos que para que un proceso entre en la región crítica deben tener el
permiso todos y cada uno del resto de los procesos, permiso que solicita enviando un
mensaje a todos ellos, vía multicasting, difusión o uno a uno. El mensaje acarrea una
etiqueta temporal que es el valor del reloj lógico local correspondiente a su envío.
Cuando un proceso recibe un mensaje de solicitud de permiso, la acción que toma el
proceso receptor es la siguiente:

1. Si el receptor no está en su región crítica y no desea entrar en ella, se dice que está en situación de permiso concedido
(CONCEDIDO) y envía inmediatamente un mensaje de réplica al proceso que solitó el permiso.
2. Si el receptor está ejecutando en su región crítica, se dice que tiene el permiso (OTORGADO), no envía réplica al
emisor y encola la petición. Como vemos, si un proceso no contesta significa que no concede el permiso de entrada.
3. Si el receptor desea también entrar en la región crítica, pero aún no lo ha conseguido se dice que está en estado de
solicitud (SOLICITANDO), compara el reloj del mensaje entrante con el del mensaje que ha enviado al resto de los
procesos para solicitar el permiso. El más bajo gana. Si gana el emisor del mensaje entrante, el receptor envía a este la
réplica. Si gana el receptor, encola el mensaje y no envía réplica.
Inicialización:
            estado:=CONCEDIDO;
Para obtener el permiso:
           estado:=SOLICITANDO;
           multicast de solicitud de permiso al resto;
           T:=Reloj lógico del mensaje de petición;
           Wait until(Número de réplicas recibidas=n-1);
           estado:=OTORGADO;

Cuando se recibe una petición <Ci, pi> en pj:
           if(estado=OTORGADO or (estado=SOLICITANDO and C.pj < C.pi) )
           then
                   Encola la petición de pi sin replicar
           else
                   Replica inmediatamente a pi
           fi

Para conceder el permiso tras abandonar la región crítica:
           estado=CONCEDIDO;
           Replica a todos las peticiones en la cola;

Fig. 3.6 El algoritmo de Ricart y Agrawala
        En conjunto, el algoritmo es más lento, más complicado y menos robusto que el
algoritmo centralizado, de modo que ¿porqué molestarse estudiándolo? Porque demuestra que
un algoritmo distribuido, sin un control central, es posible, lo que estimula el estudio
de soluciones distribuidas más avanzadas.

3.2.3 El algoritmo en anillo
        Esta basado en una disposición de los n procesos que están interesados en
utilizar la región crítica en un anillo lógico. Se concede la entrada en la región
crítica al proceso que obtiene el denominado testigo. El testigo es un mensaje que se
pasa de proceso en proceso en un sentido único recorriendo el anillo. Cada proceso tiene
la dirección del proceso al que pasa el testigo. Cuando un proceso recibe el testigo, si
no está interesado en la región crítica, pasa es testigo a su vecino. Si necesita entrar
en la región crítica, espera bloqueado la llegada del testigo, que es retenido y no es
entregado al vecino sino cuando abandona la región crítica.

        Para obtener el testigo, como máximo se emplean n-1 mensajes. Una desventaja es
que los mensajes se envían continuamente aun en el caso de que ningún proceso reclame el
testigo. Otra es que este algoritmo tiene n puntos de fallo, si bien la recuperación es
más fácil que en los casos anteriores. Si cada vez que se recibe el testigo se envía un
mensaje de confirmación, es sencillo detectar la caída de un proceso y retirarlo del
anillo.


           3.3    Algoritmos de elección

                Una elección es un procedimiento cuya función es elegir un proceso en un
grupo a fin de que este desempeñe un papel determinado, como puede ser centralizar
peticiones de entrada en una región crítica, a modo de coordinador. Vamos a considerar
que los procesos implicados en la elección son idénticos, sin que ninguno de ellos tenga
una característica destacable como para ser el coordinador idóneo. Cada proceso tiene un
identificador único como puede ser su dirección de red. En general, los algoritmos de
elección intentan localizar al proceso con el identificador más alto para hacerlo
coordinador. Para enviar los mensajes, los procesos necesitan conocer las direcciones de
red de todo el grupo de procesos en busca de coordinador, de modo que la elección ya
estaría hecha de antemano. El problema es que los procesos desconocen cuáles de ellos
están aún activos y cuáles no. El requisito que debe cumplir una elección de coordinador
es que esta sea única. Los algoritmos difieren unos de otros en el modo de conseguirlo.

El algoritmo del matón Este algoritmo data de 1982 y es debido a García-Molina. Cuando un proceso se apercibe de que
el coordinador no responde a sus mensajes, inicia una convocatoria de elección. Una elección se desarrolla como sigue:
1. P envía un mensaje de tipo ELECCION a todos los procesos con identificadores más altos. 2. Si ninguno de ellos
responde, P gana la elección y se convierte en el coordinador. 3. En cuanto P recibe el mensaje de respuesta de alguno
de ellos, renuncia a ser el coordinador y su trabajo ha terminado. Cada uno de estos procesos, tras enviar el mensaje,
convocan una elección
En cualquier momento, un proceso puede recibir un mensaje ELECTION de uno de los procesos con identificador
inferior. La rutina que sirve el mensaje envía un mensaje de confirmación y toma el control iniciando una elección, a
menos que ya esté celebrando una. Llega un momento en que todos los procesos renuncian y uno de ellos se convierte
en el nuevo coordinador, hecho que anuncia al resto de los procesos mediante el envío de un mensaje.
Si un proceso que inicialmente estaba caído se recupera, inicia una elección. Si es el de identificador más alto, ganará la
elección y asumirá el papel de coordinador. Siempre gana el proceso de identifica-dor más grande, de ahí el nombre del
algoritmo.
En la figura 3.7 vemos el desarrollo de una elección en un grupo de ocho procesos numerados del 0 al 7, siendo este
último el coordinador que, en un momento dado, deja de estar operativo. El proceso 4 es el primero en darse cuenta de
que el coordinador no responde y convoca una elección, enviando un mensaje de tipo ELECCION a los procesos 5, 6 y 7,
los dos primeros confirmando el mensaje. En cuanto el proceso 4 recibe la confirmación del proceso 5 da su trabajo por
terminado. Sabe que él no será el coordinador, sino uno de los superiores que han confirmado. Los procesos 5 y 6
convocan elecciones de forma más o menos simultánea. El proceso cinco recibe confirmación del 6 y renuncia. El
proceso 6 no recibe confirmación alguna, de modo que se erige en ganador, algo que anuncia al resto enviándoles un
mensaje COORDINADOR. El proceso 4, que estaba esperando el resultado de la elección -aunque ya lo casi lo conocía-
reanuda su trabajo, esta vez con un nuevo coordinador.
3.4 Transacciones atómicas
El paradigma cliente-servidor proporciona una buena forma de estructurar el sistema y de desarrollar aplicaciones, pero
necesita del concepto de transacción para controlar secuencias complejas de interacciones entre el cliente y el servidor.
Sin transacciones no se puede conseguir que los sistemas distribuidos funcionen en las aplicaciones típicas de la vida
real. Los conceptos de transacciones fueron concebidos para poder abordar la complejidad de las aplicaciones on-line en
sistemas de un único procesador. Estos conceptos, ya veteranos, son hoy día incluso más críticos en la implementa-ción
con éxito de sistemas masivamente distribuidos, que operan y fallan en formas mucho más complejas.
Los sistemas de proceso de trasacciones fueron pioneros en conceptos de computación distribuida y computación
tolerante a fallos. Ellos introdujeron los datos distribuidos en aras de la fiabilidad, disponibilidad y prestaciones. Ellos
desarrollaron el almacenamiento tolerante a fallos y el proceso tolerante a fallos a fin de garantizar la disponibilidad de
datos y aplicaciones. Y fueron ellos quienes desarrollaron el modelo cliente-servidor y las llamadas a procedimiento
remoto para la computación distribuida. Y, lo más importante, las propiedades ACID de las transacciones han emergido
como los conceptos unificadores de la computación distribuida ([Gra93]). Como puede apreciarse, no es posible obviar
el tópico de las transacciones atómicas en un curso sobre sistemas distribuidos. En esta sección nos ocupamos de ellas,
tratando algunos de sus múltiples aspectos.
3.4.1 Introducción a las transacciones atómicas

Pensemos en una primitiva de sincronización como un semáforo. Subir o bajar un semáforno es una operación de muy
bajo nivel que obliga al programador a tratar los detalles de la exclusión mutua, la gestión de la región crítica, la
recuperación en caso de fallo, etc, cuando opera sobre datos compartidos. Lo que nos gustaría en un entorno de datos
compartidos y con componentes suscepti-bles de fallo es disponer de primitivas de manipulación de datos de más alto
nivel que permitan al programador:
1. Concentrarse en el problema, ignorando que los datos son accedidos de forma concurrente 2. Ignorar que un fallo
puede dejar los datos en un estado inconsistente.
Estas primitivas se utilizan ampliamente en los sistemas distribuidos (su finalidad es compartir datos y recursos y tienen
más posibilidades de fallo) y se llaman transacciones atómicas.
El uso de las transacciones se remonta a los años 60 cuando los datos se almacenaban en cintas magnéticas. Una base
de datos residía en una cinta. que se llamaba el “fichero maestro”. Las actualizaciones residían en una o más cintas (por
ejemplo las ventas diarias o semanales) llamadas “ficheros de movimientos”. Maestro y movimientos se montaban en el
computador para producir un nuevo fichero maestro, que sería utilizado al día o a la semana siguiente con nuevos
ficheros de movimientos. La ventaja de este método -no reconocida suficientemente en aquellos años- es que si el
programa que llevaba a cabo las actualizaciones fallaba, se producía una caída en la alimentación eléctirica, etc y el
proceso de actualización se interrumpía, siempre se podía descartar la nueva cinta que había quedado a medias y volver
sobre el maestro y las actualizaciones para generar de nuevo el fichero maestro. Así, una actualización del maestro
procedía correctamente hasta el final o no se modificaba en absoluto. Esta propiedad era una transacción atómica sobre
el objeto “fichero maestro”.
Consideremos ahora una aplicación bancaria que realiza una retirada de una cantidad de una cuenta y el ingreso
correspondiente en otra cuenta distinta. Si el computador falla después de la retirada y antes del ingreso, el dinero se
desvanece. Puede que ambas cuentas residan en distintas máquinas y el fallo se deba a una pérdida de la conexión
telefónica entre ambas operaciones. Sería necesario agrupar ambas operaciones en una transacción atómica como en el
ejemplo de la cinta magnética que garantizase que la operación se realiza completamente o no se realiza. La clave reside
en volver al estado inicial de las cuentas si es que se ha producido un fallo en mitad del proceso. Esta habilidad es
proporcionada por las transacciones atómicas.
3.4.2 Servicios transaccionales
Conviene examinar la aplicación bancaria anterior en el contexto del modelo cliente-servidor. Cuando decimos que un
servidor porporciona operaciones atómicas significa que el efecto de desarrollar una operación en beneficio del cliente:
          Está libre de interferencia de las operaciones realizadas en beneficio de otros
clientes
          Bien la operación concluye completamente o no tiene efecto alguno si el servidor
falla.

Una transacción entre un cliente y un servidor es una secuencia de interacciones. El servidor bancario proporciona las
operaciones Depósito, Retirada, Balance, Total Sucursal?. sobre una serie de objetos, en este caso cuentas:
Depósito(Cuenta, Cantidad)
          Deposita la cantidad Cantidad en la cuenta Cuenta

Retirada(Cuenta, Cantidad)
          Retira la cantidad Cantidad de la cuenta Cuenta
Balance(Cuenta) Cantidad
           Devuelve el balance de la cuenta Cuenta

Total Sucursal e Total
           Devuelve la suma de todos los balances

Consideremos un cliente que quiere realizar una serie de operaciones sobre las cuentas A, B, C. La primera operación
transfiere 100 pesetas de A a B. La segunda transfiere 200 pesetas de C a B:
Transacción: T: Retirada(A, 100); Depósito(B, 100); Retirada(C, 200); Depósito(B, 200); End Transacción?(T)
Como vemos, desde el punto de vista del cliente, una transacción es una secuencia de operaciones que se realizan en un
sólo paso, llevando al servidor de un estado consistente a otro. El cliente no es consciente de que otros clientes pueden
realizar operaciones sobre las cuentas A y B. A un servidor de este tipo se le conoce como servidor transaccional o que
provee de un servicio transaccional.
En un servicio transaccional, el cliente, cuando inicia una transacción con el servidor, emite la petición Abrir
Transacción? y el servidor le devuelve un indentificador de transacción. Este indentificador será usado en las
operaciones siguientes. El cliente notifica al servidor el final de la secuencia de operaciones mediante la primitiva Cierra
Transacción?.
Abrir Transacción n Trans
        Arranca en el servidor una nueva transacción y devuelve un único identificador de
transacción o TID, que será usado como parámetro en el resto de las operaciones de la
transacción

Cerrar Transacción?(Trans) r (Compromiso, Aborto)
        Termina la transacción. Si devuelve un compromiso, indica que la transacción se
ha comprometido (se ha realizado en su totalidad). Si devuelve un valor de Aborto, la
transac-ción no se ha realizado.

Abortar Transacción?(Trans)
           Aborta la transacción

La transacción puede abortar por varias razones. Entre ellas la naturaleza misma de la transacción y su desarrollo,
conflictos con otra transacción o el fallo de procesos o máquinas. La transacción puede ser abortada, tanto por el cliente
como por el servidor. Cuando el servidor decide unilateralmente abortar la transacción en curso, la operación en curso
devuelve un código de error como SERVER_ABORT. Veamos cual es el comportamiento de cliente y servidor en
presencia de fallos:
Fallo en el servidor Si un servidor transaccional falla inesperadamente, cuando vuelve a arrancar, aborta toda
transacción no comprometida utilizando un procedimiento de recuperación para restaurar los valores de los items de
datos provisionales a los valores definitivos producidos por la transacción comprometida más recientemente previa al
fallo. Replica al cliente la operación solicitada con un valor SERVER_ABORT. Otra posibilidad es que el cliente dé un plazo
de respuesta al servidor para cada operación emitida. Si el servidor se recupera dentro del plazo, continúa con la
transacción en curso en lugar de abortarla.
Fallo en el cliente Si un cliente falla inesperadamente en el desarrollo de una transacción, el servidor puede dar un plazo
de expiración a la transacción. Si una nueva operación de la transacción no llega en ese plazo el servidor aborta la
transacción e inicia el procedimiento de recuperación.
3.4.3 Propiedades de las transacciones atómicas
Las transacciones tienen cuatro propiedades fundamentales que se conocen por el acrónimo ACID: Atomicidad,
Consistencia, serializabilidad o aislamiento (“Isolation”) y Durabilidad.
3.4.3.1 Atomicidad
La atomicidad garantiza que la transacción procede hasta que se completa o no se realiza en absoluto. Si se completa,
esto ocurre en una acción indivisible e instantánea. Mientras una transacción está en progreso, otros procesos, estén o
no estén implicados en transacciones, no pueden ver los estados intermedios. Por ejemplo, supongamos una
transacción que se ocupa de añadir octetos a un fichero de 10 octetos. Mientras la transacción esta en curso, otro
proceso debe ver un fichero de sólo 10 bytes. Cuando la transacción se compromete, el fichero instantánemente
aparece con su nuevo tamaño. Un sistema de ficheros que garantiza este comportamiento es un sistema de ficheros
transaccional. La mayoría de los sistemas de ficheros no son transaccionales.
3.4.3.2 Consistencia
La propiedad de la consistencia obliga cumplir ciertos invariantes de los datos del servidor. Por ejemplo, como resultado
de una transferencia interna, una sucursal bancaria debe mantener el mismo dinero en su saldo que antes de que la
transacción se realice. La consistencia de los datos puede ser violada por el cliente si las operaciones que emite no son
consistentes y por el servidor si no dispone de un adecuado mecanismo de control de concurrencia. Si las operaciones
de forman una transacción T que emite un cliente son consistentes, el servidor garantiza que la consistencia de los datos
que T comparte con otra transacción U no va ser violada por la concurrencia de las operaciones de U.
3.4.3.3 Serializabilidad
La tercera propiedad dice que las transacciones deben ser aisladas. Aislada significa transacciones concurrentes en un
servidor no interfieren las unas con las otras. Una forma de lograr el aislamiento es anular la concurrencia del servidor
de modo que ejecute las transacciones de forma estrictamente secuencial, una tras otra. El objetivo de un servidor, sin
embargo es maximizar sus prestaciones, algo que pasa por la atención concurrente al mayor número de transacciones
posible. Esto significa que si un servidor está atendiendo a dos o más transacciones simultáneamente que operan sobre
datos compartidos por los clientes -un fichero, por ejemplo-, el servidor transaccional debe garantizar que el resultado
final de estos datos es aquel que produce una realización estrictamente secuencial de las transacciones. Esta realización,
no obstante, es decidida arbitrariamente por el servidor. Supongamos que un servidor transaccional mantiene una
variable x que es accedida por tres clientes. Las transacciones de los clientes en un momento dado son las siguientes:
Proceso 1: Abrir Transacción; x := 0; x := x + 1; Cerrar Transacción;
 Proceso 2:

Abrir Transacción; x := 0; x := x + 2; Cerrar Transacción;
Proceso 3: Abrir Transacción; x := 0; x := x + 3; Cerrar Transacción;
        Las peticiones de las distintas transacciones llegan al servidor entrelazadas. A
cada secuencia de ejecución de las peticiones por parte del servidor se le llama
entrelazado o planificación. Si el servidor es transaccional, no todas las
planificaciones son válidas. En la tabla que sigue vemos tres planificaciones posibles,
donde el tiempo transcurre hacia la derecha:

        Planificación 1                        x := 0;                       x := x + 1;                       x := 0;
x := x + 2;             x := 0;                                  x := x + 3;                   legal
        Planificación 2                        x := 0;                       x := 0;                           x := x
+ 1;             x := x + 2;                             x := 0;                   x := x + 3;
legal
Planificación 3                 x := 0;                         x := 0;                          x := x
+ 1;                x := 0;                         x := x + 2;                  x := x + 3;
ilegal
                                                    tiempo

        En la planificación 1 las transacciones son ejecutadas de forma estrictamente
secuencial, y el valor final es 3. Decimos que esta planificación ha sido serializada. La
planificación 2 no es serializada, pero es legal por que, al final, x toma un valor que
podría haber sido alcanzado por una planificación estrictamente secuencial. La
planificación 3 es ilegal, ya que x termina con un valor de 5, valor que imposible
alcanzar con una planificación serializada.

        Equivalencia serial
        Si un entrelazado de dos o más transacciones tiene el mismo efecto sobre los
datos que alguna ejecución serializada de dichas transacciones decimos que el entrelazado
es serialmente equivalente. La planificación 2 de la figura es serialmente equivalente.

3.4.3.4 Durabilidad
         Una transacción debe ser durable. Esta propiedad establece que si un servidor
compromete una transacción -por ejemplo con una réplica a una primitiva Cerrar
Transacción(Trans)que devuelva el valor Compromiso-, no importa lo que ocurra, los
cambios son ya permanentes. Ningún fallo después del compromiso puede desacer los
resultados o causar su desaparición, con la consiguiente confusión posterior en el
cliente.

2.3 Bibliografía
[Cou95] Coulouris A. et al.,
           Distributed Systems,
           2nd. Edition. Addison-Wesley, 1995.

[Tan95] Tanenbaum, A.,
         Distributed Operating Systems,
         Prentice-Hall, 1995.
 [Cou94]         Coulouris, G., Distributed Systems, Concepts and Design, Second Edition,
Addison-Wesley, 1994.

[Gra93] Gray, J., Reuter, A., Transaction Processing, Concepts and Techniques, Morgan Kaufmann Publishers, 1993.
[Lam78] Lamport, L., “Time, Clocks, and the Ordering of Events in a Distributed System”, Communications of the ACM,
Number 7, Volume 21, July, 1978. [Lis93] Liskov, B., “Practical uses of syncronized clocks in distributed systems”,
Distributed Computing, No. 6, pp. 211–219, 1993.

2.1.1. Comunicación con los clientes-Servidor (Socket)

Origen de los socket tuvo lugar en una variante del sistema operativo Unix conocida como BSD Unix. En la universidad de
Berkeley, en los inicios del Internet, pronto se hizo evidente que los programadores necesitarían un medio sencillo y
eficaz para escribir programas capaces de intercomunicarse entre sí. Esta necesidad dio origen a la primera
especificación e implementación de sockets.
Cliente-Servidor es el modelo que actualmente domina el ámbito de comunicación, ya que descentraliza los procesos y
los recursos. Es un Sistema donde el cliente es una aplicación, en un equipo, que solicita un determinado servicio y
existe un software, en otro equipo, que lo proporciona.
Los servicios pueden ser;
a)Ejecución de un programa.
b)Acceso a una Base

2.1.2 comunicacion con rpc

RCP (REMOTE PROCEDURE CALL)

El mecanismo general para las aplicaciones cliente-servidor se proporciona por el paquete Remote Procedure Call (RPC).
RPC fue desarrollado por Sun Microsystems y es una colección de herramientas y funciones de biblioteca. Aplicaciones
importantes construidas sobre RPC son NIS, Sistema de Información de Red y NFS, Sistema de Ficheros de Red.
Un servidor RPC consiste en una colección de procedimientos que un cliente puede solicitar por el envío de una petición
RPC al servidor junto con los parámetros del procedimiento. El servidor invocará el procedimiento indicado en nombre
del cliente, entregando el valor de retorno, si hay alguno. Para ser independiente de la máquina, todos los datos
intercambiados entre el cliente y el servidor se convierten al formato External Data Representation (XDR) por el emisor,
y son reconvertidos

a la representación local por el receptor. RPC confía en sockets estandard UDP y TCP para transportar
los datos en formato XDR hacia el host remoto. Sun amablemente a puesto RPC en el dominio público; se
describe en una serie de RFCs.

La comunicación entre servidores RPC y clientes es un tanto peculiar. Un servidor RPC ofrece una o más colecciones de
procedimientos; cada conjunto se llama un programa y es idenficado de forma única por un número de programa. Una
lista que relaciona nombres de servicio con números de programa se mantiene usualmente en /etc/rpc.
En esta figura, la llamada remota toma 10 pasos, en el primero de los cuales el programa cliente (o procedimiento) llama
al procedimiento stub enlazado en su propio espacio de direcciones. Los parámetros pueden pasarse de la manera usual
y hasta aquí el cliente no nota nada inusual en esta llamada ya que es una llamada local normal.
El stub cliente reúne luego los parámetros y los empaqueta en un mensaje. Esta operación se conoce como reunión de
argumentos (parameter marshalling). Después que se ha construido el mensaje, se lo pasa a la capa de transporte para
su transmisión (paso 2). En un sistema LAN con un servicio sin conexiones, la entidad de transporte probablemente sólo
le agrega al mensaje un encabezamiento y lo coloca en la subred sin mayor trabajo (paso 3). En una WAN, la transmisión
real puede ser más complicada.
Cuando el mensaje llega al servidor, la entidad de transporte lo pasa al stub del servidor (paso 4), que desempaqueta los
parámetros. El stub servidor llama luego al procedimiento servidor (paso 5), pasándole los parámetros de manera
estándar. El procedimiento servidor no tiene forma de saber que está siendo activado remotamente, debido a que se lo
llama desde un procedimiento local que cumple con todas las reglas estándares. Únicamente el stub sabe que está
ocurriendo algo particular.
Después que ha completado su trabajo, el procedimiento servidor retorna (paso 6) de la misma forma en que retornan
otros procedimientos cuando terminan y, desde luego, puede retornar un resultado a un llamador. El stub servidor
empaqueta luego el resultado en un mensaje y lo entrega a la interfaz con transporte (paso 7), posiblemente mediante
una llamada al sistema, al igual que en el paso 2. Después que la respuesta retorna a la máquina cliente (paso 8), la
misma se entrega al stub cliente (paso 9) que desempaqueta las respuestas. Finalmente, el stub cliente retorna a su
llamador, el procedimiento cliente y cualquier valor devuelto por el servidor en el paso 6, se entrega al cliente en el paso
10. El propósito de todo el mecanismo de la Fig.1 es darle al cliente (procedimiento cliente) la ilusión de que está
haciendo una llamada a un procedimiento local. Dado el éxito de la ilusión, ya que el cliente no puede saber que el
servidor es remoto, se dice que el mecanismo es transparente. Sin embargo, una inspección más de cerca revela algunas
dificultades en alcanzar la total transparencia.
2.1.3 comunicacion en grupo


La comunicación se clasifica deacuerdo al numero de usuarios alos que se le a enviado el mensaje.

-BROADCAST O DIFUSION FORZADA un nodo emite todos los escuchan y solo contesta a quien va dirigido el mensaje
-MULTICAST se entrega el msj a todos los anfitriones HOST que están compuestos de ciertas características.
-UNICAST o POINTCAST un nodo emite y otro recibe, solo escucha aquel a quien se dirigió el msj.
Una clasificación adicional es la realizada en base a grupos
-LISTAS DE DESTINARIOS se tiene una lista de aquellos alos que se les enviara el mensaje.
-IDENTIFICADOR DE GRUPO se forman grupos y el msj es dirigido solo a los miembros de ese grupo.
-PREDICADOR DE PERTENENCIA se envía y otro recibe, solo escucha aquel a quien se dirigió el mensaje.
2.1.4 tolerancia a fallos


La difusión de los sistemas distribuidos incrementa la demanda de sistemas que esencialmente nunca
fallen [25, Tanenbaum].

Los sistemas tolerantes a fallos requerirán cada vez más una considerable redundancia en hardware, comunicaciones,
software, datos, etc.
La réplica de archivos sería un requisito esencial.
También debería contemplarse la posibilidad de que los sistemas funcionen aún con la carencia de parte de los datos.
Los tiempos de fallo aceptables por los usuarios serán cada vez menores.

2.2 sincronizacion sistemas distribuidos

En sistemas con una única CPU las regiones críticas, la exclusión mutua y otros problemas de
sincronización son resueltos generalmente utilizando métodos como semáforos y monitores. Estos
métodos no se ajustan para ser usados en sistemas distribuidos ya que invariablemente se basan en la
existencia de una memoria compartida.

No es posible reunir toda la información sobre el sistema en un punto y que luego algún proceso la examine y tome las
decisiones.

En general los algoritmos


distribuidos tienen las siguientes propiedades:

1)- la información relevante está repartida entre muchas máquinas
2)- los procesos toman decisiones basadas solamente en la información local disponible
3) - debería poder evitarse un solo punto que falle en el sistema
4)- no existe un reloj común u otro tiempo global exacto
Si para asignar un recurso de E/S un proceso debe recolectar información de todos los procesos para tomar la decisión
esto implica una gran carga para este proceso y su caída afectaría en mucho al sistema.
Idealmente, un sistema distribuido debería ser más confiable que las máquinas individuales. Alcanzar la sincronización
sin la centralización requiere hacer cosas en forma distinta a los sistemas operativos tradicionales.
2.2.1 relojes fisicos


El algoritmo de Lamport proporciona un orden de eventos sin ambigüedades, pero [25, Tanenbaum]:

Los valores de tiempo asignados a los eventos no tienen porqué ser cercanos a los tiempos reales en los que ocurren. En
ciertos sistemas (ej.: sistemas de tiempo real ), es importante la hora real del reloj: Se precisan relojes físicos externos
(más de uno). Se deben sincronizar: Con los relojes del mundo real. Entre sí. La medición del tiempo real con alta
precisión no es sencilla.
Desde antiguo el tiempo se ha medido astronómicamente.

Se considera el día solar al intervalo entre dos tránsitos consecutivos del sol, donde el tránsito del sol es el evento en
que el sol alcanza su punto aparentemente más alto en el cielo.
El segundo solar se define como 1 / 86.400 de un día solar.
Como el período de rotación de la tierra no es constante, se considera el segundo solar promedio de un gran número de
días.
Los físicos definieron al segundo como el tiempo que tarda el átomo de cesio 133 para hacer 9.192.631.770 transiciones:
Se tomó este número para que el segundo atómico coincida con el segundo solar promedio de 1958. La Oficina
Internacional de la Hora en París (BIH) recibe las indicaciones de cerca de 50 relojes atómicos en el mundo y calcula el
tiempo atómico internacional (TAI). Como consecuencia de que el día solar promedio (DSP) es cada vez mayor, un día
TAI es 3 mseg menor que un DSP:
La BIH introduce segundos de salto para hacer las correcciones necesarias para que permanezcan en fase: El sistema de
tiempo basado en los segundos TAI. El movimiento aparente del sol. Surge el tiempo coordenado universal (UTC). El
Instituto Nacional del Tiempo Estándar (NIST) de EE. UU. y de otros países: Operan estaciones de radio de onda corta o
satélites de comunicaciones. Transmiten pulsos UTC con cierta regularidad establecida (cada segundo, cada 0,5 mseg,
etc.). Se deben conocer con precisión la posición relativa del emisor y del receptor: Se debe compensar el retraso de
propagación de la señal. Si la señal se recibe por módem también se debe compensar por la ruta de la señal y la
velocidad del módem. Se dificulta la obtención del tiempo con una precisión extremadamente alta.

2.2.2 relojes logicos

Las computadoras poseen un circuito para el registro del tiempo conocido como dispositivo reloj [25,
Tanenbaum].

Es un cronómetro consistente en un cristal de cuarzo de precisión sometido a una tensión eléctrica que:

    • Oscila con una frecuencia bien definida que depende de:
              o Al forma en que se corte el cristal.
              o El tipo de cristal.
              o La magnitud de la tensión.


    • A cada cristal se le asocian dos registros:
o Registro contador.
             o Registro mantenedor.


    • Cada oscilación del cristal decrementa en “1” al contador.

    • Cuando el contador llega a “0”:
             o Se genera una interrupción.
             o El contador se vuelve a cargar mediante el registro mantenedor.


    • Se puede programar un cronómetro para que genere una interrupción “x” veces por segundo.

    • Cada interrupción se denomina marca de reloj.

Para una computadora y un reloj:

    • No interesan pequeños desfasajes del reloj porque:
             o Todos los procesos de la máquina usan el mismo reloj y tendrán consistencia
interna.
             o Importan los tiempos relativos.

Para varias computadoras con sus respectivos relojes:

    • Es imposible garantizar que los cristales de computadoras distintas oscilen con la misma frecuencia.

    • Habrá una pérdida de sincronía en los relojes (de software), es decir que tendrán valores distintos al ser leidos.

La diferencia entre los valores del tiempo se llama distorsión del reloj y podría generar fallas en los programas
dependientes del tiempo.
Lamport demostró que la sincronización de relojes es posible y presentó un algoritmo para lograrlo.
Lamport señaló que la sincronización de relojes no tiene que ser absoluta:

    • Si 2 procesos no interactúan no es necesario que sus relojes estén sincronizados.

    • Generalmente lo importante no es que los procesos estén de acuerdo en la hora, pero sí importa que coincidan
      en el orden en que ocurren los eventos.

2.2.3 usos de la sincroninizacion manejo de cache comunicacion en grupo exclusion mutua eleccion
transacciones atomicas e interbloqueo


memoria cache
En los sistemas de archivos convencionales, el fundamento para la memoria caché es la reducción de la E/S de disco (lo
que aumenta el rendimiento), en un SAD el objetivo es reducir el tráfico en la red. Esquema Básico, el concepto de
memoria caché es sencillo, si los datos necesarios para satisfacer la solicitud de acceso no se encuentran en la memoria
cache, se trae una copia de servicio al usuario y los accesos se llevan a cabo con la copia de memoria caché.
La idea es conservar allí los bloques de disco de acceso mas reciente, para así manejar localmente los accesos repetidos
a la misma información y no aumentar el tráfico de la red. Se utiliza una política de reemplazo (por ejemplo, la de
utilización menos reciente) para limitar el tamaño de la memoria caché. Políticas de Actualización, la política empleada
para escribir los bloques de datos modificados en la copia maestra del servidor tiene un efecto decisivo sobre la
confiabilidad y el rendimiento del sistema. La política mas sencilla consiste en escribir los datos directamente en el disco
tan pronto se coloquen en una memoria caché. La ventaja de la escritura directa es su confiabilidad, ya que se pierde
poca información si un sistema cliente falla. Sin embargo, esta política requiere que cada acceso de escritura espere
hasta que se envíe la información al servidor, por lo que representa una escritura de escaso rendimiento. La memoria
caché con escritura directa equivale a usar el servicio remoto para accesos de escritura y explotar la memoria cache
únicamente para accesos de lectura. NFS proporciona el acceso de escritura directa.
Consistencia, una maquina cliente se enfrenta al problema de decidir si una copia de datos en memoria caché local es
consistente con la copia maestra ( y por tanto, puede usarse). Si la maquina cliente determina que sus datos en memoria
caché están desfasados, ya no pueden servir para los accesos y hay que colocar en la memoria caché una copia
actualizada de los datos. Existen dos enfoques para verificar la validez de los datos en memoria caché ..:
        Enfoque iniciado por el cliente, el cliente inicia una comprobación de validez,
en la cual se pone en contacto con el servidor y comprueban si los datos locales son
consistentes con la copia maestra.
        Enfoque iniciado por el servidor, el servidor anota, para cada cliente, las
partes de los archivos que coloca en memoria cache, y cuando detecta una inconsistencia,
debe reaccionar. Una posible fuente inconsistencia ocurre cuando dos clientes, que
trabajan en modos conflictivos, colocan en memoria caché un archivo.

Comunicación en grupos (Algoritmos Para la Sincronización de Relojes)
Si una máquina tiene un receptor de UTC, todas las máquinas deben sincronizarse con ella. Si ninguna máquina tiene un
receptor de UTC: • Cada máquina lleva el registro de su propio tiempo. • Se debe mantener el tiempo de todas las
máquinas tan cercano como sea posible. Se supone que cada máquina tiene un cronómetro que provoca una
interrupción “h” veces por segundo. Cuando el cronómetro se detiene, el manejador de interrupciones añade “1” a un
reloj en software. El reloj en software mantiene un registro del número de marcas (interrupciones) a partir de cierta
fecha acordada antes; al valor de este reloj se lo llama “C”.
Algoritmo de Cristian
Es adecuado para sistemas en los que: • Una máquina tiene un receptor UTC, por lo que se la llama despachador del
tiempo. • El objetivo es sincronizar todas las máquinas con ella. Cada máquina envía un mensaje al servidor para solicitar
el tiempo actual, periódicamente, en un tiempo no mayor que è
prontamente con un mensaje que contiene el tiempo actual “CUTC”. Cuando el emisor obtiene la respuesta puede hacer
que su tiempo sea “CUTC”. Un gran problema es que el tiempo no puede correr hacia atrás: • “CUTC” no puede ser
menor que el tiempo actual “C” del emisor. • La atención del requerimiento en el servidor de tiempos requiere un
tiempo del manejador de interrupciones. • También se debe considerar el tiempo de transmisión. El cambio del reloj se
debe introducir de manera global: • Si el cronómetro genera 100 interrupciones por segundo:
           Cada interrupción añade 10 mseg al tiempo.
           Para atrasar solo agregaría 9 mseg.
           Para adelantar agregaría 11 mseg.

La corrección por el tiempo del servidor y el tiempo de transmisión se hace midiendo en el emisor: • El tiempo inicial
(envío) “T0”. • El tiempo final (recepción) “T1”. • Ambos tiempos se miden con el mismo reloj. El tiempo de propagación
del mensaje será (T1 - T0) / 2. Si el tiempo del servidor para manejar la interrupción y procesar el mensaje es “I”: • El
tiempo de propagación será (T1 - T0 - I) / 2. Para mejorar la precisión: • Se toman varias mediciones. • Se descartan los
valores extremos. • Se promedia el resto. El tiempo de propagación se suma al tiempo del servidor para sincronizar al
emisor cuando éste recibe la respuesta.
Algoritmo de Berkeley
En el algoritmo de Cristian el servidor de tiempo es pasivo. En el algoritmo de Berkeley el servidor de tiempo: • Es activo.
• Realiza un muestreo periódico de todas las máquinas para preguntarles el tiempo. • Con las respuestas:
        Calcula un tiempo promedio.
        Indica a las demás máquinas que avancen su reloj o disminuyan la velocidad del
mismo hasta lograr la disminución requerida.

Es adecuado cuando no se dispone de un receptor UTC.
Algoritmos con Promedio
Los anteriores son algoritmos centralizados. Una clase de algoritmos descentralizados divide el tiempo en intervalos de
resincronización de longitud fija: • El i -ésimo intervalo:
           Inicia en “T0 + i R” y va hasta “T0 + (i + 1) R”.
           “T0” es un momento ya acordado en el pasado.
           “R” es un parámetro del sistema.

Al inicio de cada intervalo cada máquina transmite el tiempo actual según su reloj. Debido a la diferente velocidad de los
relojes las transmisiones no serán simultáneas. Luego de que una máquina transmite su hora, inicializa un cronómetro
local para reunir las demás transmisiones que lleguen en cierto intervalo “S”. Cuando recibe todas las transmisiones se
ejecuta un algoritmo para calcular una nueva hora para los relojes. Una variante es promediar los valores de todas las
demás máquinas. Otra variante es descartar los valores extremos antes de promediar (los “m” mayores y los “m”
menores). Una mejora al algoritmo considera la corrección por tiempos de propagación.
Varias Fuentes Externas de Tiempo
Los sistemas que requieren una sincronización muy precisa con UTC se pueden equipar con varios receptores de UTC.
Las distintas fuentes de tiempo generaran distintos rangos (intervalos de tiempo) donde “caerán” los respectivos UTC,
por lo que es necesaria una sincronización. Como la transmisión no es instantánea se genera una cierta incertidumbre
en el tiempo. Cuando un procesador obtiene todos los rangos de UTC: • Verifica si alguno de ellos es ajeno a los demás y
de serlo lo descarta por ser un valor extremo. • Calcula la intersección (en el tiempo) de los demás rangos. • La
intersección determina un intervalo cuyo punto medio será el UTC y la hora del reloj interno. Se deben compensar los
retrasos de transmisión y las diferencias de velocidades de los relojes. Se debe asegurar que el tiempo no corra hacia
atrás. Se debe resincronizar periódicamente desde las fuentes externas de UTC.
Exclusión Mutua
Cuando un proceso debe leer o actualizar ciertas estructuras de datos compartidas: • Primero ingresa a una región
crítica para lograr la exclusión mutua y garantizar que ningún otro proceso utilizará las estructuras de datos al mismo
tiempo. En sistemas monoprocesadores las regiones críticas se protegen con semáforos, monitores y similares. En
sistemas distribuidos la cuestión es más compleja.
Un Algoritmo Centralizado
La forma más directa de lograr la exclusión mutua en un sistema distribuido es simular a la forma en que se lleva a cabo
en un sistema monoprocesador. Se elige un proceso coordinador. Cuando un proceso desea ingresar a una región
crítica: • Envía un mensaje de solicitud al coordinador:
           Indicando la región crítica.
           Solicitando permiso de acceso.

• Si ningún otro proceso está en ese momento en esa región crítica:
           El coordinador envía una respuesta otorgando el permiso.
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2
Unidad 2

Contenu connexe

Tendances

Sockets y canales
Sockets y canalesSockets y canales
Sockets y canalesJuan Anaya
 
Remote Procedure Call (RPC)
Remote Procedure Call (RPC)Remote Procedure Call (RPC)
Remote Procedure Call (RPC)Taty Millan
 
Comunicacion intra procesos con socket
Comunicacion intra procesos con socketComunicacion intra procesos con socket
Comunicacion intra procesos con socketRene Guaman-Quinche
 
Taller Sockets TCP UDP Multicast
Taller Sockets TCP UDP MulticastTaller Sockets TCP UDP Multicast
Taller Sockets TCP UDP MulticastHector L
 
Capitulo 2 comunicacion
Capitulo 2 comunicacionCapitulo 2 comunicacion
Capitulo 2 comunicacionErick Jamett
 
Wsdl bpel4ws chumpitaz
Wsdl bpel4ws chumpitazWsdl bpel4ws chumpitaz
Wsdl bpel4ws chumpitazCalzada Meza
 
Comunicación Cliente-Servidor (Sockets)
Comunicación Cliente-Servidor (Sockets)Comunicación Cliente-Servidor (Sockets)
Comunicación Cliente-Servidor (Sockets)Developer in WPF
 
guia de aprendizaje correo electronico
guia de aprendizaje correo electronicoguia de aprendizaje correo electronico
guia de aprendizaje correo electronicoMaida Cerpa
 
Redes en Linux
Redes en LinuxRedes en Linux
Redes en LinuxHector L
 
estructura_de_un_programa_en_lenguaje_ensamblador
estructura_de_un_programa_en_lenguaje_ensambladorestructura_de_un_programa_en_lenguaje_ensamblador
estructura_de_un_programa_en_lenguaje_ensambladorGloria Azúa
 
Capítulo 4.1 funciones de la capa de transporte
Capítulo 4.1 funciones de la capa de transporteCapítulo 4.1 funciones de la capa de transporte
Capítulo 4.1 funciones de la capa de transporteIsabel Yepes
 

Tendances (20)

Sockets y canales
Sockets y canalesSockets y canales
Sockets y canales
 
Http y tcp/ip
Http y tcp/ipHttp y tcp/ip
Http y tcp/ip
 
Remote Procedure Call (RPC)
Remote Procedure Call (RPC)Remote Procedure Call (RPC)
Remote Procedure Call (RPC)
 
59 Php. Formatos Mime
59 Php. Formatos Mime59 Php. Formatos Mime
59 Php. Formatos Mime
 
Comunicacion intra procesos con socket
Comunicacion intra procesos con socketComunicacion intra procesos con socket
Comunicacion intra procesos con socket
 
Taller Sockets TCP UDP Multicast
Taller Sockets TCP UDP MulticastTaller Sockets TCP UDP Multicast
Taller Sockets TCP UDP Multicast
 
Capitulo 2 comunicacion
Capitulo 2 comunicacionCapitulo 2 comunicacion
Capitulo 2 comunicacion
 
Wsdl bpel4ws chumpitaz
Wsdl bpel4ws chumpitazWsdl bpel4ws chumpitaz
Wsdl bpel4ws chumpitaz
 
El servidor
El servidorEl servidor
El servidor
 
Smtp (protocolo simple de
Smtp (protocolo simple deSmtp (protocolo simple de
Smtp (protocolo simple de
 
Correo electronico
Correo electronicoCorreo electronico
Correo electronico
 
servidores de correo
servidores de correoservidores de correo
servidores de correo
 
Obj 9 capa 5 - sesion
Obj 9   capa 5 - sesionObj 9   capa 5 - sesion
Obj 9 capa 5 - sesion
 
Comunicación Cliente-Servidor (Sockets)
Comunicación Cliente-Servidor (Sockets)Comunicación Cliente-Servidor (Sockets)
Comunicación Cliente-Servidor (Sockets)
 
Practica cliente servidor java
Practica cliente servidor javaPractica cliente servidor java
Practica cliente servidor java
 
guia de aprendizaje correo electronico
guia de aprendizaje correo electronicoguia de aprendizaje correo electronico
guia de aprendizaje correo electronico
 
Redes en Linux
Redes en LinuxRedes en Linux
Redes en Linux
 
estructura_de_un_programa_en_lenguaje_ensamblador
estructura_de_un_programa_en_lenguaje_ensambladorestructura_de_un_programa_en_lenguaje_ensamblador
estructura_de_un_programa_en_lenguaje_ensamblador
 
Programacion en sockets informe
Programacion en sockets informeProgramacion en sockets informe
Programacion en sockets informe
 
Capítulo 4.1 funciones de la capa de transporte
Capítulo 4.1 funciones de la capa de transporteCapítulo 4.1 funciones de la capa de transporte
Capítulo 4.1 funciones de la capa de transporte
 

En vedette

Cuestionario 3
Cuestionario 3Cuestionario 3
Cuestionario 3rey
 
Cuestionario 1
Cuestionario 1Cuestionario 1
Cuestionario 1rey
 
Cuestionario 2
Cuestionario 2Cuestionario 2
Cuestionario 2rey
 
Cuestionario 3
Cuestionario 3Cuestionario 3
Cuestionario 3rey
 
Tutoria 2 seminario de investigacion
Tutoria 2 seminario de investigacionTutoria 2 seminario de investigacion
Tutoria 2 seminario de investigacionLaura Marcela Bernal
 
C:\Fakepath\Unidad I
C:\Fakepath\Unidad IC:\Fakepath\Unidad I
C:\Fakepath\Unidad Irey
 

En vedette (8)

Cuestionario 3
Cuestionario 3Cuestionario 3
Cuestionario 3
 
Cuestionario 1
Cuestionario 1Cuestionario 1
Cuestionario 1
 
Cuestionario 2
Cuestionario 2Cuestionario 2
Cuestionario 2
 
Cuestionario 3
Cuestionario 3Cuestionario 3
Cuestionario 3
 
Presentación1
Presentación1Presentación1
Presentación1
 
Tutoria 2 seminario de investigacion
Tutoria 2 seminario de investigacionTutoria 2 seminario de investigacion
Tutoria 2 seminario de investigacion
 
C:\Fakepath\Unidad I
C:\Fakepath\Unidad IC:\Fakepath\Unidad I
C:\Fakepath\Unidad I
 
Transceiver
TransceiverTransceiver
Transceiver
 

Similaire à Unidad 2

Conexion dinamica
Conexion dinamicaConexion dinamica
Conexion dinamicam_aguirre
 
Capitula 3 funcionalidad y protocolo de la capa de aplicación
Capitula 3 funcionalidad y  protocolo de la capa de aplicaciónCapitula 3 funcionalidad y  protocolo de la capa de aplicación
Capitula 3 funcionalidad y protocolo de la capa de aplicaciónRicardoM724
 
protocolo y funcionalidad de la capa de aplicación
protocolo y funcionalidad de la capa de aplicaciónprotocolo y funcionalidad de la capa de aplicación
protocolo y funcionalidad de la capa de aplicaciónFelipe Villamizar
 
Sesion 08 tel202 2010-1
Sesion 08   tel202 2010-1Sesion 08   tel202 2010-1
Sesion 08 tel202 2010-1kevinXD123
 
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-Sonia Garcia
 
Protocolos y funcionalidades de la capa de aplicacion
Protocolos y funcionalidades de la capa de aplicacionProtocolos y funcionalidades de la capa de aplicacion
Protocolos y funcionalidades de la capa de aplicacionFernando Illescas Peña
 
Ccna explorationTEMA III
Ccna explorationTEMA IIICcna explorationTEMA III
Ccna explorationTEMA IIIaktivfinger
 
Rol de la capa de Transporte - REDES
Rol de la capa de Transporte - REDESRol de la capa de Transporte - REDES
Rol de la capa de Transporte - REDESEdgardo Diaz Salinas
 
capa de aplicacion protocolos
capa de aplicacion protocoloscapa de aplicacion protocolos
capa de aplicacion protocoloskerengisela
 
Protokolos capa de aplicacion
Protokolos capa de aplicacionProtokolos capa de aplicacion
Protokolos capa de aplicacionkerengisela
 
COMUNICACIÓN DISTRIBUIDA
COMUNICACIÓN DISTRIBUIDACOMUNICACIÓN DISTRIBUIDA
COMUNICACIÓN DISTRIBUIDADiana
 
Comunicación entre procesos Sistemas distribuidos
Comunicación entre procesos Sistemas distribuidosComunicación entre procesos Sistemas distribuidos
Comunicación entre procesos Sistemas distribuidosStalin Jara
 
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptx
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptxArquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptx
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptxXavierNavia
 

Similaire à Unidad 2 (20)

Conexion dinamica
Conexion dinamicaConexion dinamica
Conexion dinamica
 
RPC - LLAMADAS REMOTAS
RPC - LLAMADAS REMOTASRPC - LLAMADAS REMOTAS
RPC - LLAMADAS REMOTAS
 
Practica1
Practica1Practica1
Practica1
 
Capitula 3 funcionalidad y protocolo de la capa de aplicación
Capitula 3 funcionalidad y  protocolo de la capa de aplicaciónCapitula 3 funcionalidad y  protocolo de la capa de aplicación
Capitula 3 funcionalidad y protocolo de la capa de aplicación
 
Cliente servidor
Cliente servidorCliente servidor
Cliente servidor
 
protocolo y funcionalidad de la capa de aplicación
protocolo y funcionalidad de la capa de aplicaciónprotocolo y funcionalidad de la capa de aplicación
protocolo y funcionalidad de la capa de aplicación
 
SEMANA 6.pptx
SEMANA 6.pptxSEMANA 6.pptx
SEMANA 6.pptx
 
Sesion 08 tel202 2010-1
Sesion 08   tel202 2010-1Sesion 08   tel202 2010-1
Sesion 08 tel202 2010-1
 
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-
8699418 manual-de-instalacion-y-configuracion-del-servidor-de-correo-postfix-
 
Protocolos y funcionalidades de la capa de aplicacion
Protocolos y funcionalidades de la capa de aplicacionProtocolos y funcionalidades de la capa de aplicacion
Protocolos y funcionalidades de la capa de aplicacion
 
Exploration network chapter4
Exploration network chapter4Exploration network chapter4
Exploration network chapter4
 
Ccna explorationTEMA III
Ccna explorationTEMA IIICcna explorationTEMA III
Ccna explorationTEMA III
 
Rol de la capa de Transporte - REDES
Rol de la capa de Transporte - REDESRol de la capa de Transporte - REDES
Rol de la capa de Transporte - REDES
 
capa de aplicacion protocolos
capa de aplicacion protocoloscapa de aplicacion protocolos
capa de aplicacion protocolos
 
protocolos
protocolosprotocolos
protocolos
 
Protokolos capa de aplicacion
Protokolos capa de aplicacionProtokolos capa de aplicacion
Protokolos capa de aplicacion
 
COMUNICACIÓN DISTRIBUIDA
COMUNICACIÓN DISTRIBUIDACOMUNICACIÓN DISTRIBUIDA
COMUNICACIÓN DISTRIBUIDA
 
Comunicación entre procesos Sistemas distribuidos
Comunicación entre procesos Sistemas distribuidosComunicación entre procesos Sistemas distribuidos
Comunicación entre procesos Sistemas distribuidos
 
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptx
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptxArquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptx
Arquitectura-orientada-a-Servicios.-v-2017.01-Prof.-L.-Straccia.pptx
 
Capitulo 4
Capitulo 4Capitulo 4
Capitulo 4
 

Unidad 2

  • 1. Unidad 2 - La Comunicación en los Sistemas Distribuidos 2.1 comunicacion sod 2.1 Llamada a procedimiento remoto (RPC) En el anterior epígrafe hemos estudiado un modelo de interacción entre los procesos de un sistema distribuido que es el modelo cliente-servidor. Para implementarlo, el sistema dispone de dos llamadas al sistema, send y receive, que las aplicaciones utilizan de forma conveniente. Estas primitivas, a pesar de constituir la base de la construcción de los sistemas distribuidos, pertenecen a un nivel demasiado bajo como para programar de forma eficiente aplicaciones distribuidas. 2.1.1 La operación RPC básica La llamada a procedimiento remoto constituye un mecanismo que integra el concepto cliente-servidor con la programación convencional basada en llamadas a procedimientos. La idea surgió en 1984 y consiste en que el cliente se comunica con el servidor mediante una llamada ordinaria a un procedimiento. Esta llamada se denomina a procedimiento remoto porque el procedimiento invocado se encuentra en otro espacio de direccionamiento, en la misma o en distinta máquina que el cliente. La información se transporta en los parámetros de la llamada y el resultado es devuelto en el retorno de la llamada. El cliente no tiene que utilizar las primitivas send y receive como en el modelo cliente-servidor puro, de modo que la programación de aplicacio-nes distribuidas se hace más sencilla. 2.1.2 El paso de parámetros La función del cabo cliente es empaquetar los parámetros en un mensaje y enviarlo al cabo servidor. Este examina el código del procedimiento en una sentencia tipo switch e invoca el procedimiento de forma local. El resultado es de nuevo empaquetado en un mensaje y enviado al cabo cliente. Esta interacción, que parece directa, no es tan simple como aparenta ser. Mientras las arquitecturas del cliente y del servidor sean iguales no se presenta ningún problema especial. En un entorno distribuido, sin embargo, cada arquitectura tiene su propia representación de números, caracteres, etc. Por ejemplo, los mainframe IBM utilizan el código EBCDIC para los caracteres en lugar del código ASCII, como el IBM PC. Problemas similares ocurren con la representación de coma flotante o los enteros negativos (complemento a 1 o complemento a 2). Otro problema surge con la forma de almacenar un entero. La arquitectura PC mantiene una representación “little endian”, a saber, el byte menos significativo en el byte más bajo de memoria. La arquitectura SPARC utiliza un almacenamiento “big endian”, es decir, el byte más significativo en el byte más bajo de la memoria. Un 486 operando en modo protegido representa un entero con cuatro bytes, de modo que el 5 lo representa como 0005. Un mecanismo adicional de paso de parámetros es denominado de copia-restauración. Consiste en realizar una copia del parámetro en la pila. Si esta copia parámetro es modificada en el procedimiento, se restaura su nuevo valor a la variable original. Algunos compiladores de Ada utilizan este mecanismo en parámetros in out, si bien ello no está especificado en la definición del lenguaje. La estrategia de copia con restauración puede ser utilizada para pasar punteros a procedimientos remotos. Supongamos la invocación del procedimiento remoto cuenta = read(df, buf, nbytes); La implementación más directa consiste en copiar al buffer del mensaje local un vector de “nbytes” caracteres en lugar de buf, que es la referencia al vector. El mensaje es entonces enviado al cabo servidor. Ahora el buffer del mensaje se encuentra en el espacio de direccionamiento de este último, invocará la rutina de servicio read con la referencia al
  • 2. vector recibido en el mensaje, es decir de forma convencional por referencia. Ahora el mensaje es devuelto con su contenido actualizado a la rutina cabo del cliente, que restaura el vector del mensaje a su vector original. Para optimizar este mecanismo eludimos en el cabo cliente la copia del vector al mensaje en caso de lectura. En el caso de la escritura, prescindiremos de restaurarlo. Como vemos, es posible pasar punteros a procedimientos remotos siempre que sean referencias a estructuras sencillas como vectores. No obstante, no podemos enviar a procedimientos remotos referencias a estructuras de datos complejas como listas o árboles. 2.1.3 Especificación de interfase El servidor RPC puede ser considerado como un módulo u objeto que implementa unas operacio-nes sobre datos ocultos. El servidor da a conocer estas operaciones a los clientes mediante lo que se denomina su interface, constituida por las declaraciones de los métodos que soporta. Como sabemos, el objetivo del mecanismo RPC es lograr que un programa tenga acceso a los servicios de uno de estos módulos, aunque residan en otro espacio de direccionamiento, posiblemente remoto. La figura 2.8 muestra los componentes de una implementación RPC. La mitad rayada constituye el software adicional de empaquetamiento y desempaquetamiento de parámetros y primitivas de comunicación que debe ser ocultado al programador. Por brillante que sea la idea de la interacción cliente-servidor a través de RPC, si el programador debe encarar la construcción de los cabos, el progreso de los sistemas distribuidos se verá comprometido por la falta de uso en la práctica. Es preciso que la generación de cabos en el cliente y el servidor se realice de forma automática. Pues bien, la interfaz del servidor se utiliza como la base de esta generación automática de cabos. El primer paso es definir el interfaz, es decir, el conjunto de los prototipos de los procedimientos de servicio, mediante un lenguaje determinado, denominado lenguaje de interfase. La figura 2.8, a) muestra un ejemplo de servidor. La figura 2.8, b) su definición de interfaz. Un compilador especial toma como entrada el fichero escrito en el lenguaje de interfase y como salida genera el código objeto de los procedimientos que constituyen el cabo cliente, por una parte, y el cabo servidor, por la otra. El programa cliente se enlaza con estos procedimientos objeto para generar el ejecutable. En cuanto al servidor, los procedimientos de servicio, escritos por el programador, se compilan previamente a lenguaje objeto y, a continuación, se enlazan con los procedimientos cabo, entre los que figura el procedimiento principal del servidor RPC. 1. include <header.h> void main(void) { struct mensaje m1, m2; /* Mensajes entrante y saliente */ int r; while(1) { receive(FILE_SERVER, &m1); /* El servidor se bloquea esperando un mensaje */ switch(m1.opcode) { case CREATE: r = do_create(&m1, &m2); break; case READ: r = do_read(&m1, &m2); break; case WRITE: r = do_write(&m1, &m2); break; case DELETE: r = do_delete(&m1, &m2); break; case DELETE: r = E_BAD_OP; break; } m2.result = r; send(m1.source, &m2); }
  • 3. } a) 1. include <header.h> specification of file_server, version 3.1 long read(in char name[MAX_PATH], out char buf[BUF_SIZE], in long bytes, in long position); long write(in char name[MAX_PATH], in char buf[BUF_SIZE], in long bytes, in long position); int create(in char[MAX_PATH], in int mode); int delete(in char[MAX_PATH]); end; b) 2.1.4 Enlace dinámico No es conveniente que un servicio esté ligado a una máquina. A veces las máquinas no están operativas, de modo que los servicios se mueven a otra máquina. El cliente está interesado en el servicio, no en qué máquina ejecuta el servidor. Para solicitar un servicio, un cliente podría enviar un mensaje en una sentencia como la siguiente send(33.33.33.33@20, &mens); en el código fuente que implementa la llamada RPC. Esta solución es inflexible, puesto que, si dentro de la máquina 33.33.33.33 el servidor pasa a escuchar en otro puerto distinto del 20, el cliente debe ser recompilado. Lo mismo ocurre si el servidor cambia de máquina. En contraste, el cliente debería invocar el servicio por su nombre, sin hacer referencia a dirección alguna. La figura 2.8 b) muestra la especificación formal del servidor de ficheros 2.8 a). En la especificación formal del servidor intervienen el nombre del servidor y su número de versión. Ambos datos identifican un servidor. Un servidor con el mismo nombre y la misma versión, no obstante, pueden estar replicados en dos o más máquinas a fin de mejorar el servicio o propor-cionar tolerancia a fallos. El cliente debe solicitar un servicio invocando su nombre y versión, sin citar dirección alguna. El número de versión es conveniente a fin de que un servidor que evoluciona conserve su nombre. Un servidor puede evolucionar ofertando nuevos servicios, cancelando otros y modificando otros. A pesar de esta evolución, es preciso que clientes antiguos, desconocedores de los cambios, sigan obteniendo el mismo tipo de servicio. Es preciso compren-der, no obstante, que un servidor con el mismo nombre pero con número de versión distinto es un servidor diferente. Las ventajas de identificar al servidor por su nombre son evidentes, pero, ¿cómo el cliente localiza al servidor? ¿Quién le proporciona su dirección? Este es un problema al que algunos sistemas RPC, entre ellos Sun RPC, dan respuesta mediante lo que se llama el enlace dinámico, que no es sino averiguar la dirección del servidor en tiempo de ejecución. El enlace dinámico está basado en un tercer proceso denominado el enlazador. Cuando el servidor arranca, en su código de inicialización previo al bucle principal, envía un mensaje al enlazador a fin de registrarse como un proceso que presta un servicio. El enlazador es, al fin y al cabo, un registrador de servicios, un servidor de nombres. El servidor entrega su nombre, su número de versión y su dirección. Se dice que el servidor exporta su interfaz. No sería extraño que dos programadores diesen el mismo nombre a dos servidores distintos, de modo que, a pesar de que no aparezca, cada servidor RPC tiene asociado, además del nombre y la versión, un identificador numérico, generalmente de 32 bits, que también entrega en la operación de registro. Dos servidores distintos deben tener identificadores distintos (se entiende aquí servidor como programa, no como proceso). Si bien sería raro, es posible que dos programadores que terminan dos
  • 4. servidores RPC, coincidan en darles el mismo identificador. Lo que ocurra cuando ambos traten de registrarse depende de cada implementación particular del software RPC, pero es lógico pensar que el enlazador rechazaría la segunda petición de registro. 2.1.5 Semántica RPC en presencia de fallos El objetivo de la llamada a procedimiento remoto es conseguir la ejecución de procedimientos en otras máquinas sin cambiar la forma en que se invoca el procedimiento en el código fuente. Salvo algunas excepciones como que un procedimiento remoto no puede usar variables globales, el objetivo ha sido alcanzado plenamente. Mientras no se produzcan errores la transparencia de la llamada remota está conseguida, ya que el programador no necesita saber que la llamada que realiza es a un procedimiento remoto. Los problemas llegan cuando bien cliente o bien servidor dejan de operar correctamente, ya que las diferencias entre llamadas locales y remotas no son fáciles de enmascarar. Vamos a considerar cinco situaciones de fallo: 1. El cliente no es capaz de localizar al servidor. 2. El mensaje del cliente al servidor se pierde. 3. El mensaje de réplica de servidor a cliente se pierde. 4. El servidor se cae tras recibir el mensaje del cliente. 5. El cliente se cae tras recibir la réplica. El cliente no puede localizar al servidor Puede haber varias causas. Una es que el servidor se cae. Otra es que el servidor se actualiza y un cliente antiguo invoca una versión del servidor que ya no ejecuta. Una solución es que la llamada devuelva −1 como código de error. Sin embargo, −1 puede ser un resultado válido como en la llamada RPC de suma. Otro intento de solución es escribir un manejador de excepción (señales en C) para los errores producidos en las llamadas RPC. Sin embargo, esta solución acaba con la transparencia respecto a las llamadas locales. Lo mejor es recibir el resultado en parámetros de salida de la llamada RPC y que esta devuelva 0 en caso de ejecución con éxito y un código de error en otro caso. La petición del cliente se pierde Este caso tiene un tratamiento sencillo. El núcleo del cliente arranca un temporizador cuando envía el mensaje al servidor. Si al cabo de un plazo no ha llegado réplica o reconocimiento del servidor, el cliente da el mensaje por perdido y lo reenvía. Si todos los reenvíos se pierden, el kernel del cliente considera que el servidor no está activo y devuelve un error al cabo cliente, que lo pasa a la aplicación. Estamos en el caso anterior. La réplica del servidor se pierde Este problema es más complejo. Cuando en el caso anterior venció el plazo sin que llegase la respuesta del servidor, asumimos que se había perdido el mensaje enviado por el cliente. Pero existe la posibilidad de que el mensaje perdido fuese la réplica. De cualquier forma, establecimos que lo que había que hacer era el reenvío del mensaje. En el primer caso, el servidor recibe el mensaje reenviado por primera vez. Todo vuelve a funcionar correctamente. En el segundo caso el servidor recibe el mensaje por segunda vez. Sirve la petición dos veces, como si en el programa cliente hubiésemos invocado la llamada una segunda vez. En algunos casos, la repetición de una operación en el servidor no causa ningún daño. Por ejemplo, el leer los 20 primeros bytes de un fichero. Las peticiones que tienen esta propiedad se dicen que son idempotentes. Otras veces, la re-petición sí ocasiona perjuicios, como puede ser el añadir 20 bytes a ese fichero o retirar de una cuenta bancaria 500 millones de pesetas. La solución a este problema pasa por numerar las peticiones. Las retransmisiones llevan el mismo número de secuencia que la transmisión original. Entonces el kernel del servidor detecta que la réplica se ha perdido y la reenvía, sin operar sobre el servidor. Una versión distinta de esta solución es introducir en la cabecera de la petición un bit de retransmisión. El servidor se cae La figura 2.10 a) muestra la secuencia de eventos producidos en un servidor en el servicio de una petición. El sistema operativo del servidor recibe el paquete entrante con el mensaje, que entrega al cabo para que invoque la ejecución del procedimiento que sirve la petición. A continuación, el cabo pasa la réplica al sistema operativo que lo envía en un paquete al cliente. Ahora bien, tras haberse ejecutado el procedimiento de servicio, el servidor puede sufrir una caída que impide la emisión de la réplica al cliente. Es el caso b) de la figura. Por el contrario, la caída puede producirse tras la recepción del paquete, pero previamente a la ejecución del procedimiento de servicio. Es el caso c).
  • 5. Las consecuencias de los casos b) y c) es diferente. Supongamos que la operación remota es escribir un texto en la impresora. El servidor primero carga el texto en la memoria interna de la impresora y después escribe en un registro de la misma para iniciar la impresión. El servidor puede caerse antes de establecer el bit o después de establecer el bit. En el primer caso, la operación no será realizada. En el segundo caso, sí, ya que la impresora continúa su trabajo con independencia de que el servidor esté activo o no lo esté. Podemos pensar que este caso tiene la misma complejidad que la pérdida de la réplica, examina-da en el caso anterior. No es así. La pérdida de la réplica supone un reenvío de la solicitud de impresión. El núcleo del servidor se dará cuenta de que el mensaje tiene un número de secuencia repetido y enviará de nuevo la réplica si repetir la impresión. En contraste, la caída del servidor supone la pérdida del registro de los números de secuencia de mensajes del cliente. Por esta razón, tras un rearranque, el servidor no puede saber si la re-petición de impresión ha sido servida con anterioridad, de modo que volverá a ser servida. Si la caída se produjo en el caso c) la impresión no se hizo, de modo que reiniciar la operación es lo correcto. Sin embargo, si la caída se produjo en el caso b) reiniciar la operación supone repetirla. Lo peor del caso b) es que ni cliente ni servidor sabrán nunca si la operación se realizó con anterioridad o no. 2.1.6 Implementación de software RPC El éxito o el fracaso de un sistema operativo distribuido radica en sus prestaciones. Si un sistema es lento, no tiene éxito. Las prestaciones de un sistema operativo distribuido radican en gran parte en la velocidad de las comunicaciones, y esta velocidad depende fundamentalmente de la implementación del protocolo de comunicación más que en sus principios abstractos. En esta sección vamos a discutir la implementación de software RPC. Protocolos RPC En los sistemas comerciales actuales, el software RPC está implementado como una biblioteca de funciones que el programa de usuario invoca. Tanto el cabo cliente como el cabo servidor no son sino un conjunto de llamadas a funciones de la biblioteca RPC. Veamos el ejemplo de Sun RPC. El siguiente mandato UNIX es el que se utiliza para compilar el programa cliente rdate de la figura 2.9. # cc -o rdate rdate.c date_clnt.c -lrpclib donde se aprecia el enlace de la biblioteca de Sun RPC, rpclib. El mandato para generar el servidor RPC es similar. La aplicación de usuario rdate invoca funciones RPC del cabo que, a su vez, invocan las llamadas al sistema de comunicaciones del sistema operativo para enviar los mensajes al servidor RPC. Así, el software RPC puede entenderse como un nivel de servicio entre cliente o servidor y el sistema operativo, tal como ilustra la figura 2.11. Generalmente, las llamadas al sistema de comunicaciones de los sistemas UNIX están implementadas mediante la pila de protocolos TCP/IP, que forman parte del núcleo de UNIX. IP es el protocolo de nivel de red (nivel tres en la pila OSI). TCP es uno de los protocolos de transporte de la pila TCP/IPTCP es un protocolo del nivel de transporte (nivel cuatro en la pila OSI), orientado a conexión. La comunicación entre dos procesos mediante conexión se basa en establecer un circuito virtual entre ambas máquinas antes del hacer envío alguno. El establecimiento de una conexión es costoso en tiempo y recursos, pero garantiza la fiabilidad total de la comunicación. 2.2 Comunicación de grupos La comunicación RPC tiene dos partes, una, el cliente, dos, el servidor. Hay situaciones en que este modelo no es el idóneo en un sistema con un conjunto de servidores de ficheros replicados a fin de proporcionar tolerancia a fallos. Un programa cliente que hace una escritura a disco debe hacer llegar la petición simultáneamente a todos los servidores y no a uno de ellos únicamente. El problema puede solucionarse invocando tantas llamadas RPC como servidores existentes. Existe, sin embargo, otro paradigma de comunicación disponible para los sistemas distribuidos que es la comunicación de grupos, más apropiado en casos como este. 2.2.1 Introducción a la comunicación de grupos
  • 6. La característica principal de un grupo de procesos es que cuando se envía un mensaje al grupo, todos sus componentes lo reciben. Por otra parte, los grupos son dinámicos. Los grupos nacen y mueren y en cada grupo terminan algunos procesos y se incorporan otros. Por lo tanto es necesario un mecanismo de gestión de grupos. Un proceso puede pertenecer a más de un grupo y abandonar un grupo para unirse a otro. Un grupo es una abstracción cuyo propósito es evitar, en las llamadas de comunicación con grupos de procesos, parámetros molestos como el número de elementos en el grupo o la localización de cada proceso del grupo y proporcionar primitivas más potentes y transparentes, como el ejemplo anterior de envío de un mensaje a un conjunto de servidores de ficheros. El cliente no debería saber cuantos servidores están disponibles en cada momento ni en qué máquinas concretas han sido arrancados. La implementación de grupos depende mucho del hardware de comunicación disponible. En algunas redes, como ethernet, existen unas direcciones especiales en las que pueden escuchar más de una máquina. Para ello es necesario configurar el adaptador de red ethernet en cada máquina. Un único marco o enviado a esta dirección es leído por todas las máquinas que escuchan en ella. Estas direcciones se denominan multicasting. Si el nivel de enlace de la red soporta multicasting, como es el caso de ethernet, la implementación de grupos es sencilla. Basta asignar a cada grupo una dirección multicasting diferente. Existen redes que si bien no admiten multicasting, sí admiten difusión. Marcos ethernet con la dirección de destino 111…111 son recibidos por todas las máquinas de la red. La difusión puede ser utilizada para implementar grupos, pero es menos eficiente, porque el marco se envía a todas las máquinas, tanto las que pertenecen al grupo como las que no. De todas formas, el envío al grupo de procesos requiere de un solo paquete. Si el nivel de enlace no proporciona multicasting ni difusión, aún es posible la implementación de grupos. Para ello, el emisor debe enviar un paquete particular a cada miembro del grupo. Por supuesto, esta es la implementación menos eficiente. 2.2.2 Aspectos de diseño La comunicación de grupos comparte muchos aspectos de la comunicación estándar de paso de mensajes, tales como primitivas con buffer o sin buffer, bloqueantes o no bloqueantes, etc. No obstante, existen más posibilidades adicionales a elegir en la comunicación de grupos. En esta sección examinamos algunos de estos aspectos particulares en la comunicación de grupos. 2.2.2.1 Grupos cerrados frente a grupos abiertos Los protocolos que soportan comunicación de grupos pueden dividirse en dos categorías. Una es la de los grupos cerrados. En ellos sólo los miembros del grupo pueden enviarse mensajes entre sí. Procesos que no pertenecen al grupo no pueden enviar mensajes al grupo como tal, si bien, por supuesto, sí pueden enviar mensajes particulares a cada miembro del grupo a título particular. Otros protocolos soportan grupos abiertos. Un proceso que no pertenece a un grupo puede enviar mensajes a este grupo. Los grupos cerrados son utilizados típicamente en procesa-miento en paralelo, donde los procesos tienen su propio cometido y no interactúan con el mundo exterior. Los grupos abiertos son apropiados para problemas como el de los servidores replica-dos, donde un cliente envía una petición al grupo. Los miembros del grupo también necesitan hacer uso de la comunicación en grupo y no sólo un proceso externo, por ejemplo para decidir quién debe ejecutar una petición dada. 2.2.2.2 Grupos de iguales frente a grupos jerárquicos En algunos grupos un proceso es el jefe o coordinador y el resto trabajan para él. En otros, todos los procesos tienen la misma categoría y las decisiones se toman de forma colectiva. En el primer caso, cuando uno de los trabajadores o un cliente externo solicita una petición, esta es enviada al coordinador, que decide cuál de los trabajadores es el más apropiado para servirla. Cada una de estas organizaciones tiene sus ventajas y sus inconvenientes. Los grupos pares no tienen un único punto de fallo. Si un trabajador deja de existir, la carga se reparte en el resto. Sin embargo, incurren en el retraso que supone el ponerse de acuerdo para decidir quién sirve una petición. Los grupos jerárquicos tienen las propiedades opuestas. 2.2.2.3 Pertenencia a grupos
  • 7. Se necesita un método para crear, destruir y modificar los grupos. Una solución es introducir un proceso denominado el servidor de grupos. El servidor de grupos mantiene tablas con los grupos existentes y sus integrantes. Esta solución es eficiente y fácil de implementar. El problema es que el servidor de grupos es una técnica centralizadora y, como tal, constituye un único punto de fallo. La opción opuesta es la gestión distribuida. Un nuevo proceso que se incorpora al grupo puede enviar un mensaje al grupo y todos los procesos toman nota de su existencia. Cuando un proceso del grupo termina, envía un mensaje de adiós. Surge un problema cuando un proceso del grupo termina inesperadamente. El resto del grupo tiene que descubrirlo experimentalmente, ya que el proceso nunca responde a nada. Cuando todos los miembros lo han constatado, se le da de baja. 2.2.2.4 Direccionamiento de grupos Para dirigir un mensaje a un grupo, el grupo debe tener una dirección. Si el nivel de enlace de la red -en adelante, la red- soporta multicasting, se puede implementar una dirección de grupo como una dirección multicasting. Si la red soporta difusión, pero no multicasting, el mensaje debe ser recibido por todos los núcleos y extraer de él la dirección del grupo. Si ninguno de los procesos de la máquina es miembro del grupo, el mensaje es descartado. En otro caso, es pasado a todos los procesos que pertenecen al grupo. Si la red no soporta ni difusión ni multicasting, el núcleo de la máquina emisora tendrá que tener una lista de los procesos que pertenecen al grupo y enviar un mensaje a cada uno de los componentes del grupo. 2.2.2.5 Primitivas send y receive No es conveniente que los procesos de usuario puedan utilizar las primitivas send y recei-ve por separado. Según Tanenbaum, send y receive se corresponden en programación distribuida con la construcción “go to” en programación convencional. Su utilización provoca más trastornos que utilidad. Si RPC es la primitiva de comunicación usada por los procesos de usuario, la comunicación de grupo debiera poder construirse mediante RPC. El problema es tratar con una llamada a procedimiento que devuelve tantos valores como procesos tiene un grupo. No parece posible, de modo que una aproximación común es volver a las primitivas send y receive en los procesos de usuario. Si se permite send y receive a los procesos de usuario, se pueden aprovechar estas primitivas para realizar la comunicación de grupo. En el caso de la comunicación convencional cliente servidor, el primer parámetro de send es un número de puerto en la red y el segundo parámetro es el mensaje. Se puede utilizar send para la comunicación de grupos empleando como primer parámetro la dirección de un grupo de procesos en lugar de un puerto determinado. Así unifica-mos la comunicación punto a punto y la comunicación de grupos en una primitiva única. La implementación de send que haga el núcleo o la rutina de biblioteca puede ser una de las tres citadas en el apartado de direccionamiento de grupos. send puede ser con buffer o sin buffer, bloqueante o no bloqueante, fiable o no fiable, etc, igual que en la comunicación punto a punto. La comunicación de grupo no cambia las cosas. Enviar a un grupo obliga al núcleo del sistema que envía a hacer una comunicación multicasting a todos los miembros del grupo, pero ¿qué es recibir de un grupo? Puede entenderse que todos los miembros del grupo van a enviar una réplica diferente y por lo tanto un envío a un grupo debería continuar en el programa de usuario con tantas operaciones receive como miembros tuviese el grupo. Ello, no obstante, significa una pérdida de transparencia, ya que un proceso externo no debe conocer la estructura interna de un grupo. 2.2.2.6 Atomicidad de la difusión Una de las características de la comunicación de grupos es que un mensaje enviado a un grupo debe ser recibido por todos los miembros del grupo o por ninguno de ellos. A esta propiedad se la denomina la atomicidad de la difusión o simplemente la atomicidad. La atomicidad facilita en gran medida la programación de sistemas distribuidos. Supongamos, por ejemplo, una base de datos distribuida. Una base de datos distribuida puede tener una relación cuyos atributos estén repartidos en máquinas dispersas geográficamente. El acceso a una tupla significa enviar un mensaje a
  • 8. todas las máquinas. Supongamos la creación de una tupla de estas características. Si uno de los mensajes se pierde, la base de datos queda en un estado inconsistente. La tupla debe crearse en su totalidad o no crearse y la aplicación ser informada del éxito o del fracaso de la operación entera, no sólo un éxito parcial. Implementar la atomicidad de la difusión no es tan simple como parece. Por ejemplo, uno de los adaptadores de red tal vez acaba de recibir un paquete y antes de que esté preparado para recibir uno nuevo, llega el paquete de difusión, que no puede ser aceptado y simplemente se pierde. Todas las máquinas del grupo han recibido el paquete excepto una, lo que arruina la difusión completa. Para cerciorarse de que todo ha ido bien, el emisor de la difusión debe esperar las confirmaciones de los miembros del grupo. Si una falta, deberá repetir la difusión o reenviar el mensaje en particular. Puede ocurrir que antes de repetir la difusión o hacer el reenvío, el emisor de la difusión se caiga. En esta situación, el cliente debe rearrancar, pero nunca sabrá cuántos son los mensajes que realmente han sido enviados y cuántos los que han fallado. Algunos miembros del grupo han recibido el mensaje y otros no. Una situación inaceptable e ¿incorregible? No, queda alguna esperanza. Existe un algoritmo que demuestra que la atomicidad es posible. El emisor realiza la difusión, inicializa temporizadores y realiza los reenvíos necesarios. Cuando un miembro del grupo recibe un mensaje nuevo, envía el mensaje a todos los miembros del grupo -de nuevo utilizando temporizadores y retransmisiones si son necesarias-. Si el mensaje no es nuevo, simplemente es descartado. No importa cuantas máquinas caigan en el proceso de envíos y reenvíos, lo importante es que de los procesos supervivientes en el grupo todos han recibido el mensaje. 2.2.2.7 Ordenación de mensajes Para que la comunicación en grupo sea fácil de usar y comprender requiere de dos propieda-des. La primera es la atomicidad, examinada más arriba y la segunda es el orden de los mensajes. Supongamos cinco máquinas, cada una con un proceso. Los procesos 0, 1, 3 y 4 pertenecen a un grupo de procesos. Supongamos que los procesos 0 y 4 deciden enviar un mensaje al resto de los procesos del grupo. Supongamos que el proceso 0 lo ha decidido un instante de tiempo antes. La propiedad de orden temporal global exige que cada miembro del grupo reciba primero el mensaje del proceso 0 y después el mensaje del proceso 4. Una red local que soporte difusión garantiza el orden temporal global. Todos los mensajes del proceso 0 llegan al resto del grupo ya que el paquete con dirección difusión es recibido por todos los adaptadores de red de forma simultánea. Sólo después, cuando el mensaje ha sido enviado y deja libre el canal el proceso 4 puede emitir su paquete de difusión. Una red sin difusión no garantiza el orden temporal global, que debe implementar la difusión enviando cuatro mensajes consecutivos que pueden entrelazarse con los del proceso 4. Así, el proceso 1 puede recibir primero el mensaje del proceso 0 y después el del 4 y el proceso 3 puede recibir primero el mensaje del proceso 4 y después el del proceso 0. 2.2.2.8 Grupos solapados En el apartado anterior vimos el problema de la ordenación temporal global aplicada a un grupo dado. Dos procesos del mismo grupo enviaban simultáneamente un mensaje al grupo. Hemos mencionado previamente que un proceso puede pertenecer a más de un grupo, de manera que los grupos pueden solaparse. Este solapamiento produce un nuevo tipo de inconsistencia temporal. La figura 2.14 muestra el problema planteado. Los procesos A y D, en distinto grupo, envían simultáneamente un mensaje a su propio grupo. Como en el caso anterior supongamos que la red no proporciona difusión y esta se implementa mediante unicasting. El envío simultáneo es consitente si B y C reciben primero el mensaje del grupo 1 y después el mensaje del grupo 2 (o viceversa). Unicasting no puede garantizar esto, de modo que es posible el escenario de la figura 2.14. B recibe el mensaje dirigido al grupo 1 y después el mensaje al grupo 2. C, por el contrario, primero recibe el mensaje dirigido al grupo 2 y después el mensaje al grupo 1. Fig. 2.14 Cuatro procesos y cuatro mensajes. B y C toman los mensajes de A y D en diferente orden. Una comunicación de grupo que garantiza que esto no ocurre se dice que tiene la propiedad de orden temporal entre grupos solapados. La implementación del orden temporal entre grupos solapados es costosa y difícil de implementar, de modo que algunos sistemas distribuidos la implementan y otros no, actualmente la mayoría de ellos.
  • 9. 2.2.2.9 Escalabilidad Muchos algoritmos de comunicación de grupos funcionan bien siempre que los grupos sean pequeños y haya pocos grupos, pero ¿qué ocurre cuando cada grupo tiene muchos procesos y hay miles de grupos? Y ¿qué ocurre cuando los grupos se extienden geográficamente entre continen-tes? Para ellos es preciso sobrepasar los estrechos límites de la red local e introducir encaminado-res y muchas redes locales. La presencia de encaminadores afecta a las propiedades de la comunicación del sistema operativo distribuido, ya que están basadas en la suposición de ausencia de encaminadores. Un encaminador es básicamente una máquina que pertenece a dos o más redes. Su propósito es unir dos o más redes locales distantes geográficamente, de distinto nivel de enlace o ambas cosas a la vez, permitiendo que todas ellas compartan un mismo protocolo de nivel de red. En la definición de grupo nada impide que los procesos que forman el grupo se encuentren en una misma Inter-red pero en distintas redes locales. Cuando la comunicación de grupo se realiza mediante unicasting la presencia de gateways no es problemática. Cada mensaje enviado por el proceso emisor llega al proceso destinatario siguiendo los cauces convencionales del algoritmo utilizado por el protocolo de red. Consideremos un sistema operativo distribuido en el que las redes locales que abarca soportan multicasting, como ethernet. 3.1 Sincronización de relojes Los algoritmos distribuidos tienen las siguientes propiedades: 1. La información relevante está repartida entre múltiples máquinas 2. Los procesos toman decisiones basados únicamente en información local 3. Es preciso evitar un único punto de fallo 4. No existe un reloj común Los primeros tres aspectos dicen que es inaceptable recoger toda la información en un único punto. El último aspecto es que ahora nos interesa. En un sistema centralizado, el tiempo se solicita mediante una llamada al sistema, como la llamada UNIX time. Si un proceso A solicita el tiempo y poco después lo solicita el proceso B, B obtiene un tiempo posterior al de A, ya que ambos consultan el mismo reloj. En un sistema distribuido, en que A y B corren en máquinas distintas y consultan distintos relojes, si el reloj de A es ligeramente más lento que el de B, A puede conseguir un tiempo posterior al de B a pesar de habero solicitado antes. 3.1.1 Relojes lógicos Leslie Lamport, en 1978 ([Les78]), mostró que la sincronización de relojes para producir un patrón de tiempo común a más de una máquina es posible y presentó un algoritmo para lograrlo. Lamport afirmó que no es necesario disponer de un registro común absoluto del tiempo cuando los procesos no interactúan y, cuando lo hacen, tampoco es necesario en la mayoría de las aplicaciones. Para muchos casos, lo imporante es que los procesos que interactúan se pongan de acuerdo en el tiempo en que los eventos ocurren. En el ejemplo de make, lo importante es que pepo.c sea más antiguo que pepo.o, no el instante preciso de creación de ambos. Así, para ciertas clases de algoritmos, lo que importa es la consistencia interna de los relojes, no la exactitud particular de cada uno de ellos. Para estos algoritmos, es conveniente hablar de relojes lógicos. Cuando el objetivo es mantener todos los relojes dentro de un margen error dado respecto al tiempo absoluto, es conveniente hablar de relojes físicos. Lamport definió la relación ocurre-antes, a m b, leída “a ocurre antes que b”, y significa que a ocurre antes que b y todos los procesos están de acuerdo en ello. Lamport definió esta relación como sigue: 1. Si los eventos a y b ocurren en el mismo proceso y a ocurre antes que b, entonces a b. 2. Si a es el evento que consiste en el envío de un mensaje a otro proceso y b es el evento que consiste en la recepción del mensaje en otro proceso, entonces a b. 3. Si a e b y b c, entonces b e c.
  • 10. 3.1.2 Relojes físicos El día solar es el tiempo que transcurre desde que el sol alcanza su punto más alto en el horizonte hasta que vuelve a alcanzarlo. Un día tiene 24 horas, de modo que definimos el segundo solar como 1/(24*60*60) = 1/86400 de un día solar. En 1940 se descubrió que la duración del día no era constante. Estudios actuales sobre coral antiguo han llevado a los geólogos a pensar que hace 300 millones de años había 400 días en un año. No es que el año fuera más largo. Es que los días eran más cortos. La tierra rotaba sobre sí misma más rápido que en la actualidad. Además de esta tendencia a largo plazo, la tierra experimenta perturbaciones esporádicas en su tiempo de rotación debido a las turbulencias de su núcleo de hierro. Estas oscilaciones llevaron a los astrónomos a determinar la duración del segundo como la media de un gran número de ellas. Dividida esta cantidad por 86400 obtenemos el segundo solar medio. Con la invención del reloj atómico en 1948, la medida del tiempo pasó de ser responsabilidad de los astrónomos a ser responsabilidad de los físicos. Definieron el segundo atómico como el tiempo que tarda el isótopo 133 del cesio en realizar 9192631770 transiciones. Este número de transiciones fue escogido, por supuesto, porque son las que igualaban la duración del segundo solar medio el día que el segundo atómico fue introducido. El segundo atómico es más preciso que el segundo solar, pero no es absolutamente preciso. En el mundo existen actualmente unos 50 laboratorios que disponen de un reloj de 133Cs. Cada uno de ellos registra el número de ticks acumulados desde las cero horas del primero de enero de 1958. En París existe una organización que se llama la Oficina Internacional de la Hora que promedia los ticks de estos 50 laboratorios. Al resultado lo divide por 9192631770 para obtener el Tiempo Atómico Internacional (TAI). El TAI es extrordinariamente estable y está a disposición de cualquiera que lo solicite. Sin embargo, como el periodo de rotación de la tierra está aumentando continuamente, el segundo solar aumenta en la misma medida. Así, un día solar, que son 86400 segundos solares, tiene ahora 86400.003 segundos TAI. Usar el tiempo TAI es más exacto, pero llegará un momento que el mediodía no será a las 12, sino a las doce y cuarto. Los segundos TAI duran menos que los segundos solares. Para ello, cuando un reloj solar ha perdido 0.8 segundos respecto al tiempo TAI, por ejemplo, el tiempo es de 4.0 TAI y de 3.2 solar, se extingue ese segundo solar para que pase directamente de 3.2 a 4.0 y mantener la sincronía con el tiempo TAI. Esto da una medida del tiempo con intervalos irregulares, llamado el Tiempo Universal Coordinado (UTC), que es la base actual del registro del tiempo. Ha reemplazado al antiguo estándar de la medida del tiempo, el GMT (Greenwich Meridian Time), que es tiempo solar. Para proporcionar el tiempo UTC, una institución de Estados Unidos, el Instituto Nacional del Tiempo Estándar (NIST), mantiene una estación de radio de onda corta que radia un pulso cada vez que comienza un segundo UTC. La precisión de esta estación es de un milisegundo, pero el ruido atmosférico eleva este error en la práctica a 10 milisegundos. En Inglaterra y otros países existen estaciones similares. También satélites proporcionan el tiempo UTC, y lo hacen con una precisión de 0.5 milisegundos, veinte veces mayor que las estaciones de radio de onda corta. El costo de este servicio varía, según su exactitud, entre 100.000 pts y varios millones de pesetas según su precisión. Hay un medio más barato, que es obtenerlo del NIST por teléfono. Este es el método más inexacto, ya que hay que corregir el retraso de la señal en la línea y el modem. Concluyendo, podemos decir que el tiempo absoluto puede ser proporcionado al computador, pero a un precio alto y siempre con un margen de error no despreciable. Mas información: http://www.cstv.to.cnr.it/toi/uk/utctime.html
  • 11. 3.1.3 Algoritmos de sincronización de relojes La medida del tiempo en las máquinas se lleva a cabo mediante un oscilador de cristal. Un chip denominado temporizador recibe la señal periódica del oscilador e interrumpe la UCP cada cierto número de oscilaciones, previamente programado. Valores típicos oscilan entre 50 y 100 interrupciones por segundo a la UCP. Por preciso que sea un oscilador a cristal, siempre existe un margen de error que conlleva la discrepancia de la medida del tiempo de dos máquinas diferentes. En una red local, por ejemplo, ninguna máquina tiene el mismo registro del tiempo. Para disminuir la discrepancia entre relojes, se puede tener acceso a una estación de onda corta de las ya citadas. El caso general, sin embargo, es que este servicio no está disponible, y el problema que se plantea es, dado un conjunto de máquinas, mantener sus relojes lo más cercanos que sea posible mediante software. Se han propuesto para ello muchos algoritmos, todos ellos con el mismo principio, que ahora describimos. Se supone que cada máquina dispone de un temporizador que interrumpe a la UCP H veces por segundo. El núcleo dispone de una variable que es incrementada en la unidad por la rutina de interrupción del reloj. Esta variable registra el número de ticks recibidos desde la puesta en marcha del sistema, por ejemplo. Esta variable se considera el reloj del sistema y vamos a denominar el valor que almacena como C. Cuando el tiempo es t, el tiempo registrado por la máquina p es Cp(t). Idealmente Cp(t) debiera ser igual a t, para todo p y todo t. En otras palabras, dC/dt debiera ser idealmente 1. Teóricamente, un temporizador con H=60 interrumpe al reloj sesenta veces por segundo. En una hora interrumpe 60*60*60 = 216000 veces. En la práctica, se puede contar este número de interrupciones y descubrir que no son exactamente esas, sino que el dato varía entre 215998 y 216002 ticks en una hora, lo que representa un error relativo de aproximadamente 10–5. La precisión de un temporizador viene dada por su tasa de deriva máxima 0, de modo que si se dice que el reloj opera dentro de sus especificaciones. Dos relojes iguales dentro de sus especificaciones pueden generar una direferencia máxima en su medida del tiempo cuando la deriva toma en ellos el valor máximo y de signo opuesto. Así, partiendo ambos de cero, en un intervalo , el reloj uno toma un valor de y el reloj dos un valor de 0, obteniendo una diferencia máxima en la medida de 0. Si los diseñadores del sistema desean que nunca dos relojes muestren diferencias mayores a una constante 0, 0, de modo que 0, lo que significa que los relojes deben ser sincronizados cada 0 segundos. A continuación vamos a ver algunos algoritmos que llevan a cabo esta resincronización. 3.1.3.1 El algoritmo de Cristian Este algoritmo requiere que una de las máquinas disponga de un receptor de onda corta y el objetivo es lograr que todas las demás operen sincronizadas con ella. A esta máquina la vamos a llamar un servidor de tiempo. Periódicamente, y siempre antes de segundos, cada una de las máquinas envía un mensaje al servidor de tiempo solicitando el tiempo CUTC, que es servido tan rápido como es posible como indica la figura 3.5 XX falta XX. El algoritmo tiene dos problemas, uno más leve y otro más serio. El más serio es que un reloj nunca puede ser retrasado. Si el reloj de la máquina que solicita el tiempo es rápido, el tiempo CUTC recogido es menor y su reloj debe ser atrasado. Esto no se puede permitir porque muchas aplicaciones, como make, confían en la secuencia temporal de eventos en el sistema como la base de su operación. A un evento que ocurre después de otro, como la generación de un fichero objeto, no se le puede asignar un tiempo de creación o última modificación inferior al del programa fuente.
  • 12. La modificación del reloj debe realizarse gradualmente. Una forma de hacerlo es la siguiente. Supongamos que el temporizador interrumpe la UCP cien veces por segundo, lo que significa que un tick de reloj es un intervalo de tiempo de diez milisegundos. La rutina de interrupción incrementa un contador en el núcleo, el reloj, en una unidad, lo que equivale a sumar al tiempo diez milisegundos. Para retrasar el reloj un segundo se puede dejar de incrementar el contador una de cada cien interrupciones -por ejemplo, la décima-, lo que significa que cada segundo retrasamos el reloj diez milisegundos. Para retrasarlo un segundo necesitamos cien segundos. Para adelantar el reloj se puede utilizar esta misma técnica. Al cabo de 100 segundos, habremos adelantado el reloj un segundo. También se puede adelantar el reloj de una sóla vez añadiendo 100 ticks al reloj, ya que el adelantamiento del tiempo no causa problemas. El problema secundario es que desde que una máquina solicita el tiempo CUTC, la réplica del servidor de tiempo tarda en llegar una cantidad de tiempo no despreciable y, lo que es peor, que varía con la congestión de la red. El algoritmo de Cristian aborda este problema intentando medirlo. El cliente registra el tiempo local T0 en que envía el mensaje y el tiempo T1 en el que llega y estima que la réplica tardó en llegar (T1-T0)/2. Este tiempo que es local y, por ser pequeño, relativo exacto aunque el reloj se haya alejado sensiblemente del tiempo UTC. (T1-T0)/2 se suma al CUTC que trae el mensaje y el resulado es el CUTC que finalmente el cliente adopta. Para mejorar la exactitud se puede realizar un muestreo entre distintos tiempos de retorno de la petición de tiempo y realizar una media. Se aconseja descartar los valores que superan un umbral dado para evitar introducir en la estimación réplicas obtenidas en momentos de congestión. 3.1.3.2 El algoritmo de Berkeley Es el adoptado por UNIX BSD. Frente al algoritmo de Cristian, basado en un servidor pasivo que responde a las peticiones de clientes, el algoritmo de Berkeley toma una aproximación activa. Es útil cuando no se dispone del tiempo UTC, vía un receptor de onda u otro. Un demonio UNIX periódicamente realiza un escrutinio de las máquinas, aquella en la que reside incluida, a fin de obtener el valor de sus relojes. Realiza una media de todos ellos y la comunica a todas la máquinas para que avancen o retrasen sus relojes. 3.1.3.3 Algoritmos de promediado Los algoritmos anteriores tienen la desventaja de su aproximación centralizada y, por lo tanto, tienen un único punto de fallo. Presentamos a continuación un algoritmo descentralizado. Las máquinas dividen el tiempo en intervalos de longitud R, de modo que el comienzo del i-ésimo intervalo comienza en el instante T0+iR se prolonga hasta el instante T0+(i+1)R, donde T0 es un instante pasado previamente acordado. Cuando comienza uno de estos intervalos, cada máquina realiza una difusión del tiempo según su reloj. Debido a la deriba particular de cada reloj, dos difusiones no ocurren simultáneamente. Después de la difusión de su tiempo, cada máquina establece un temporizador y espera el mensaje correspondiente al broadcast del resto de las máquinas en un intervalo S. Cuando han llegado todos los mesajes, un algoritmo de promediado proporciona el nuevo tiempo. El algoritmo más simple es realizar la media aritmética de los tiempos. Una variación es descartar previamente los valores extremos a fin de protegernos frente a relojes defectuosos. Otra variación es estimar el tiempo de propagación de cada mensaje para añadirlo al tiempo que el mensaje transporta. Esta estimación puede llevarse a cabo a partir de un conocimiento previo de la topología de la red o realizando mediciones del tiempo de retorno de algunos mensajes de prueba. 3.1.4 El empleo de la sincronización de relojes
  • 13. Hasta hace poco tiempo no se ha presentado la necesidad de sincronizar los relojes de máquinas en una red de área ancha. Ahora es posible sincronizar relojes distribuidos a lo largo de toda la Internet en márgenes de precisión de unos pocos milisegundos respecto al tiempo UTC. La disponibilidad de algoritmos de bajo costo para mantener la sincronización de relojes ha incitado el desarrollo de algoritmos distribuidos que explotan esta circunstancia disminuyendo el número de mensajes implicados en las versiones que no la explotan. A continuación ilustramos el empleo de la sincronización de relojes en el problema de la consistencia de la caché de un sistema de ficheros distribuidos. La referencia [Lis93] contiene más ejemplos. Un ejemplo de la utilidad de algoritmos basados en el uso de relojes sincronizados está relacionado con la consistencia de la cache de disco en un sistema de ficheros distribuido. Razones de prestaciones exigen una caché en el cliente. Dos clientes operando sobre un mismo fichero mantienen cada uno de ellos una copia del fichero en su propia máquina. La inconsistencia de las cachés surge cuando uno de los clientes trata de escribir en el fichero. Tradicionalmente, cuando un cliente deseaba escribir un fichero de su caché solicitaba permiso al servidor. Inmediatamente, el servidor está obligado a solicitar permiso al proceso o procesos que están leyendo del fichero para que dejen de hacerlo (y lo descarten de la caché), y esperar a que todos los permisos lleguen antes de conceder el permiso de escritura, lo que introduce una fuerte sobrecarga en tiempo y ancho de banda en la red. La introducción de los relojes sincronizados agiliza este tipo de protocolos de los sistemas de ficheros distribuidos. La idea básica es que cuando un cliente solicita un fichero, el servidor le otorga una concesión en la que detalla el tiempo de expiración de la misma E. Como cliente y servidor tienen los tiempos sincronizados, el plazo es el mismo en ambos. Mientras dura la concesión, el cliente tiene la garantía de que opera sobre el fichero de forma consistente. Un cliente no necesita comunicar al servidor que ha terminado la operación de lectura. Si un cliente solicita la escritura de un fichero, el servidor debe pedir a los clientes lectores la terminación prematura de la concesión. ¿Qué ocurre cuando no hay respuesta por parte del cliente lector? El servidor no sabe si el cliente simplemente se ha caído. En este caso, el servidor no obtiene respuesta, lo que plantearía un problema en el algoritmo tradicional. Con los relojes sincronizados, simplemente espera a que cumpla el plazo de la concesión del fichero. 3.2 Exclusión mutua Cuando dos o más procesos comparten una estructura de datos, su lectura o actualización no debe ser simultánea. Para evitar la simultáneidad de acceso, y con ello la incosistencia de la estructura, el código de acceso y actualización de la misma se denomina región crítica y su ejecución es protegida mediante construcciones como semáforos, monitores, etc. En esta sección examinamos algunos ejemplos de cómo construir regiones críticas en sistemas distribuidos. 3.2.1 Un algoritmo centralizado La forma más directa de conseguir la exclusión mutua en un sistema distribuido es simular al mecanismo de los sistemas centralizados. Se requiere de un proceso que actúa como coordinador. Este registra las regiones críticas de los procesos. Cuando un proceso desea entrar en una región crítica envía un mensaje al coordinador con el número de la región crítica. Si ningún otro proceso está ejecutando la región crítica, el coordinador envía una réplica al proceso con la concesión de entrada, tal y como muestra la figura 3.5. Cuando la réplica llega, el proceso entra en la región crítica.
  • 14. Fig. 3.5 a) Solicitud y concesión de entrada en región crítica. b) La concesión se retrasa hasta mientras la región crítica esté en uso. c) Concesión tras ser liberada Supongamos que el proceso 3 de la figura desea entrar en la misma región crítica antes de que el proceso 2 salga. La petición llega al coordinador, que sabiendo que el proceso 2 está dentro, no envía réplica alguna al proceso 3, que permanece bloqueado esperándola -también se puede implementar la denegación mediante un mensaje-, pero lo registra en la cola de la región como solicitante. Cuando el proceso 2 sale de la región crítica lo comunica al coordinador mediante un mensaje de liberación. El coordinador procesa el mensaje determinando si existe en la cola de la región recién liberada algún proceso esperando. En nuestro caso, efectivamente lo hay. Es el proceso 3, que por fin recibe el mensaje de concesión de entrada. Este algoritmo garantiza la exclusión mutua. Primero, el coordinador sólo permite entrar en la misma a un proceso. Segundo, es justo, ya que las peticiones son atendidas en el orden en que llegan. Tercero, ningún proceso espera indefinidamente por la entrada. El esquema es fácil de implementar y es eficiente, ya que requiere tres mensajes para usar una región crítica. El defecto principal del algoritmo, como todos los algoritmos centralizados es la existencia de un único punto de fallo. 3.2.2 El algoritmo distribuido de Ricart y Agrawala Ricart y Agrawala presentaron en 1981 un algoritmo de exclusión mutua distribuido. Consideramos un conjunto de N procesos con una esctructura sencilla en la que alternan los cálculos fuera de la región crítica y dentro de la región crítica. Las condiciones del algoritmo son las siguientes: 1. Los procesos se comunican mediante mensajes de capacidad no nula. 2. Los mensajes pueden llegar a un proceso en cualquier punto de la ejecución, bien dentro o bien fuera de la región crítica. De cualquier modo una interrupción, excepción, manejador de señal, etc, se encarga de procesar la llegada del mensaje. 3. Se asume que la comunicación es fiable y los mensajes entre dos procesos son entregados en el orden en el que fueron enviados. 4. Es preciso una relación de orden total entre los eventos de todo el sistema. Consideramos que para que un proceso entre en la región crítica deben tener el permiso todos y cada uno del resto de los procesos, permiso que solicita enviando un mensaje a todos ellos, vía multicasting, difusión o uno a uno. El mensaje acarrea una etiqueta temporal que es el valor del reloj lógico local correspondiente a su envío. Cuando un proceso recibe un mensaje de solicitud de permiso, la acción que toma el proceso receptor es la siguiente: 1. Si el receptor no está en su región crítica y no desea entrar en ella, se dice que está en situación de permiso concedido (CONCEDIDO) y envía inmediatamente un mensaje de réplica al proceso que solitó el permiso. 2. Si el receptor está ejecutando en su región crítica, se dice que tiene el permiso (OTORGADO), no envía réplica al emisor y encola la petición. Como vemos, si un proceso no contesta significa que no concede el permiso de entrada. 3. Si el receptor desea también entrar en la región crítica, pero aún no lo ha conseguido se dice que está en estado de solicitud (SOLICITANDO), compara el reloj del mensaje entrante con el del mensaje que ha enviado al resto de los procesos para solicitar el permiso. El más bajo gana. Si gana el emisor del mensaje entrante, el receptor envía a este la réplica. Si gana el receptor, encola el mensaje y no envía réplica. Inicialización: estado:=CONCEDIDO;
  • 15. Para obtener el permiso: estado:=SOLICITANDO; multicast de solicitud de permiso al resto; T:=Reloj lógico del mensaje de petición; Wait until(Número de réplicas recibidas=n-1); estado:=OTORGADO; Cuando se recibe una petición <Ci, pi> en pj: if(estado=OTORGADO or (estado=SOLICITANDO and C.pj < C.pi) ) then Encola la petición de pi sin replicar else Replica inmediatamente a pi fi Para conceder el permiso tras abandonar la región crítica: estado=CONCEDIDO; Replica a todos las peticiones en la cola; Fig. 3.6 El algoritmo de Ricart y Agrawala En conjunto, el algoritmo es más lento, más complicado y menos robusto que el algoritmo centralizado, de modo que ¿porqué molestarse estudiándolo? Porque demuestra que un algoritmo distribuido, sin un control central, es posible, lo que estimula el estudio de soluciones distribuidas más avanzadas. 3.2.3 El algoritmo en anillo Esta basado en una disposición de los n procesos que están interesados en utilizar la región crítica en un anillo lógico. Se concede la entrada en la región crítica al proceso que obtiene el denominado testigo. El testigo es un mensaje que se pasa de proceso en proceso en un sentido único recorriendo el anillo. Cada proceso tiene la dirección del proceso al que pasa el testigo. Cuando un proceso recibe el testigo, si no está interesado en la región crítica, pasa es testigo a su vecino. Si necesita entrar en la región crítica, espera bloqueado la llegada del testigo, que es retenido y no es entregado al vecino sino cuando abandona la región crítica. Para obtener el testigo, como máximo se emplean n-1 mensajes. Una desventaja es que los mensajes se envían continuamente aun en el caso de que ningún proceso reclame el testigo. Otra es que este algoritmo tiene n puntos de fallo, si bien la recuperación es más fácil que en los casos anteriores. Si cada vez que se recibe el testigo se envía un mensaje de confirmación, es sencillo detectar la caída de un proceso y retirarlo del anillo. 3.3 Algoritmos de elección Una elección es un procedimiento cuya función es elegir un proceso en un grupo a fin de que este desempeñe un papel determinado, como puede ser centralizar peticiones de entrada en una región crítica, a modo de coordinador. Vamos a considerar que los procesos implicados en la elección son idénticos, sin que ninguno de ellos tenga una característica destacable como para ser el coordinador idóneo. Cada proceso tiene un identificador único como puede ser su dirección de red. En general, los algoritmos de
  • 16. elección intentan localizar al proceso con el identificador más alto para hacerlo coordinador. Para enviar los mensajes, los procesos necesitan conocer las direcciones de red de todo el grupo de procesos en busca de coordinador, de modo que la elección ya estaría hecha de antemano. El problema es que los procesos desconocen cuáles de ellos están aún activos y cuáles no. El requisito que debe cumplir una elección de coordinador es que esta sea única. Los algoritmos difieren unos de otros en el modo de conseguirlo. El algoritmo del matón Este algoritmo data de 1982 y es debido a García-Molina. Cuando un proceso se apercibe de que el coordinador no responde a sus mensajes, inicia una convocatoria de elección. Una elección se desarrolla como sigue: 1. P envía un mensaje de tipo ELECCION a todos los procesos con identificadores más altos. 2. Si ninguno de ellos responde, P gana la elección y se convierte en el coordinador. 3. En cuanto P recibe el mensaje de respuesta de alguno de ellos, renuncia a ser el coordinador y su trabajo ha terminado. Cada uno de estos procesos, tras enviar el mensaje, convocan una elección En cualquier momento, un proceso puede recibir un mensaje ELECTION de uno de los procesos con identificador inferior. La rutina que sirve el mensaje envía un mensaje de confirmación y toma el control iniciando una elección, a menos que ya esté celebrando una. Llega un momento en que todos los procesos renuncian y uno de ellos se convierte en el nuevo coordinador, hecho que anuncia al resto de los procesos mediante el envío de un mensaje. Si un proceso que inicialmente estaba caído se recupera, inicia una elección. Si es el de identificador más alto, ganará la elección y asumirá el papel de coordinador. Siempre gana el proceso de identifica-dor más grande, de ahí el nombre del algoritmo. En la figura 3.7 vemos el desarrollo de una elección en un grupo de ocho procesos numerados del 0 al 7, siendo este último el coordinador que, en un momento dado, deja de estar operativo. El proceso 4 es el primero en darse cuenta de que el coordinador no responde y convoca una elección, enviando un mensaje de tipo ELECCION a los procesos 5, 6 y 7, los dos primeros confirmando el mensaje. En cuanto el proceso 4 recibe la confirmación del proceso 5 da su trabajo por terminado. Sabe que él no será el coordinador, sino uno de los superiores que han confirmado. Los procesos 5 y 6 convocan elecciones de forma más o menos simultánea. El proceso cinco recibe confirmación del 6 y renuncia. El proceso 6 no recibe confirmación alguna, de modo que se erige en ganador, algo que anuncia al resto enviándoles un mensaje COORDINADOR. El proceso 4, que estaba esperando el resultado de la elección -aunque ya lo casi lo conocía- reanuda su trabajo, esta vez con un nuevo coordinador. 3.4 Transacciones atómicas El paradigma cliente-servidor proporciona una buena forma de estructurar el sistema y de desarrollar aplicaciones, pero necesita del concepto de transacción para controlar secuencias complejas de interacciones entre el cliente y el servidor. Sin transacciones no se puede conseguir que los sistemas distribuidos funcionen en las aplicaciones típicas de la vida real. Los conceptos de transacciones fueron concebidos para poder abordar la complejidad de las aplicaciones on-line en sistemas de un único procesador. Estos conceptos, ya veteranos, son hoy día incluso más críticos en la implementa-ción con éxito de sistemas masivamente distribuidos, que operan y fallan en formas mucho más complejas. Los sistemas de proceso de trasacciones fueron pioneros en conceptos de computación distribuida y computación tolerante a fallos. Ellos introdujeron los datos distribuidos en aras de la fiabilidad, disponibilidad y prestaciones. Ellos desarrollaron el almacenamiento tolerante a fallos y el proceso tolerante a fallos a fin de garantizar la disponibilidad de datos y aplicaciones. Y fueron ellos quienes desarrollaron el modelo cliente-servidor y las llamadas a procedimiento remoto para la computación distribuida. Y, lo más importante, las propiedades ACID de las transacciones han emergido como los conceptos unificadores de la computación distribuida ([Gra93]). Como puede apreciarse, no es posible obviar el tópico de las transacciones atómicas en un curso sobre sistemas distribuidos. En esta sección nos ocupamos de ellas, tratando algunos de sus múltiples aspectos.
  • 17. 3.4.1 Introducción a las transacciones atómicas Pensemos en una primitiva de sincronización como un semáforo. Subir o bajar un semáforno es una operación de muy bajo nivel que obliga al programador a tratar los detalles de la exclusión mutua, la gestión de la región crítica, la recuperación en caso de fallo, etc, cuando opera sobre datos compartidos. Lo que nos gustaría en un entorno de datos compartidos y con componentes suscepti-bles de fallo es disponer de primitivas de manipulación de datos de más alto nivel que permitan al programador: 1. Concentrarse en el problema, ignorando que los datos son accedidos de forma concurrente 2. Ignorar que un fallo puede dejar los datos en un estado inconsistente. Estas primitivas se utilizan ampliamente en los sistemas distribuidos (su finalidad es compartir datos y recursos y tienen más posibilidades de fallo) y se llaman transacciones atómicas. El uso de las transacciones se remonta a los años 60 cuando los datos se almacenaban en cintas magnéticas. Una base de datos residía en una cinta. que se llamaba el “fichero maestro”. Las actualizaciones residían en una o más cintas (por ejemplo las ventas diarias o semanales) llamadas “ficheros de movimientos”. Maestro y movimientos se montaban en el computador para producir un nuevo fichero maestro, que sería utilizado al día o a la semana siguiente con nuevos ficheros de movimientos. La ventaja de este método -no reconocida suficientemente en aquellos años- es que si el programa que llevaba a cabo las actualizaciones fallaba, se producía una caída en la alimentación eléctirica, etc y el proceso de actualización se interrumpía, siempre se podía descartar la nueva cinta que había quedado a medias y volver sobre el maestro y las actualizaciones para generar de nuevo el fichero maestro. Así, una actualización del maestro procedía correctamente hasta el final o no se modificaba en absoluto. Esta propiedad era una transacción atómica sobre el objeto “fichero maestro”. Consideremos ahora una aplicación bancaria que realiza una retirada de una cantidad de una cuenta y el ingreso correspondiente en otra cuenta distinta. Si el computador falla después de la retirada y antes del ingreso, el dinero se desvanece. Puede que ambas cuentas residan en distintas máquinas y el fallo se deba a una pérdida de la conexión telefónica entre ambas operaciones. Sería necesario agrupar ambas operaciones en una transacción atómica como en el ejemplo de la cinta magnética que garantizase que la operación se realiza completamente o no se realiza. La clave reside en volver al estado inicial de las cuentas si es que se ha producido un fallo en mitad del proceso. Esta habilidad es proporcionada por las transacciones atómicas. 3.4.2 Servicios transaccionales Conviene examinar la aplicación bancaria anterior en el contexto del modelo cliente-servidor. Cuando decimos que un servidor porporciona operaciones atómicas significa que el efecto de desarrollar una operación en beneficio del cliente: Está libre de interferencia de las operaciones realizadas en beneficio de otros clientes Bien la operación concluye completamente o no tiene efecto alguno si el servidor falla. Una transacción entre un cliente y un servidor es una secuencia de interacciones. El servidor bancario proporciona las operaciones Depósito, Retirada, Balance, Total Sucursal?. sobre una serie de objetos, en este caso cuentas: Depósito(Cuenta, Cantidad) Deposita la cantidad Cantidad en la cuenta Cuenta Retirada(Cuenta, Cantidad) Retira la cantidad Cantidad de la cuenta Cuenta
  • 18. Balance(Cuenta) Cantidad Devuelve el balance de la cuenta Cuenta Total Sucursal e Total Devuelve la suma de todos los balances Consideremos un cliente que quiere realizar una serie de operaciones sobre las cuentas A, B, C. La primera operación transfiere 100 pesetas de A a B. La segunda transfiere 200 pesetas de C a B: Transacción: T: Retirada(A, 100); Depósito(B, 100); Retirada(C, 200); Depósito(B, 200); End Transacción?(T) Como vemos, desde el punto de vista del cliente, una transacción es una secuencia de operaciones que se realizan en un sólo paso, llevando al servidor de un estado consistente a otro. El cliente no es consciente de que otros clientes pueden realizar operaciones sobre las cuentas A y B. A un servidor de este tipo se le conoce como servidor transaccional o que provee de un servicio transaccional. En un servicio transaccional, el cliente, cuando inicia una transacción con el servidor, emite la petición Abrir Transacción? y el servidor le devuelve un indentificador de transacción. Este indentificador será usado en las operaciones siguientes. El cliente notifica al servidor el final de la secuencia de operaciones mediante la primitiva Cierra Transacción?. Abrir Transacción n Trans Arranca en el servidor una nueva transacción y devuelve un único identificador de transacción o TID, que será usado como parámetro en el resto de las operaciones de la transacción Cerrar Transacción?(Trans) r (Compromiso, Aborto) Termina la transacción. Si devuelve un compromiso, indica que la transacción se ha comprometido (se ha realizado en su totalidad). Si devuelve un valor de Aborto, la transac-ción no se ha realizado. Abortar Transacción?(Trans) Aborta la transacción La transacción puede abortar por varias razones. Entre ellas la naturaleza misma de la transacción y su desarrollo, conflictos con otra transacción o el fallo de procesos o máquinas. La transacción puede ser abortada, tanto por el cliente como por el servidor. Cuando el servidor decide unilateralmente abortar la transacción en curso, la operación en curso devuelve un código de error como SERVER_ABORT. Veamos cual es el comportamiento de cliente y servidor en presencia de fallos: Fallo en el servidor Si un servidor transaccional falla inesperadamente, cuando vuelve a arrancar, aborta toda transacción no comprometida utilizando un procedimiento de recuperación para restaurar los valores de los items de datos provisionales a los valores definitivos producidos por la transacción comprometida más recientemente previa al fallo. Replica al cliente la operación solicitada con un valor SERVER_ABORT. Otra posibilidad es que el cliente dé un plazo de respuesta al servidor para cada operación emitida. Si el servidor se recupera dentro del plazo, continúa con la transacción en curso en lugar de abortarla. Fallo en el cliente Si un cliente falla inesperadamente en el desarrollo de una transacción, el servidor puede dar un plazo de expiración a la transacción. Si una nueva operación de la transacción no llega en ese plazo el servidor aborta la transacción e inicia el procedimiento de recuperación.
  • 19. 3.4.3 Propiedades de las transacciones atómicas Las transacciones tienen cuatro propiedades fundamentales que se conocen por el acrónimo ACID: Atomicidad, Consistencia, serializabilidad o aislamiento (“Isolation”) y Durabilidad. 3.4.3.1 Atomicidad La atomicidad garantiza que la transacción procede hasta que se completa o no se realiza en absoluto. Si se completa, esto ocurre en una acción indivisible e instantánea. Mientras una transacción está en progreso, otros procesos, estén o no estén implicados en transacciones, no pueden ver los estados intermedios. Por ejemplo, supongamos una transacción que se ocupa de añadir octetos a un fichero de 10 octetos. Mientras la transacción esta en curso, otro proceso debe ver un fichero de sólo 10 bytes. Cuando la transacción se compromete, el fichero instantánemente aparece con su nuevo tamaño. Un sistema de ficheros que garantiza este comportamiento es un sistema de ficheros transaccional. La mayoría de los sistemas de ficheros no son transaccionales. 3.4.3.2 Consistencia La propiedad de la consistencia obliga cumplir ciertos invariantes de los datos del servidor. Por ejemplo, como resultado de una transferencia interna, una sucursal bancaria debe mantener el mismo dinero en su saldo que antes de que la transacción se realice. La consistencia de los datos puede ser violada por el cliente si las operaciones que emite no son consistentes y por el servidor si no dispone de un adecuado mecanismo de control de concurrencia. Si las operaciones de forman una transacción T que emite un cliente son consistentes, el servidor garantiza que la consistencia de los datos que T comparte con otra transacción U no va ser violada por la concurrencia de las operaciones de U. 3.4.3.3 Serializabilidad La tercera propiedad dice que las transacciones deben ser aisladas. Aislada significa transacciones concurrentes en un servidor no interfieren las unas con las otras. Una forma de lograr el aislamiento es anular la concurrencia del servidor de modo que ejecute las transacciones de forma estrictamente secuencial, una tras otra. El objetivo de un servidor, sin embargo es maximizar sus prestaciones, algo que pasa por la atención concurrente al mayor número de transacciones posible. Esto significa que si un servidor está atendiendo a dos o más transacciones simultáneamente que operan sobre datos compartidos por los clientes -un fichero, por ejemplo-, el servidor transaccional debe garantizar que el resultado final de estos datos es aquel que produce una realización estrictamente secuencial de las transacciones. Esta realización, no obstante, es decidida arbitrariamente por el servidor. Supongamos que un servidor transaccional mantiene una variable x que es accedida por tres clientes. Las transacciones de los clientes en un momento dado son las siguientes: Proceso 1: Abrir Transacción; x := 0; x := x + 1; Cerrar Transacción; Proceso 2: Abrir Transacción; x := 0; x := x + 2; Cerrar Transacción; Proceso 3: Abrir Transacción; x := 0; x := x + 3; Cerrar Transacción; Las peticiones de las distintas transacciones llegan al servidor entrelazadas. A cada secuencia de ejecución de las peticiones por parte del servidor se le llama entrelazado o planificación. Si el servidor es transaccional, no todas las planificaciones son válidas. En la tabla que sigue vemos tres planificaciones posibles, donde el tiempo transcurre hacia la derecha: Planificación 1 x := 0; x := x + 1; x := 0; x := x + 2; x := 0; x := x + 3; legal Planificación 2 x := 0; x := 0; x := x + 1; x := x + 2; x := 0; x := x + 3; legal
  • 20. Planificación 3 x := 0; x := 0; x := x + 1; x := 0; x := x + 2; x := x + 3; ilegal tiempo En la planificación 1 las transacciones son ejecutadas de forma estrictamente secuencial, y el valor final es 3. Decimos que esta planificación ha sido serializada. La planificación 2 no es serializada, pero es legal por que, al final, x toma un valor que podría haber sido alcanzado por una planificación estrictamente secuencial. La planificación 3 es ilegal, ya que x termina con un valor de 5, valor que imposible alcanzar con una planificación serializada. Equivalencia serial Si un entrelazado de dos o más transacciones tiene el mismo efecto sobre los datos que alguna ejecución serializada de dichas transacciones decimos que el entrelazado es serialmente equivalente. La planificación 2 de la figura es serialmente equivalente. 3.4.3.4 Durabilidad Una transacción debe ser durable. Esta propiedad establece que si un servidor compromete una transacción -por ejemplo con una réplica a una primitiva Cerrar Transacción(Trans)que devuelva el valor Compromiso-, no importa lo que ocurra, los cambios son ya permanentes. Ningún fallo después del compromiso puede desacer los resultados o causar su desaparición, con la consiguiente confusión posterior en el cliente. 2.3 Bibliografía [Cou95] Coulouris A. et al., Distributed Systems, 2nd. Edition. Addison-Wesley, 1995. [Tan95] Tanenbaum, A., Distributed Operating Systems, Prentice-Hall, 1995. [Cou94] Coulouris, G., Distributed Systems, Concepts and Design, Second Edition, Addison-Wesley, 1994. [Gra93] Gray, J., Reuter, A., Transaction Processing, Concepts and Techniques, Morgan Kaufmann Publishers, 1993. [Lam78] Lamport, L., “Time, Clocks, and the Ordering of Events in a Distributed System”, Communications of the ACM, Number 7, Volume 21, July, 1978. [Lis93] Liskov, B., “Practical uses of syncronized clocks in distributed systems”, Distributed Computing, No. 6, pp. 211–219, 1993. 2.1.1. Comunicación con los clientes-Servidor (Socket) Origen de los socket tuvo lugar en una variante del sistema operativo Unix conocida como BSD Unix. En la universidad de Berkeley, en los inicios del Internet, pronto se hizo evidente que los programadores necesitarían un medio sencillo y eficaz para escribir programas capaces de intercomunicarse entre sí. Esta necesidad dio origen a la primera especificación e implementación de sockets. Cliente-Servidor es el modelo que actualmente domina el ámbito de comunicación, ya que descentraliza los procesos y los recursos. Es un Sistema donde el cliente es una aplicación, en un equipo, que solicita un determinado servicio y existe un software, en otro equipo, que lo proporciona.
  • 21. Los servicios pueden ser; a)Ejecución de un programa. b)Acceso a una Base 2.1.2 comunicacion con rpc RCP (REMOTE PROCEDURE CALL) El mecanismo general para las aplicaciones cliente-servidor se proporciona por el paquete Remote Procedure Call (RPC). RPC fue desarrollado por Sun Microsystems y es una colección de herramientas y funciones de biblioteca. Aplicaciones importantes construidas sobre RPC son NIS, Sistema de Información de Red y NFS, Sistema de Ficheros de Red. Un servidor RPC consiste en una colección de procedimientos que un cliente puede solicitar por el envío de una petición RPC al servidor junto con los parámetros del procedimiento. El servidor invocará el procedimiento indicado en nombre del cliente, entregando el valor de retorno, si hay alguno. Para ser independiente de la máquina, todos los datos intercambiados entre el cliente y el servidor se convierten al formato External Data Representation (XDR) por el emisor, y son reconvertidos a la representación local por el receptor. RPC confía en sockets estandard UDP y TCP para transportar los datos en formato XDR hacia el host remoto. Sun amablemente a puesto RPC en el dominio público; se describe en una serie de RFCs. La comunicación entre servidores RPC y clientes es un tanto peculiar. Un servidor RPC ofrece una o más colecciones de procedimientos; cada conjunto se llama un programa y es idenficado de forma única por un número de programa. Una lista que relaciona nombres de servicio con números de programa se mantiene usualmente en /etc/rpc. En esta figura, la llamada remota toma 10 pasos, en el primero de los cuales el programa cliente (o procedimiento) llama al procedimiento stub enlazado en su propio espacio de direcciones. Los parámetros pueden pasarse de la manera usual y hasta aquí el cliente no nota nada inusual en esta llamada ya que es una llamada local normal. El stub cliente reúne luego los parámetros y los empaqueta en un mensaje. Esta operación se conoce como reunión de argumentos (parameter marshalling). Después que se ha construido el mensaje, se lo pasa a la capa de transporte para su transmisión (paso 2). En un sistema LAN con un servicio sin conexiones, la entidad de transporte probablemente sólo le agrega al mensaje un encabezamiento y lo coloca en la subred sin mayor trabajo (paso 3). En una WAN, la transmisión real puede ser más complicada. Cuando el mensaje llega al servidor, la entidad de transporte lo pasa al stub del servidor (paso 4), que desempaqueta los parámetros. El stub servidor llama luego al procedimiento servidor (paso 5), pasándole los parámetros de manera estándar. El procedimiento servidor no tiene forma de saber que está siendo activado remotamente, debido a que se lo llama desde un procedimiento local que cumple con todas las reglas estándares. Únicamente el stub sabe que está ocurriendo algo particular. Después que ha completado su trabajo, el procedimiento servidor retorna (paso 6) de la misma forma en que retornan otros procedimientos cuando terminan y, desde luego, puede retornar un resultado a un llamador. El stub servidor empaqueta luego el resultado en un mensaje y lo entrega a la interfaz con transporte (paso 7), posiblemente mediante una llamada al sistema, al igual que en el paso 2. Después que la respuesta retorna a la máquina cliente (paso 8), la misma se entrega al stub cliente (paso 9) que desempaqueta las respuestas. Finalmente, el stub cliente retorna a su llamador, el procedimiento cliente y cualquier valor devuelto por el servidor en el paso 6, se entrega al cliente en el paso 10. El propósito de todo el mecanismo de la Fig.1 es darle al cliente (procedimiento cliente) la ilusión de que está haciendo una llamada a un procedimiento local. Dado el éxito de la ilusión, ya que el cliente no puede saber que el
  • 22. servidor es remoto, se dice que el mecanismo es transparente. Sin embargo, una inspección más de cerca revela algunas dificultades en alcanzar la total transparencia. 2.1.3 comunicacion en grupo La comunicación se clasifica deacuerdo al numero de usuarios alos que se le a enviado el mensaje. -BROADCAST O DIFUSION FORZADA un nodo emite todos los escuchan y solo contesta a quien va dirigido el mensaje -MULTICAST se entrega el msj a todos los anfitriones HOST que están compuestos de ciertas características. -UNICAST o POINTCAST un nodo emite y otro recibe, solo escucha aquel a quien se dirigió el msj. Una clasificación adicional es la realizada en base a grupos -LISTAS DE DESTINARIOS se tiene una lista de aquellos alos que se les enviara el mensaje. -IDENTIFICADOR DE GRUPO se forman grupos y el msj es dirigido solo a los miembros de ese grupo. -PREDICADOR DE PERTENENCIA se envía y otro recibe, solo escucha aquel a quien se dirigió el mensaje. 2.1.4 tolerancia a fallos La difusión de los sistemas distribuidos incrementa la demanda de sistemas que esencialmente nunca fallen [25, Tanenbaum]. Los sistemas tolerantes a fallos requerirán cada vez más una considerable redundancia en hardware, comunicaciones, software, datos, etc. La réplica de archivos sería un requisito esencial. También debería contemplarse la posibilidad de que los sistemas funcionen aún con la carencia de parte de los datos. Los tiempos de fallo aceptables por los usuarios serán cada vez menores. 2.2 sincronizacion sistemas distribuidos En sistemas con una única CPU las regiones críticas, la exclusión mutua y otros problemas de sincronización son resueltos generalmente utilizando métodos como semáforos y monitores. Estos métodos no se ajustan para ser usados en sistemas distribuidos ya que invariablemente se basan en la existencia de una memoria compartida. No es posible reunir toda la información sobre el sistema en un punto y que luego algún proceso la examine y tome las decisiones. En general los algoritmos distribuidos tienen las siguientes propiedades: 1)- la información relevante está repartida entre muchas máquinas 2)- los procesos toman decisiones basadas solamente en la información local disponible 3) - debería poder evitarse un solo punto que falle en el sistema 4)- no existe un reloj común u otro tiempo global exacto
  • 23. Si para asignar un recurso de E/S un proceso debe recolectar información de todos los procesos para tomar la decisión esto implica una gran carga para este proceso y su caída afectaría en mucho al sistema. Idealmente, un sistema distribuido debería ser más confiable que las máquinas individuales. Alcanzar la sincronización sin la centralización requiere hacer cosas en forma distinta a los sistemas operativos tradicionales. 2.2.1 relojes fisicos El algoritmo de Lamport proporciona un orden de eventos sin ambigüedades, pero [25, Tanenbaum]: Los valores de tiempo asignados a los eventos no tienen porqué ser cercanos a los tiempos reales en los que ocurren. En ciertos sistemas (ej.: sistemas de tiempo real ), es importante la hora real del reloj: Se precisan relojes físicos externos (más de uno). Se deben sincronizar: Con los relojes del mundo real. Entre sí. La medición del tiempo real con alta precisión no es sencilla. Desde antiguo el tiempo se ha medido astronómicamente. Se considera el día solar al intervalo entre dos tránsitos consecutivos del sol, donde el tránsito del sol es el evento en que el sol alcanza su punto aparentemente más alto en el cielo. El segundo solar se define como 1 / 86.400 de un día solar. Como el período de rotación de la tierra no es constante, se considera el segundo solar promedio de un gran número de días. Los físicos definieron al segundo como el tiempo que tarda el átomo de cesio 133 para hacer 9.192.631.770 transiciones: Se tomó este número para que el segundo atómico coincida con el segundo solar promedio de 1958. La Oficina Internacional de la Hora en París (BIH) recibe las indicaciones de cerca de 50 relojes atómicos en el mundo y calcula el tiempo atómico internacional (TAI). Como consecuencia de que el día solar promedio (DSP) es cada vez mayor, un día TAI es 3 mseg menor que un DSP: La BIH introduce segundos de salto para hacer las correcciones necesarias para que permanezcan en fase: El sistema de tiempo basado en los segundos TAI. El movimiento aparente del sol. Surge el tiempo coordenado universal (UTC). El Instituto Nacional del Tiempo Estándar (NIST) de EE. UU. y de otros países: Operan estaciones de radio de onda corta o satélites de comunicaciones. Transmiten pulsos UTC con cierta regularidad establecida (cada segundo, cada 0,5 mseg, etc.). Se deben conocer con precisión la posición relativa del emisor y del receptor: Se debe compensar el retraso de propagación de la señal. Si la señal se recibe por módem también se debe compensar por la ruta de la señal y la velocidad del módem. Se dificulta la obtención del tiempo con una precisión extremadamente alta. 2.2.2 relojes logicos Las computadoras poseen un circuito para el registro del tiempo conocido como dispositivo reloj [25, Tanenbaum]. Es un cronómetro consistente en un cristal de cuarzo de precisión sometido a una tensión eléctrica que: • Oscila con una frecuencia bien definida que depende de: o Al forma en que se corte el cristal. o El tipo de cristal. o La magnitud de la tensión. • A cada cristal se le asocian dos registros:
  • 24. o Registro contador. o Registro mantenedor. • Cada oscilación del cristal decrementa en “1” al contador. • Cuando el contador llega a “0”: o Se genera una interrupción. o El contador se vuelve a cargar mediante el registro mantenedor. • Se puede programar un cronómetro para que genere una interrupción “x” veces por segundo. • Cada interrupción se denomina marca de reloj. Para una computadora y un reloj: • No interesan pequeños desfasajes del reloj porque: o Todos los procesos de la máquina usan el mismo reloj y tendrán consistencia interna. o Importan los tiempos relativos. Para varias computadoras con sus respectivos relojes: • Es imposible garantizar que los cristales de computadoras distintas oscilen con la misma frecuencia. • Habrá una pérdida de sincronía en los relojes (de software), es decir que tendrán valores distintos al ser leidos. La diferencia entre los valores del tiempo se llama distorsión del reloj y podría generar fallas en los programas dependientes del tiempo. Lamport demostró que la sincronización de relojes es posible y presentó un algoritmo para lograrlo. Lamport señaló que la sincronización de relojes no tiene que ser absoluta: • Si 2 procesos no interactúan no es necesario que sus relojes estén sincronizados. • Generalmente lo importante no es que los procesos estén de acuerdo en la hora, pero sí importa que coincidan en el orden en que ocurren los eventos. 2.2.3 usos de la sincroninizacion manejo de cache comunicacion en grupo exclusion mutua eleccion transacciones atomicas e interbloqueo memoria cache En los sistemas de archivos convencionales, el fundamento para la memoria caché es la reducción de la E/S de disco (lo que aumenta el rendimiento), en un SAD el objetivo es reducir el tráfico en la red. Esquema Básico, el concepto de memoria caché es sencillo, si los datos necesarios para satisfacer la solicitud de acceso no se encuentran en la memoria cache, se trae una copia de servicio al usuario y los accesos se llevan a cabo con la copia de memoria caché. La idea es conservar allí los bloques de disco de acceso mas reciente, para así manejar localmente los accesos repetidos a la misma información y no aumentar el tráfico de la red. Se utiliza una política de reemplazo (por ejemplo, la de utilización menos reciente) para limitar el tamaño de la memoria caché. Políticas de Actualización, la política empleada para escribir los bloques de datos modificados en la copia maestra del servidor tiene un efecto decisivo sobre la
  • 25. confiabilidad y el rendimiento del sistema. La política mas sencilla consiste en escribir los datos directamente en el disco tan pronto se coloquen en una memoria caché. La ventaja de la escritura directa es su confiabilidad, ya que se pierde poca información si un sistema cliente falla. Sin embargo, esta política requiere que cada acceso de escritura espere hasta que se envíe la información al servidor, por lo que representa una escritura de escaso rendimiento. La memoria caché con escritura directa equivale a usar el servicio remoto para accesos de escritura y explotar la memoria cache únicamente para accesos de lectura. NFS proporciona el acceso de escritura directa. Consistencia, una maquina cliente se enfrenta al problema de decidir si una copia de datos en memoria caché local es consistente con la copia maestra ( y por tanto, puede usarse). Si la maquina cliente determina que sus datos en memoria caché están desfasados, ya no pueden servir para los accesos y hay que colocar en la memoria caché una copia actualizada de los datos. Existen dos enfoques para verificar la validez de los datos en memoria caché ..: Enfoque iniciado por el cliente, el cliente inicia una comprobación de validez, en la cual se pone en contacto con el servidor y comprueban si los datos locales son consistentes con la copia maestra. Enfoque iniciado por el servidor, el servidor anota, para cada cliente, las partes de los archivos que coloca en memoria cache, y cuando detecta una inconsistencia, debe reaccionar. Una posible fuente inconsistencia ocurre cuando dos clientes, que trabajan en modos conflictivos, colocan en memoria caché un archivo. Comunicación en grupos (Algoritmos Para la Sincronización de Relojes) Si una máquina tiene un receptor de UTC, todas las máquinas deben sincronizarse con ella. Si ninguna máquina tiene un receptor de UTC: • Cada máquina lleva el registro de su propio tiempo. • Se debe mantener el tiempo de todas las máquinas tan cercano como sea posible. Se supone que cada máquina tiene un cronómetro que provoca una interrupción “h” veces por segundo. Cuando el cronómetro se detiene, el manejador de interrupciones añade “1” a un reloj en software. El reloj en software mantiene un registro del número de marcas (interrupciones) a partir de cierta fecha acordada antes; al valor de este reloj se lo llama “C”. Algoritmo de Cristian Es adecuado para sistemas en los que: • Una máquina tiene un receptor UTC, por lo que se la llama despachador del tiempo. • El objetivo es sincronizar todas las máquinas con ella. Cada máquina envía un mensaje al servidor para solicitar el tiempo actual, periódicamente, en un tiempo no mayor que è prontamente con un mensaje que contiene el tiempo actual “CUTC”. Cuando el emisor obtiene la respuesta puede hacer que su tiempo sea “CUTC”. Un gran problema es que el tiempo no puede correr hacia atrás: • “CUTC” no puede ser menor que el tiempo actual “C” del emisor. • La atención del requerimiento en el servidor de tiempos requiere un tiempo del manejador de interrupciones. • También se debe considerar el tiempo de transmisión. El cambio del reloj se debe introducir de manera global: • Si el cronómetro genera 100 interrupciones por segundo: Cada interrupción añade 10 mseg al tiempo. Para atrasar solo agregaría 9 mseg. Para adelantar agregaría 11 mseg. La corrección por el tiempo del servidor y el tiempo de transmisión se hace midiendo en el emisor: • El tiempo inicial (envío) “T0”. • El tiempo final (recepción) “T1”. • Ambos tiempos se miden con el mismo reloj. El tiempo de propagación del mensaje será (T1 - T0) / 2. Si el tiempo del servidor para manejar la interrupción y procesar el mensaje es “I”: • El tiempo de propagación será (T1 - T0 - I) / 2. Para mejorar la precisión: • Se toman varias mediciones. • Se descartan los valores extremos. • Se promedia el resto. El tiempo de propagación se suma al tiempo del servidor para sincronizar al emisor cuando éste recibe la respuesta. Algoritmo de Berkeley
  • 26. En el algoritmo de Cristian el servidor de tiempo es pasivo. En el algoritmo de Berkeley el servidor de tiempo: • Es activo. • Realiza un muestreo periódico de todas las máquinas para preguntarles el tiempo. • Con las respuestas: Calcula un tiempo promedio. Indica a las demás máquinas que avancen su reloj o disminuyan la velocidad del mismo hasta lograr la disminución requerida. Es adecuado cuando no se dispone de un receptor UTC. Algoritmos con Promedio Los anteriores son algoritmos centralizados. Una clase de algoritmos descentralizados divide el tiempo en intervalos de resincronización de longitud fija: • El i -ésimo intervalo: Inicia en “T0 + i R” y va hasta “T0 + (i + 1) R”. “T0” es un momento ya acordado en el pasado. “R” es un parámetro del sistema. Al inicio de cada intervalo cada máquina transmite el tiempo actual según su reloj. Debido a la diferente velocidad de los relojes las transmisiones no serán simultáneas. Luego de que una máquina transmite su hora, inicializa un cronómetro local para reunir las demás transmisiones que lleguen en cierto intervalo “S”. Cuando recibe todas las transmisiones se ejecuta un algoritmo para calcular una nueva hora para los relojes. Una variante es promediar los valores de todas las demás máquinas. Otra variante es descartar los valores extremos antes de promediar (los “m” mayores y los “m” menores). Una mejora al algoritmo considera la corrección por tiempos de propagación. Varias Fuentes Externas de Tiempo Los sistemas que requieren una sincronización muy precisa con UTC se pueden equipar con varios receptores de UTC. Las distintas fuentes de tiempo generaran distintos rangos (intervalos de tiempo) donde “caerán” los respectivos UTC, por lo que es necesaria una sincronización. Como la transmisión no es instantánea se genera una cierta incertidumbre en el tiempo. Cuando un procesador obtiene todos los rangos de UTC: • Verifica si alguno de ellos es ajeno a los demás y de serlo lo descarta por ser un valor extremo. • Calcula la intersección (en el tiempo) de los demás rangos. • La intersección determina un intervalo cuyo punto medio será el UTC y la hora del reloj interno. Se deben compensar los retrasos de transmisión y las diferencias de velocidades de los relojes. Se debe asegurar que el tiempo no corra hacia atrás. Se debe resincronizar periódicamente desde las fuentes externas de UTC. Exclusión Mutua Cuando un proceso debe leer o actualizar ciertas estructuras de datos compartidas: • Primero ingresa a una región crítica para lograr la exclusión mutua y garantizar que ningún otro proceso utilizará las estructuras de datos al mismo tiempo. En sistemas monoprocesadores las regiones críticas se protegen con semáforos, monitores y similares. En sistemas distribuidos la cuestión es más compleja. Un Algoritmo Centralizado La forma más directa de lograr la exclusión mutua en un sistema distribuido es simular a la forma en que se lleva a cabo en un sistema monoprocesador. Se elige un proceso coordinador. Cuando un proceso desea ingresar a una región crítica: • Envía un mensaje de solicitud al coordinador: Indicando la región crítica. Solicitando permiso de acceso. • Si ningún otro proceso está en ese momento en esa región crítica: El coordinador envía una respuesta otorgando el permiso.