diff --git a/content/sd/0002-apis-de-comunicacao.md b/content/sd/0002-apis-de-comunicacao.md index 5733b695..ebf6e359 100644 --- a/content/sd/0002-apis-de-comunicacao.md +++ b/content/sd/0002-apis-de-comunicacao.md @@ -18,77 +18,117 @@ type: content ## Representação externa de dados e _marshalling_ -A informação armazenada em programas é representada com diversas estruturas de dados, enquanto que a informação transmitida em mensagens consiste numa sequência de _bytes_. Independentemente da forma de comunicação utilizada, as estruturas de dados devem ser _flattened_ (convertidas numa sequência de bytes) antes da transmissão e reconstruídas na chegada. +A informação armazenada em programas é representada com diversas estruturas de +dados, enquanto que a informação transmitida em mensagens consiste numa sequência +de _bytes_. Independentemente da forma de comunicação utilizada, as estruturas de +dados devem ser _flattened_ (convertidas numa sequência de bytes) antes da +transmissão e reconstruídas na chegada. -Visto que nem todos os computadores armazenam os valores primitivos da mesma forma, um dos seguintes métodos pode ser utilizado para permitir que dois computadores troquem dados binários: +Visto que nem todos os computadores armazenam os valores primitivos da mesma forma, +um dos seguintes métodos pode ser utilizado para permitir que dois computadores +troquem dados binários: -- Os valores são convertidos para um formato externo acordado antes da transmissão e convertidos para o formato local ao serem recebidos -- Os valores são transmitidos no formato do remetente, juntamente com uma indicação do formato utilizado, e o destinatário converte os valores se necessário +- Os valores são convertidos para um formato externo acordado antes da transmissão + e convertidos para o formato local ao serem recebidos +- Os valores são transmitidos no formato do remetente, juntamente com uma indicação + do formato utilizado, e o destinatário converte os valores se necessário ## Protocolos _request-reply_ -Esta forma de comunicação foi concebida para suportar as _roles_ e trocas de mensagens das interações típicas cliente-servidor. Normalmente, a comunicação _request-reply_ é síncrona porque o processo cliente bloqueia até receber resposta do servidor. A comunicação assíncrona pode ser útil em situações em que os clientes podem receber as respostas mais tarde. +Esta forma de comunicação foi concebida para suportar as _roles_ e trocas de +mensagens das interações típicas cliente-servidor. Normalmente, a comunicação +_request-reply_ é síncrona porque o processo cliente bloqueia até receber resposta +do servidor. A comunicação assíncrona pode ser útil em situações em que os clientes +podem receber as respostas mais tarde. -Embora muitas implementações atuais usem [TCP](/rc/transporte/#tcp---transmission-control-protocol), um protocolo baseado em [UDP](/rc/transporte/#udp---user-datagram-protocol) evita _overheads_ desnecessários, em particular: +Embora muitas implementações atuais usem +[TCP](/rc/transporte/#tcp---transmission-control-protocol), um protocolo baseado em +[UDP](/rc/transporte/#udp---user-datagram-protocol) evita _overheads_ desnecessários, +em particular: -- Os _acknowledgements_ são redundantes, uma vez que os pedidos são seguidos por respostas -- Estabelecer uma conexão envolve dois pares extra de mensagens para além do par necessário (pedido e resposta) -- O controlo de fluxo é redundante para a maioria das invocações, visto que usam argumentos e resultados pequenos +- Os _acknowledgements_ são redundantes, uma vez que os pedidos são seguidos por + respostas +- Estabelecer uma conexão envolve dois pares extra de mensagens para além do par + necessário (pedido e resposta) +- O controlo de fluxo é redundante para a maioria das invocações, visto que usam + argumentos e resultados pequenos :::tip[Nota] -Muitas vezes é difícil decidir o tamanho apropriado para o _buffer_ no qual vamos receber os datagramas (isto aplica-se tanto do lado do cliente como do servidor). O tamanho limitado dos datagramas pode não ser adequado para sistemas [RMI](https://pt.wikipedia.org/wiki/RMI) ou [RPC](/sd/apis-de-comunicacao/#rpc), uma vez que os argumentos e resultados dos _procedures_ podem ter um tamanho arbitrário. +Muitas vezes é difícil decidir o tamanho apropriado para o _buffer_ no qual vamos +receber os datagramas (isto aplica-se tanto do lado do cliente como do servidor). +O tamanho limitado dos datagramas pode não ser adequado para sistemas +[RMI](https://pt.wikipedia.org/wiki/RMI) ou [RPC](#rpc), uma vez que os argumentos e +resultados dos _procedures_ podem ter um tamanho arbitrário. ::: ### Exemplo de aplicação UDP -Vamos analisar o comportamento de uma aplicação cliente-servidor que utiliza UDP para a troca de mensagens. +Vamos analisar o comportamento de uma aplicação cliente-servidor que utiliza UDP +para a troca de mensagens. Ao utilizar UDP, sabemos que as mensagens podem: - Perder-se - Chegar fora de ordem - Chegar repetidas -Imaginemos um caso em que o cliente não recebe resposta ao seu pedido. Tem agora 2 opções: -ou **retorna erro** ou **repete o envio**. +Imaginemos um caso em que o cliente não recebe resposta ao seu pedido. +Tem agora 2 opções: ou **retorna erro** ou **repete o envio**. Se chegar uma resposta depois do reenvio, pode ter acontecido 1 de 3 cenários: - O pedido original não chegou ao servidor (operação executada apenas 1 vez) - A resposta ao pedido original perdeu-se (operação executada 2 vezes) -- O servidor recebeu o pedido original e começou a processá-lo, mas _crashou_, podendo a operação ter sido realizada ou não caso não seja atómica (operação executada 1 ou 2 vezes) +- O servidor recebeu o pedido original e começou a processá-lo, mas _crashou_, + podendo a operação ter sido realizada ou não caso não seja atómica (operação + executada 1 ou 2 vezes) -O facto de a operação ser repetida, além de desperdiçar tempo, pode ter efeitos inesperados caso esta não seja **idempotente** (operação que produz o mesmo estado e devolve a mesma resposta independentemente do número de vezes que for executada). +O facto de a operação ser repetida, além de desperdiçar tempo, pode ter efeitos +inesperados caso esta não seja **idempotente** (operação que produz o mesmo estado +e devolve a mesma resposta independentemente do número de vezes que for executada). -Como é que o servidor pode evitar isto? Tem que ser capaz de verificar se o _id_ do pedido já foi recebido anteriormente: +Como é que o servidor pode evitar isto? Tem que ser capaz de verificar se o _id_ +do pedido já foi recebido anteriormente: - Se for a primeira vez: executa a operação normalmente -- Se for repetido: deve ter guardado o histórico de respostas a pedidos executados e retornar a resposta correspondente (isto implica o armazenamento de _ids_ e suas respostas) +- Se for repetido: deve ter guardado o histórico de respostas a pedidos executados + e retornar a resposta correspondente (isto implica o armazenamento de _ids_ e suas + respostas) -Conseguimos assim perceber que programar sistemas distribuídos através de _sockets_ é bastante complexo e vulnerável a falhas, pelo que iremos utilizar mais um nível de abstração, o RPC. +Conseguimos assim perceber que programar sistemas distribuídos através de _sockets_ +é bastante complexo e vulnerável a falhas, pelo que iremos utilizar mais um nível de +abstração, o RPC. ## RPC -O **RPC** (_Remote Procedure Call_) permite que um cliente execute funções (_procedures_) remotamente num servidor -mas de forma aparentemente local. O facto da execução ser remota levanta dois problemas principais: +O **RPC** (_Remote Procedure Call_) permite que um cliente execute funções +(_procedures_) remotamente num servidor mas de forma aparentemente local. +O facto da execução ser remota levanta dois problemas principais: -1. A rede entre o cliente e o servidor não é _reliable_, tendo tendência a perder e reordenar mensagens -2. Os computadores onde ambos os processos correm podem ter arquiteturas muito diferentes +1. A rede entre o cliente e o servidor não é _reliable_, tendo tendência a perder + e reordenar mensagens +2. Os computadores onde ambos os processos correm podem ter arquiteturas muito + diferentes Programação típica com RPC: ![Programação típica com RPC](./assets/0002-rpc-programming.svg#dark=3) -As **Interface definition languages** (IDLs) foram concebidas para permitir que os procedimentos sejam invocados noutras linguagens de programação. Uma IDL fornece uma notação para definir interfaces e parâmetros de operações (input e output). +As **Interface definition languages** (IDLs) foram concebidas para permitir que +os procedimentos sejam invocados noutras linguagens de programação. Uma IDL +fornece uma notação para definir interfaces e parâmetros de operações (input e output). Este processo segue um mecânismo de _request reply_: -1. O cliente passa os argumentos do procedure para o _local stub_, que os transforma num _request_ (mantendo assim a ilusão de que se está a chamar um procedure local) +1. O cliente passa os argumentos do procedure para o _local stub_, que os transforma + num _request_ (mantendo assim a ilusão de que se está a chamar um procedure local) 2. O _stub_ invoca o protocolo RPC para enviar este request para o servidor -3. O servidor recebe o request, que é traduzido pelo seu _stub_ de forma a obter os argumentos (utilizando o mesmo protocolo) +3. O servidor recebe o request, que é traduzido pelo seu _stub_ de forma a obter os + argumentos (utilizando o mesmo protocolo) 4. Executa localmente o procedure 5. Devolve uma resposta ao cliente de acordo com o protocolo -6. O _stub_ do cliente traduz a resposta e obtém assim o valor, que devolve ao programa que chamou o procedure +6. O _stub_ do cliente traduz a resposta e obtém assim o valor, que devolve ao + programa que chamou o procedure ![Implementação do RPC](./assets/0002-rpc-implementation.png#dark=3) @@ -101,11 +141,16 @@ Existem várias semânticas de invocação (e mecanismos associados): - _**At-most-once**_ : O procedure é executado no máximo 1 vez - mecanismos: RPC timeout + Resend + **Message id + Response history** - _**Exactly-once**_ : O procedure é executado exatamente 1 vez - - mecanismos: RPC timeout + Resend + Message id + Response history + **Transaction rollback** + - mecanismos: RPC timeout + Resend + Message id + Response history + **Transaction + rollback** :::tip[Transparência] -Os criadores do RPC queriam tornar as chamadas de procedimento remoto idênticas às chamadas locais (sem distinção na sintaxe). No entanto, as chamadas de procedimento remoto são mais suscetíveis a falhas, devido à presença de uma rede, outro computador e outro processo. Isto exige transparência para que os clientes sejam capazes de recuperar caso haja falhas. +Os criadores do RPC queriam tornar as chamadas de procedimento remoto idênticas às +chamadas locais (sem distinção na sintaxe). No entanto, as chamadas de procedimento +remoto são mais suscetíveis a falhas, devido à presença de uma rede, outro computador +e outro processo. Isto exige transparência para que os clientes sejam capazes de +recuperar caso haja falhas. ::: @@ -113,11 +158,18 @@ A implementação que iremos utilizar na cadeira é o **gRPC**. ## gRPC -Tem como base [HTTP/2](/rc/aplicacao/#http-20) e por sua vez [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) e [TCP](/rc/transporte/#tcp---transmission-control-protocol). É um mecanismo focado em serviços cloud (e não no paradigma cliente/servidor) baseado no RPC utilizado internamente pela Google. - -- Utiliza uma **IDL** (_Interface Definition Language_) para especificar os tipos dos dados e quais as operações disponíveis. - - Um exemplo de IDL é o [**protobuf**](https://protobuf.dev/) utilizado pela Google, que fornece o seu compilador **protoc** para gerar código (por ex. Java) -- Fornece ferramentas de **geração de código a partir da IDL** (conversão de dados + invocação remota) +Tem como base [HTTP/2](/rc/aplicacao/#http-20) e por sua vez +[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) e +[TCP](/rc/transporte/#tcp---transmission-control-protocol). É um mecanismo focado +em serviços cloud (e não no paradigma cliente/servidor) baseado no RPC utilizado +internamente pela Google. + +- Utiliza uma **IDL** (_Interface Definition Language_) para especificar os tipos + dos dados e quais as operações disponíveis. + - Um exemplo de IDL é o [**protobuf**](https://protobuf.dev/) utilizado pela Google, + que fornece o seu compilador **protoc** para gerar código (por ex. Java) +- Fornece ferramentas de **geração de código a partir da IDL** (conversão de dados + + invocação remota) - As chamadas remotas podem ser **síncronas ou assíncronas** Uma chamada remota gRPC: @@ -131,20 +183,24 @@ Uma chamada remota gRPC: - Meta-dados opcionais - Um _trailer_ (indica se a chamada foi bem sucedida ou se ocorreu um erro) -Dado que estamos a utilizar a rede, podem acontecer falhas (o que deve ser tido em conta ao escrever os clientes) -e portanto podem ser devolvidas respostas com códigos de resultado em vez do tipo definido na IDL. Alguns exemplos: +Dado que estamos a utilizar a rede, podem acontecer falhas (o que deve ser tido em +conta ao escrever os clientes) e portanto podem ser devolvidas respostas com códigos +de resultado em vez do tipo definido na IDL. Alguns exemplos: - **0** - OK - **5** - not found - **13** - internal -De forma a saber como contactar o servidor, o **gRPC** utiliza por omissão [DNS](/rc/aplicacao/#dns---domain-name-system) como servidor de nomes. +De forma a saber como contactar o servidor, o **gRPC** utiliza por omissão +[DNS](/rc/aplicacao/#dns---domain-name-system) como servidor de nomes. ## Referências - Coulouris et al - Distributed Systems: Concepts and Design (5th Edition) - Secções 4.2 e 5.1-5.3 -- Larry Peterson and Bruce Davie - [Computer Networks: A Systems Approach](https://github.com/SystemsApproach/book) © Elsevier 2012 (License [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)) +- Larry Peterson and Bruce Davie - + [Computer Networks: A Systems Approach](https://github.com/SystemsApproach/book) + © Elsevier 2012 (License [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)) - Secção 5.3 - Imagem que ilustra funcionamento do RPC - Departamento de Engenharia Informática - Slides de Sistemas Distribuídos (2022/2023) diff --git a/content/sd/0003-tempo-e-sincronizacao.md b/content/sd/0003-tempo-e-sincronizacao.md index 438b88f7..1b9e83d9 100644 --- a/content/sd/0003-tempo-e-sincronizacao.md +++ b/content/sd/0003-tempo-e-sincronizacao.md @@ -657,7 +657,7 @@ com o custo adicional de processamento para reconstruir os vetores. ## Salvaguarda distribuída -Criar uma salvaguarda distribuída (ou _distribuded snapshot_) consiste +Criar uma salvaguarda distribuída (ou _distributed snapshot_) consiste essencialmente em capturar o estado global do sistema num determinado instante, o que pode ser útil porque permite: diff --git a/content/sd/0004-coordenacao-e-consenso.md b/content/sd/0004-coordenacao-e-consenso.md index 742033b8..4f32d887 100644 --- a/content/sd/0004-coordenacao-e-consenso.md +++ b/content/sd/0004-coordenacao-e-consenso.md @@ -20,7 +20,7 @@ type: content ## Exclusão mútua distribuída -Já fomos introduzido ao problema da exclusão mútua em +Já fomos introduzidos ao problema da exclusão mútua em [**Sistemas Operativos (SO)**](/so/programação/), que tem como objetivo garantir que dois processos/_threads_ não acedem concorrentemente ao mesmo recurso (ex: ficheiro, bloco de memória, ...), uma vez que tal pode causar incoerências @@ -170,7 +170,7 @@ Este algoritmo associa um **_voting set_** $V_i$ (também chamados **quóruns**) cada processo $p_i$ $(i = 1,2,...,N)$, onde $V_i \subseteq \{p_1, p_2, ..., p_N\}$. Os _sets_ $V_i$ são escolhidos de forma a que, para todo $i,j = 1,2,...,N$: -- $p_i \in V_i$ (atenção que um processo pode pertencer a mais que um _voting set_) +- $p_i \in V_i$ - $V_i \cap V_j \neq \varnothing$ – há pelo menos um membro comum entre quaisquer dois _voting sets_ - $|V_i| = K$ – de forma a ser justo, todos os _voting sets_ têm o mesmo tamanho @@ -296,7 +296,7 @@ Tolerância a falhas: Tal como vimos anteriormente, muitos algoritmos distribuídos precisam de atribuir cargos especiais a certos processos. Por exemplo, na variante -["servidor central"](/sd/coordenacao-e-consenso/#algoritmo-do-servidor-central) +["servidor central"](#algoritmo-do-servidor-central) dos algoritmos para exclusão mútua, o servidor é escolhido entre os processos que precisam de utilizar a secção crítica. É necessário um **algoritmo de eleição** para esta escolha, sendo essencial que todos os processos concordem com a mesma. diff --git a/content/sd/assets/0004-central-server.png b/content/sd/assets/0004-central-server.png index 13a6085e..3f31291c 100644 Binary files a/content/sd/assets/0004-central-server.png and b/content/sd/assets/0004-central-server.png differ diff --git a/content/sd/assets/0004-ricart-and-agrawala.png b/content/sd/assets/0004-ricart-and-agrawala.png index a69d52d1..b5f1abd4 100644 Binary files a/content/sd/assets/0004-ricart-and-agrawala.png and b/content/sd/assets/0004-ricart-and-agrawala.png differ diff --git a/content/sd/assets/0004-ring-based.png b/content/sd/assets/0004-ring-based.png index 707f3d13..32210c72 100644 Binary files a/content/sd/assets/0004-ring-based.png and b/content/sd/assets/0004-ring-based.png differ diff --git a/content/sd/assets/0004-ring-election-example.png b/content/sd/assets/0004-ring-election-example.png old mode 100755 new mode 100644 index c79e155e..3f640ff5 Binary files a/content/sd/assets/0004-ring-election-example.png and b/content/sd/assets/0004-ring-election-example.png differ