Sistemas de cómputo distribuido Bloque 2 S istemas de cómputo distribuido Contenido 3. Procesos y comunicación 3.1. Procesos 3.1.1. Hilos 3.2. Comunicación 3.2.1. Llamado a procedimientos remotos 3.2.2. Paso de mensajes 3.3. Sincronización 3.3.1. Relojes 3.3.2. Exclusión mutua 3.3.3. Algoritmo de elección 3.3.4. Algoritmos de consenso 3.4. Transacciones distribuidas 3.4.1. Problemas debido a la concurrencia de transacciones 3.4.2. Recuperación de transacciones 3.4.3. Transacciones anidadas y distribuidas 3.4.4. Transacciones con replicación 2 P rocesos y comunicación bloque dos Introducción En el vasto panorama de la informática, los sistemas distribuidos han emergido como una arquitectura esencial que permite la interconexión y cooperación de múltiples entidades computacionales. La comprensión de los procesos y la comunicación en este contexto se convierten en elemento clave para diseñar, implementar y gestionar sistemas distribuidos eficientes y confiables. Consulta la presentación del autor Los procesos en sistemas distribuidos representan unidades de ejecución que no solo residen en una única máquina, sino que se distribuyen entre varios nodos interconectados. Estos procesos, a menudo denominados nodos o entidades, colaboran para realizar tareas complejas y aprovechar los recursos distribuidos de manera eficiente. La gestión de procesos en este entorno implica coordinación, sincronización y la capacidad de adaptarse a cambios dinámicos en la topología de la red. Además, la comunicación en sistemas distribuidos se convierte en el pegamento que une los procesos dispersos y les permite intercambiar información de manera coherente y confiable. En este contexto, la transmisión de datos y mensajes no solo implica el desplazamiento de información entre nodos, sino también la consideración de desafíos únicos como la latencia de red, la tolerancia a fallos y la consistencia de datos. Dada la creciente relevancia de los sistemas distribuidos en aplicaciones modernas como la computación en la nube, el Internet de las cosas (IoT) y las redes descentralizadas, la investigación y el desarrollo continuo en procesos y comunicación son esenciales. Objetivo del bloque Analizar los procesos y comunicación dentro de los sistemas distribuidos, a través del estudio de sus fundamentos computacionales y teóricos, con el propósito de aplicar efectivamente estos conocimientos en el diseño, implementación y gestión de arquitecturas informáticas distribuidas. Lecturas base López, F. (2015). Sistemas distribuidos. México: UAM. (pp. 55-71, 72-86, 87-98). 3 S istemas de cómputo distribuido Steen, M. & Tanenbaum, A. (2023). Distributed systems. New York. (pp. 111-180, 181-246). Lecturas complementarias Chang, E., & Roberts, R. (1979). An improved algorithm for decentralized extrema-finding in circular configurations of processes. Communications of the ACM, 22(5), 281-283. García-Molina, H. (1982). Elections in a distributed computing system. IEEE transactions on Computers, 31(1), 48-59. 4 P rocesos y comunicación bloque dos 3. Procesos y comunicación Los sistemas distribuidos han emergido como una arquitectura fundamental en el diseño de sistemas informáticos contemporáneos y han proporcionado soluciones escalables y eficientes para abordar las demandas cada vez mayores de procesamiento y comunicación. La comunicación en sistemas distribuidos implica el intercambio de información entre las diversas entidades que componen el sistema. Este intercambio puede ocurrir a través de redes locales o globales, y se enfrenta a desafíos como la latencia, la consistencia y la seguridad. Los protocolos de comunicación, los modelos de concurrencia y los algoritmos de coordinación juegan un papel crucial en garantizar la coherencia y la sincronización en un entorno distribuido. Los procesos en sistemas distribuidos representan unidades de ejecución concurrentes que operan de manera independiente pero colaborativa para realizar tareas específicas. La gestión de procesos en este contexto implica abordar cuestiones como la concurrencia, la atomicidad de las operaciones y la sincronización para garantizar un comportamiento coherente y predecible del sistema. La comprensión detallada de los procesos y la comunicación en sistemas distribuidos se presenta como un imperativo para los desarrolladores y arquitectos de sistemas modernos, quienes deben abordar los complejos desafíos asociados con la descentralización de recursos y la colaboración entre entidades dispersas geográficamente. 3.1. Procesos Un proceso se define a menudo como un programa que actualmente se está ejecutando en uno de los procesadores virtuales del sistema operativo. Un problema importante es que el sistema operativo se esfuerza mucho para garantizar que los procesos independientes no afecten maliciosa o inadvertidamente la corrección del comportamiento de los demás. En otras palabras, se hace transparente el hecho de que múltiples procesos pueden compartir simultáneamente la misma CPU y otros recursos de hardware. Por lo general, el sistema operativo requiere soporte de hardware para hacer cumplir esta separación (Steen, 2023). Esta transparencia de concurrencia tiene un costo. Por ejemplo, cada vez que se crea un proceso, el sistema operativo debe construir un espacio de direcciones completamente independiente. La asignación puede implicar inicializar segmentos de memoria, como anular un segmento de datos, copiar el programa asociado en un segmento de texto y configurar una pila para datos temporales. Del mismo modo, cambiar la CPU entre dos procesos también puede requerir algún esfuerzo. Además de guardar los datos tal como se encuentran en varios registros (incluyendo el contador de programa y el puntero de pila), el sistema operativo también tendrá que modificar los registros de la Unidad de Gestión de Memoria (MMU) e invalidar las cachés de traducción de direcciones, como en el búfer de búsqueda de traducción (TLB) (Steen, 2023). Asimismo, si el sistema operativo admite más procesos de los que puede contener simultáneamente en la memoria principal, podría ser necesario intercambiar procesos entre la memoria principal y el disco antes de que se dé el cambio real. 5 S istemas de cómputo distribuido 3.1.1. Hilos Un hilo es la unidad más pequeña de ejecución dentro de un proceso. Mientras que un proceso es generalmente una instancia independiente de un programa en ejecución, los hilos son subdivisiones más pequeñas dentro de ese proceso (Steen, 2023). Un proceso puede tener uno o varios hilos de ejecución y estos comparten los recursos del proceso, como la memoria y los archivos abiertos, pero tienen su propia pila y registros. Los hilos dentro de un mismo proceso comparten la misma área de memoria, lo que facilita la comunicación entre ellos. La ejecución de múltiples hilos dentro de un proceso puede mejorar la eficiencia y el rendimiento de una aplicación, ya que pueden realizar tareas en paralelo. Por ejemplo, en un programa de procesamiento de imágenes, un hilo puede encargarse de cargar la imagen, mientras que otro hilo realiza operaciones de procesamiento en paralelo. Esto puede acelerar la ejecución de la aplicación, especialmente en sistemas con múltiples núcleos de CPU (Steen, 2023). Los hilos se distinguen de los procesos en que los primeros comparten los mismos recursos del programa que los contiene, a diferencia de los procesos que tienen su código y datos de manera independiente. Existen dos tipos de flujos de hilos identificables: ç Flujo único. Un programa solo utiliza un hilo para controlar su ejecución. ç Flujo múltiple. Los programas emplean varios contextos de ejecución para llevar a cabo su trabajo. En un sistema multihilos, cada tarea se inicia y termina tan pronto como sea posible, lo que facilita la entrada de datos en sistemas en tiempo real, especialmente cuando provienen de diversas fuentes (López, 2015). En un programa multihilo, el hilo principal del programa está en ejecución y, a su vez, tiene otros hilos o tareas paralelas en ejecución. Un hilo se define como una secuencia única de control de flujo dentro de un programa; por lo tanto, un programa puede tener más de una secuencia de control o hilo. Cada hilo es una parte independiente del programa que se ejecuta de manera autónoma. Es la unidad de código más pequeña ejecutable en un entorno multitareas. El uso de hilos permite a los programadores escribir programas más eficientes, ya que optimizan recursos importantes, como el rendimiento del CPU al minimizar los tiempos de inactividad. En entornos interactivos en red, los hilos son valiosos, ya que sincronizan las velocidades de transmisión de red con las velocidades de procesamiento del CPU. Esto es particularmente útil cuando la velocidad de manejo del sistema de archivos para lectura y escritura es más lenta en comparación con la velocidad de procesamiento del CPU. La Figura 1 esquematiza un programa de un hilo y un programa de dos hilos (López, 2015). Figura 1. Programa con un solo hilo y programa multihilos. Fuente: López (2015). 6 P rocesos y comunicación bloque dos 3.2. Comunicación La comunicación en sistemas distribuidos se refiere a la transferencia de información entre diferentes componentes o nodos que están ubicados en distintas máquinas físicas o lógicas. Estos sistemas distribuidos están diseñados para trabajar de manera cooperativa para lograr un objetivo común (Steen, 2023). Los paradigmas de comunicación más comúnmente empleados en este entorno son los siguientes: ç Cliente-servidor. ç Llamada a un procedimiento remoto (RPC). ç Comunicación en grupo. Algunos conceptos fundamentales que deben tenerse en cuenta para la comunicación son (López, 2015): ç Los datos deben ser aplanados antes de ser enviados. ç La representación de los datos debe ser consistente entre la fuente y el destino. ç Los datos deben ser empaquetados antes de su envío. ç Se deben utilizar operaciones de send para enviar y receive para recibir. ç La especificación de la comunicación, ya sea en modo bloqueante o no bloqueante. ç La abstracción del mecanismo de paso de mensajes. ç La confiabilidad de la comunicación, por ejemplo, optar por el uso de TCP en lugar de UDP. La comunicación efectiva en sistemas distribuidos es esencial para lograr la coordinación y colaboración entre los componentes del sistema, pues permite que funcionen como una entidad coherente a pesar de su distribución geográfica o lógica. Sabías que... En los sistemas distribuidos, la comunicación entre nodos es como un elegante baile sincronizado en el que múltiples entidades computacionales intercambian información de manera coordinada y eficiente. A diferencia de un sistema centralizado, donde la comunicación puede ser más directa, en entornos distribuidos cada paso requiere una cuidadosa orquestación. Este “baile” implica no solo la transmisión de datos, sino también la consideración de desafíos únicos como la latencia de red, la seguridad en la transmisión de información y la garantía de que todos los nodos estén en sintonía. Los protocolos de comunicación se convierten en la partitura que guía este baile y aseguran que la información fluya armoniosamente entre procesos geográficamente dispersos. La próxima vez que observes la colaboración entre nodos en un sistema distribuido, recuerda que detrás de cada intercambio de datos hay un refinado “baile” de comunicación que permite que estos sistemas trabajen en armonía y lleven a la eficiencia y a la coordinación a un nivel totalmente nuevo. 7 S istemas de cómputo distribuido 3.2.1. Llamado a procedimientos remotos El llamado a procedimientos remotos (RPC) es un mecanismo para ejecutar funciones en una máquina remota, por lo que da la ilusión de que la función se ejecuta en la máquina local. La idea detrás del RPC es hacer que una llamada a un procedimiento remoto se parezca lo más posible a una llamada local. En otras palabras, queremos que el RPC sea transparente: el procedimiento llamador no debería ser consciente de que el procedimiento llamado se está ejecutando en una máquina diferente o viceversa. Supongamos que existe un programa con acceso a una base de datos, el cual es capaz de añadir datos a una lista previamente almacenada. Tras realizar esta acción, el programa devuelve una referencia a la lista ya actualizada. En la Figura 2 se muestra una llamada a un procedimiento remoto, el cual se realiza considerando los siguientes pasos (Steen, 2023): ç RPC genera un archivo de interfaz de cliente (client stub) en el espacio de direcciones del cliente. ç El cliente stub serializa los parámetros y los convierte al formato de datos de red (formato de datos externo). Todos los parámetros se copian en un mensaje. ç El cliente stub envía el mensaje a la capa de transporte, la cual lo transmite a la máquina del servidor. ç En el lado del servidor, la capa de transporte pasa el mensaje a un servidor stub. El servidor stub deserializa los parámetros y llama a la función deseada de las disponibles en el servidor mediante el mecanismo de llamadas regulares a funciones. ç Cuando la función llamada por el servidor se completa, el control del programa retorna al servidor stub. ç El servidor stub serializa los valores de retorno en un mensaje y entrega el mensaje a la capa de transporte. ç La capa de transporte envía el mensaje que contiene el resultado de vuelta a la capa de transporte del cliente, la cual entrega el mensaje al cliente stub. ç El cliente stub deserializa los valores devueltos y el control retorna al llamador. Figura 2. Modo de operación de un RPC entre un proceso cliente y uno servidor. Fuente: López, 2015. Los RPC son utilizados en una variedad de contextos, desde la programación distribuida hasta la construcción de servicios web y sistemas distribuidos más amplios. Ejemplos de implementaciones de RPC incluyen tecnologías como gRPC, Java RMI (Remote Method Invocation), y XML-RPC, 8 P rocesos y comunicación entre otros. La elección de una tecnología de RPC específica dependerá de los requisitos y preferencias del sistema que se esté desarrollando. 3.2.2. Paso de mensajes El paso de mensajes permite actividades concurrentes a través de comunicación explícita. Normalmente, los procesos se ejecutan de manera autónoma. La única forma de interacción entre programas es mediante el intercambio de mensajes. El paso de mensajes puede ser síncrono o asíncrono. El modelo de paso de mensajes proporciona una gran flexibilidad en la comunicación de proceso a proceso. Aunque podemos aprovechar la flexibilidad para mejorar el rendimiento, su uso sin restricciones podría llevar a una degradación del rendimiento. Además, aumentan la complejidad de escribir programas sin errores. Por lo tanto, las bibliotecas de paso de mensajes como MPI son de gran ayuda para los programadores (Ghosh y Ghosh, 2023). bloque dos En el siguiente video encontrarás una breve introducción a las llamadas de procedimiento remoto, por lo que te invitamos a verlo: El paso de mensajes se utiliza en diversos contextos, desde sistemas distribuidos hasta aplicaciones de comunicación en red. Se implementa mediante APIs y bibliotecas específicas que proporcionan funciones para enviar, recibir y procesar mensajes. Ejemplos de implementaciones de paso de mensajes incluyen MPI (Message Passing Interface) para cómputo distribuido y sistemas de mensajería en arquitecturas de microservicios. La elección de esta técnica dependerá de los requisitos y la naturaleza específica del sistema distribuido que se esté construyendo (Ghosh, 2023). 3.3. Sincronización La sincronización en sistemas distribuidos se refiere al proceso de coordinar la ejecución de múltiples procesos o nodos de manera que se mantenga un orden temporal o lógico en la realización de operaciones. La sincronización es esencial para garantizar que los eventos y las actividades ocurran de manera predecible y coherente en un entorno distribuido donde los procesos pueden ejecutarse de forma concurrente y en nodos separados (Ghosh, 2023). La sincronización en sistemas distribuidos presenta mayores desafíos en comparación con sistemas centralizados debido a los siguientes aspectos (López, 2015): ç La información se distribuye entre varias máquinas. ç Los procesos toman decisiones basadas en información local. ç Es crucial evitar un único punto de falla. ç La ausencia de un reloj común y la falta de otra fuente de tiempo global complican la tarea. 9 S istemas de cómputo distribuido La sincronización en sistemas distribuidos es un componente crítico para garantizar la coherencia, la fiabilidad y el funcionamiento ordenado del sistema. La elección de los algoritmos y protocolos de sincronización dependerá de los requisitos específicos de la aplicación y de la naturaleza del sistema distribuido en cuestión. 3.3.1. Relojes En un sistema centralizado, el tiempo es inequívoco. Cuando un proceso desea conocer la hora, simplemente realiza una llamada al sistema operativo. Si el proceso A solicita la hora y luego, un poco más tarde, el proceso B solicita la hora, el valor que B obtendrá será mayor que (o posiblemente igual a) el valor obtenido por A. Ciertamente, no será menor. En un sistema distribuido, lograr un acuerdo sobre el tiempo no es trivial (Steen, 2023). En sistemas distribuidos, los relojes son instrumentos fundamentales para proporcionar una noción del tiempo y coordinar las actividades entre diferentes nodos. Hay varias clases de relojes utilizados en este contexto, cada uno con sus propias características y desafíos. Aquí se mencionan dos tipos de relojes relevantes en sistemas distribuidos: Relojes lógicos Relojes de Lamport. Propuestos por Leslie Lamport, estos relojes lógicos son utilizados para establecer un orden parcial en eventos distribuidos. Cada proceso mantiene un contador local que se incrementa con cada evento local y se actualiza cuando recibe mensajes de otros procesos. Sin embargo, no garantizan la relación temporal precisa entre eventos en diferentes nodos (Ghosh, 2023). Imagina un sistema distribuido en el que los relojes de los nodos no están sincronizados adecuadamente. Reflexiona sobre cómo esto podría influir en situaciones como la transmisión de mensajes, la ejecución de tareas concurrentes y la coherencia de datos. 10 Relojes vectoriales: Introducidos para mejorar las limitaciones de los relojes de Lamport, los relojes vectoriales mantienen un vector de contadores locales, uno para cada proceso. Este enfoque permite establecer un orden parcial más preciso entre eventos distribuidos y es especialmente útil para gestionar situaciones donde se requiere conocer la relación temporal entre eventos en diferentes nodos (Ghosh, 2023). Es importante destacar que la sincronización de relojes en sistemas distribuidos es un desafío debido a la variabilidad en la latencia de red y a la posibilidad de fallos. Los algoritmos y protocolos utilizados deben abordar estos desafíos para garantizar una sincronización precisa y confiable. Además, la elección del tipo de reloj y del método de sincronización dependerá de los requisitos específicos de la aplicación y de la naturaleza del sistema distribuido. P rocesos y comunicación bloque dos 3.3.2. Exclusión mutua En sistemas distribuidos, se presentan situaciones en las que existen recursos compartidos que no pueden ser utilizados simultáneamente por más de un proceso. En sistemas que comparten memoria física, es común emplear semáforos o monitores para asegurar el uso exclusivo de la región crítica. Sin embargo, en sistemas distribuidos, donde los procesos no comparten la memoria física, es necesario idear algoritmos adicionales para garantizar la exclusión mutua. Los algoritmos de exclusión mutua en sistemas distribuidos deben cumplir con requisitos básicos, como la inanición, la seguridad y el orden. La inanición se encarga de asegurar que un proceso que busca entrar en una región crítica eventualmente pueda hacerlo, de esta forma se evitan interbloqueos y se garantiza que no haya procesos en situación de inanición. La seguridad implica que la exclusión mutua debe garantizar que, en la región crítica, como máximo, solo se ejecute un proceso en un momento dado. El orden establece que el acceso a la región crítica debe seguir el orden causal propuesto por Lamport, basado en la relación “sucedió antes”. 3.3.3. Algoritmo de elección Una elección es un procedimiento llevado a cabo por los procesos de un grupo específico para seleccionar a uno de ellos para realizar una tarea particular, como la coordinación. El objetivo del algoritmo de elección es asegurar que, al comenzar una tarea, todos los procesos estén de acuerdo sobre quién será el nuevo coordinador. Para llevar a cabo este procedimiento, un algoritmo de elección utiliza tres tipos de mensajes: la anunciación del evento de elección, la votación y la anunciación del resultado de la elección. Algoritmo del grandulón En el contexto del algoritmo del “grandulón”, propuesto por García-Molina en 1982, se sigue un método general y se establecen ciertas premisas: ç El sistema es síncrono y utiliza tiempos de espera para la identificación de fallos en los procesos. ç Se permite que los procesos se bloqueen durante la ejecución del algoritmo. ç La entrega de mensajes entre procesos se asume fiable y dentro de un periodo máximo. ç Los procesos están ordenados, tienen un identificador único (IDs) conocido y se sabe la cantidad total de procesos existentes (López, 2015). La operación es la siguiente: 1. Cuando el proceso x detecta que el coordinador ha fallado, envía un mensaje de elección a todos los procesos con identificadores más grandes que el suyo. 2. El proceso x espera los votos y, si no recibe ningún voto (ok) después de un periodo específico, se autodeclara coordinador y envía el mensaje de coordinador a los procesos con identificadores más bajos que el suyo. 3. Si llega al menos un voto (aunque pueden llegar varios), puede resultar en la declaración de otro coordinador ganador. 4. Si un proceso recibe un mensaje de elección, responde con un voto y comienza otra elección (paso 4 de la Figura 3). 5. Cuando un coordinador que había fallado regresa, inicia una elección y tiene la posibilidad de recuperar el control, incluso si hay un coordinador actualmente en funciones (López, 2015). 11 S istemas de cómputo distribuido Un ejemplo de cómo opera el algoritmo del “grandulón” se ilustra en la Figura 3. Para profundizar en este tema, en el siguiente artículo encontrarás los fundamentos del algoritmo del grandulón propuesto por García-Molina: García-Molina, H. (1982). Elections in a distributed computing system. IEEE transactions on Computers, 31(1), 48-59. Figura 3. Ejemplo del algoritmo del “grandulón” para elegir a un nuevo coordinador. Fuente: López (2015). Algoritmo de anillo Otros algoritmos de elección se fundamentan en topologías de anillo, ya sea lógico o físico. Existen varios algoritmos de elección basados en anillo, y en este caso, se describe el algoritmo de anillo de Chang & Roberts, que se basa en el principio de extinción selectiva. Este algoritmo se utiliza en situaciones donde: ç Los procesos están física o lógicamente ordenados en un anillo. ç No se conoce el número total de procesos (n). ç Cada proceso se comunica con su vecino (izquierda o derecha). La operación de este algoritmo se ilustra en la Figura 4 y sigue estos pasos (López, 2015): 12 P rocesos y comunicación 1. bloque dos Inicialmente, todos los procesos son “no participantes”. 2. Cualquier proceso P decide iniciar una elección en cualquier momento. 3. Este proceso P se coloca en estado “participante” y envía un mensaje de elección M a su vecino. 4. El mensaje M enviado contiene el ID (identificador) del proceso que ha iniciado la elección. 5. Cuando el vecino recibe el mensaje de elección M, establece su estado como participante y verifica el ID del mensaje. 6. Si el ID es mayor que su propio ID, lo envía directamente a su vecino. 7. Si su ID es mayor al ID recibido, lo coloca en el mensaje M y lo envía a su vecino. 8. Este proceso de circulación del mensaje M continúa sucesivamente hasta que llega a un proceso Pn que comprueba que el ID recibido es el suyo propio. Esto indica que solo ha sobrevivido el mayor ID, que pertenece al proceso Pn. 9. En consecuencia, el proceso Pn se convierte en el coordinador y lo comunica a su vecino. Cuando un proceso recibe un mensaje de coordinador, debe cambiar su estado a “no participante” y enviar el mensaje a su vecino. 10. Cuando el mensaje de coordinador regresa al proceso que lo emitió (el coordinador original), todos los procesos conocen quién es el coordinador, y todos cambian a estado “no participante”. En el escenario en el que dos procesos inicien una elección al mismo tiempo y envíen mensajes de elección, un proceso en estado “participante” debe verificar el ID del proceso que emite el mensaje de elección. Si el ID es menor que el propio, el proceso descarta el mensaje. De esta manera, todos los mensajes de elección se extinguirán, a excepción del que contiene el ID más alto. En el siguiente artículo encontrarás los fundamentos del algoritmo de anillo propuesto por Chang y Roberts. Chang, E., & Roberts, R. (1979). An improved algorithm for decentralized extrema-finding in circular configurations of processes. Communications of the ACM, 22(5), 281-283. 13 S istemas de cómputo distribuido Figura 4. Algoritmo de elección que utiliza un anillo. Fuente: López (2015). Existen otros algoritmos de elección, cada uno con sus propias características y consideraciones específicas según los requisitos del sistema distribuido en el que se implementan. 3.3.4. Algoritmos de consenso Los algoritmos de consenso son utilizados en sistemas distribuidos para lograr que los nodos acuerden un valor o una decisión común, incluso cuando algunos de los nodos pueden fallar o comportarse de manera inesperada. El consenso es un problema fundamental en sistemas distribuidos y es crucial para garantizar la coherencia y la integridad en la toma de decisiones. Problema de los generales bizantinos El problema de los generales bizantinos fue originalmente formulado por Lamport, Shostak y Pease. Este problema plantea la situación en la que un grupo de generales asedia una ciudad y debe llegar a un acuerdo mediante un plan de ataque para decidir si atacar o retirarse, independientemente de la presencia de generales traidores en el grupo. La comunicación entre los generales se realiza exclusivamente a través de mensajes. El general comandante emite las órdenes, mientras que los tenientes generales deben decidir si atacar o retirarse (López, 2015). El desafío radica en que uno o más de los generales pueden ser traidores o pueden fallar. La traición puede manifestarse de dos maneras: ç Los mensajes pueden no llegar, es decir, las comunicaciones no son confiables. ç Un general traidor puede mentir, lo que implica que un nodo puede fallar de manera impredecible. A continuación, se examinan las circunstancias bajo las cuales se puede lograr un acuerdo entre los generales leales y cuándo dicho acuerdo es imposible. Caso 1: Tres generales Este caso ilustra el escenario en el que hay un general comandante y dos tenientes generales, y al menos uno de ellos es traidor. La pregunta clave es si los generales leales pueden llegar a un consenso, es decir, acordar “atacar” o “retirarse”. Supongamos que el general comandante es el traidor, como se muestra en la Figura 5a. En este caso, el general comandante instruirá al teniente general 1 a “atacar” y al teniente general 2 a “retirarse”. Ambos tenientes intentarán verificar la orden comunicándose entre ellos. El teniente general 1 informará al teniente general 2 que recibió la orden de “atacar”, mientras que el teniente general 2 indicará al teniente general 1 que recibió la orden de “retirarse”. Ambos tenientes generales podrán deducir que el general comandante es un traidor, pero no podrán llegar a una decisión consensuada. 14 P rocesos y comunicación bloque dos Considerando los mismos participantes, ahora supongamos que el teniente general 2 es el traidor, mientras que el general comandante y el teniente general 1 son leales. Este escenario se representa en la Figura 5b, donde el general comandante emite la orden de “atacar” a ambos tenientes generales, quienes intercambian la orden recibida. El teniente general 1 le comunica al teniente general 2 la orden de “atacar”. Sin embargo, dado que el teniente general 2 es traidor, modifica la orden recibida y le indica al teniente general 1 que debe “retirarse”. En ambos escenarios, el teniente general escucha dos órdenes diferentes, tanto del general comandante como del teniente general 2, sin saber cómo actuar. Por lo tanto, en ambos casos, no se logra un consenso (López, 2015). Figura 5. Caso de tres generales donde uno es traidor. a) El general comandante es el traidor, b) El teniente general es el traidor. No se llega a un consenso. Fuente: López (2015). Caso 2: Cuatro generales Presentamos ahora un escenario similar al anterior, pero con cuatro generales: un general comandante y tres tenientes generales, de los cuales uno es traidor. La pregunta clave es si los generales leales pueden llegar a un consenso para acordar “atacar” o “retirarse”. Supongamos que el general comandante es el traidor y los tres tenientes generales son leales. Independientemente de las órdenes que reciban los tenientes generales del general comandante, intercambian dichas órdenes entre sí. Al decidir por mayoría de las órdenes recibidas, los tres tenientes generales tomarán la misma decisión, que en este caso sería “atacar”. Este escenario se presenta en la Figura 6a. Figura 6. Caso de cuatro generales donde uno es traidor. a) El general comandante es el traidor, b) un teniente general es el traidor. En ambos casos, el consenso es “atacar”. Fuente: López (2015). Ahora, si asumimos que el comandante general y los tenientes generales 1 y 2 son leales, excepto el teniente general 3, quien es traidor, se obtiene un escenario similar al mostrado en la Figura 6b. El comandante general envía la orden de “atacar” a todos los tenientes generales. Aunque el teniente 15 S istemas de cómputo distribuido general 3, como traidor, cambia la orden recibida y envía a los tenientes generales 1 y 2 la orden de “retirarse”, esto no afecta la decisión consensuada de los tenientes generales 1 y 2, ya que, por mayoría, deciden “atacar”. Es relevante señalar que el general traidor podría haber enviado cualquier mensaje sin que esto alterara el consenso del resultado. El problema de los generales bizantinos es comúnmente mencionado en el contexto de la tolerancia a fallas en sistemas distribuidos y también se conoce como el problema de acuerdo bizantino. Lamport, Shostak y Pease demostraron que en un sistema con k procesos defectuosos, el consenso solo se puede alcanzar si hay presentes 2k+1 procesos que funcionen correctamente, lo que suma un total de 3k+1 procesos (López, 2015). 3.4. Transacciones distribuidas En términos generales, los sistemas distribuidos involucran dos acciones que pueden considerarse contrastantes. La primera acción implica que los clientes no deben interferir en las operaciones realizadas por otros clientes, mientras que la segunda acción establece que el servidor debe ser utilizado por los clientes para compartir e intercambiar información entre ellos. Para abordar situaciones que involucran datos compartidos, se utiliza una herramienta conceptual fundamental conocida como transacción, la cual representa una unidad indivisible de manipulación de información. En sistemas distribuidos, estas transacciones son denominadas transacciones atómicas y sirven como un mecanismo de alto nivel que oculta detalles técnicos, como la sincronización, la exclusión mutua, los interbloqueos y la recuperación de fallas. Algunas características clave de las transacciones incluyen: ç Agrupan operaciones en una transacción, donde todas se completan o ninguna se realiza. En caso de la última situación, se restaura el estado inicial. ç Para implementar transacciones, el servidor debe encapsular (aislar) los recursos que gestiona. En resumen, las transacciones distribuidas son operaciones que abarcan múltiples nodos o recursos en un entorno distribuido, y su gestión implica protocolos y estrategias específicas para garantizar la coherencia y atomicidad de las operaciones en dicho entorno. 3.4.1. Problemas debido a la concurrencia de transacciones Entre los principales objetivos del servidor de transacciones se encuentran la maximización de la concurrencia y la utilización de la serie equivalente. Las operaciones atómicas deben ser capaces de bloquear el acceso de varios usuarios a una región crítica. El problema de modificaciones y pérdidas surge cuando una transacción se aborta. Por otro lado, el problema de informes inconsistentes ocurre cuando una transacción lee un dato antes de que otra transacción lo actualice. Una solución a este problema sería emplear la serie equivalente de transacciones en lugar de las entrelazadas de instrucciones. La equivalencia en serie se utiliza como criterio para derivar diversos mecanismos de control de concurrencia. El servicio de transacciones asegura que el resultado será el mismo si las transacciones se llevan a cabo de manera secuencial (López, 2015). 16 P rocesos y comunicación bloque dos Para abordar estos problemas, se utilizan técnicas y protocolos de control de concurrencia, como bloqueo, aislamiento, y protocolos de dos fases, que buscan garantizar la coherencia y la integridad de los datos en entornos distribuidos con transacciones concurrentes. 3.4.2. Recuperación de transacciones Un servicio de transacciones debe tener la capacidad de abortar transacciones y recuperarse de los efectos resultantes. Algunos de los problemas asociados con la cancelación de transacciones incluyen lecturas sucias, cascada de abortos y escrituras prematuras (López, 2015). A continuación, se explican: ç El problema de las “lecturas sucias” surge cuando una transacción exitosa lee datos que han sido afectados por una transacción abortada. Una solución a este problema implica posponer la decisión de declarar exitosa una transacción hasta que todas las transacciones relacionadas hayan tenido éxito. ç En el caso de la “cascada de abortos”, se propone como solución retrasar las lecturas hasta que las transacciones que están escribiendo en los mismos datos hayan abortado o tenido éxito. ç El problema de las “escrituras prematuras” se manifiesta cuando dos transacciones escriben en el mismo dato simultáneamente. Para abordar este problema, se sugiere retrasar las operaciones de escritura. El uso de versiones tentativas suele ser una estrategia efectiva para evitar estos retrasos (López, 2015). La recuperación de transacciones es esencial para mantener la integridad de los datos y garantizar que el sistema pueda recuperarse de manera efectiva después de fallas o interrupciones, lo cual contribuye a la confiabilidad y disponibilidad de los sistemas distribuidos. 3.4.3. Transacciones anidadas y distribuidas Las transacciones anidadas y distribuidas son conceptos clave en sistemas distribuidos y bases de datos que involucran operaciones en múltiples nodos o fuentes de datos. A continuación, se explican: Transacciones anidadas Una transacción anidada (TA) se compone de un conjunto de transacciones, cada una de las cuales puede, a su vez, estar constituida por transacciones adicionales, de esta forma se crea una estructura jerárquica, como se ilustra en la Figura 7. Figura 7. Ejemplo de transacción anidada. Fuente: López (2015). 17 S istemas de cómputo distribuido Las transacciones anidadas resultan beneficiosas para diversos propósitos: ç Establecer una jerarquía entre las transacciones en función de su importancia. ç Definir la concurrencia de manera más específica. ç Reforzar el control de las transacciones, esto permite que una transacción anidada pueda abortar sin requerir que su transacción principal también lo haga. ç Modelar transacciones distribuidas, que son aquellas en las que diferentes partes de la transacción se llevan a cabo en sitios geográficamente separados. Las transacciones anidadas pueden ayudar a organizar y estructurar operaciones complejas, esto facilita la administración y el mantenimiento del código. Transacciones distribuidas En este tipo de transacciones, una transacción involucra a varios servidores (ver la Figura 8a), lo que puede dar lugar a la presencia de datos replicados. Un coordinador (ver la Figura 8b) se designa como el primer servidor que gestiona las transacciones y asume responsabilidades como las siguientes: ç Abortar o confirmar el éxito de la transacción. ç Utilizar nuevos servidores para llevar a cabo la transacción. Figura 8. a) Esquema de la transacción distribuida, b) Coordinación de transacciones. Fuente: López (2015). Ambos conceptos, transacciones anidadas y distribuidas, son esenciales en entornos donde la complejidad de las operaciones y la distribución geográfica de los recursos son factores críticos. La gestión efectiva de estas transacciones contribuye a garantizar la consistencia, la atomicidad y la durabilidad de las operaciones en sistemas distribuidos. 3.4.4. Transacciones con replicación Las transacciones con replicación son un enfoque en sistemas distribuidos donde una transacción implica a múltiples servidores, lo que puede resultar en la replicación de datos en distintos nodos del sistema. Este enfoque se utiliza para mejorar la disponibilidad, la redundancia y la tolerancia a fallas en entornos distribuidos. Existen tres modelos para gestionar peticiones en un sistema de transacciones con replicación: ç Asíncrono. Las peticiones son procesadas por servidores de réplicas locales de manera independiente. ç Síncrono. Las peticiones de modificación son procesadas en el mismo orden en todas las réplicas y se establece un orden total entre ellas. 18 P rocesos y comunicación bloque dos ç Mixto. Ciertas réplicas pueden ser contactadas y procesadas en el mismo orden, mientras que otras pueden operar de manera asincrónica (López, 2015). La elección del modelo depende de la relación entre el número promedio de lecturas y escrituras. El orden en el que pueden ser procesadas dos peticiones, r1 y r2, en los servidores de réplicas puede seguir dos principios: ç Total. Se establece si r1 es procesada antes que r2 en todos los servidores de réplicas o viceversa. ç Casual. Se establece si r1 → r2, lo que implica que r1 debe ser procesada antes que r2 en todos los servidores de réplicas. En un entorno síncrono, la ejecución de r1 implica que todas las peticiones han sido realizadas antes en todos los servidores de réplicas. Una petición no se procesará en un servidor de réplicas hasta que se cumplan las restricciones de orden y la petición haya sido encolada (López, 2015). Las transacciones con replicación son una estrategia valiosa en sistemas distribuidos para abordar desafíos relacionados con la disponibilidad, la tolerancia a fallos y el rendimiento. Esto permite el acceso eficiente a los datos en entornos distribuidos y redundantes. 19 S istemas de cómputo distribuido Referencias López, F. (2015). Sistemas distribuidos. México: UAM. Ghosh, R. K., & Ghosh, H. (2023). Distributed Systems. New Jersey: IEEE Press. Steen, M. V. (2023). Distributed systems. New York. 20