Sistemas DistribuídosIntrodução aos Sistemas Distribuídos
Definição e Características dos Sistemas Distribuídos
15 min de leitura · 1ª mais cobrada em Sistemas Distribuídos
O que é isto
Um sistema distribuído é uma coleção de computadores independentes que se apresenta aos usuários como um único sistema coerente. Cada máquina (um nó) tem processador e memória próprios; não há um relógio único nem um endereço de memória compartilhado entre os nós. A cooperação acontece só por troca de mensagens.
Essa definição exige mais do que "vários computadores na mesma rede". A rede sozinha não basta: dois PCs no mesmo cabo, cada um com seu disco, ainda não formam um sistema distribuído se cada um trabalha sozinho.
Quando os nós precisam cooperar, o projeto muda porque certas suposições deixam de valer. Três marcas acompanham a definição:
- Vários nós autônomos. Hardware e sistema operacional podem diferir. Um nó pode falhar sem que os outros parem. Não há um único "desligar o computador" que desligue o conjunto.
- Sem memória compartilhada física. Ler uma variável no outro nó não existe: envia-se uma mensagem e espera-se (ou não) uma resposta. Não há um endereço
0xA000que os dois processadores vejam. - Falhas parciais. Parte do sistema continua enquanto outra parte silencia ou se atrasa. Isso não ocorre num computador isolado, que ou está no ar ou cai inteiro. O projeto tem de conviver com "metade no ar".
A ausência de relógio global vem da mesma física: cada nó tem o próprio oscilador, sujeito a desvio. Não dá para carimbar dois eventos em máquinas distintas com "o mesmo instante" e usar isso como ordem absoluta.
Relógios locais servem para timeouts e logs; não substituem uma ordem compartilhada. A cooperação se apoia em mensagens, sem um tempo comum.
O DNS ilustra o conjunto em um exemplo compacto: o usuário pede um nome; vários servidores, em lugares distintos, colaboram. A consulta parece uma operação só. O programa cliente não escolhe o servidor autoritativo nem vê que um deles silenciou e outro respondeu.
"Parece um sistema só" significa uma pergunta e uma resposta, sem o usuário montar o mapa dos nós.
Ideia central
O projeto esconde a distribuição. Essa propriedade chama-se transparência: o usuário (ou o programa cliente) trata o sistema como se fosse um recurso local, único e estável, embora os pedaços estejam espalhados, replicados ou em movimento.
Esconde-se porque o programa que usa o recurso não deveria reescrever-se a cada mudança de máquina, de cópia ou de carga. A transparência é o contrato: a operação visível permanece a mesma; o que muda fica do lado de dentro.
Os tipos existem porque cada um esconde um fato diferente. Um sistema pode esconder o endereço (localização) e ainda assim exigir que o cliente escolha a cópia (sem replicação).
Os tipos abaixo nomeiam o que se esconde. Um "sim, é transparente" sem dizer qual fato some não distingue esses casos.
Dois deles se misturam com facilidade e precisam ficar separados:
- Replicação esconde que existem várias cópias do recurso.
- Desempenho esconde que a carga varia e que o sistema se reconfigura para continuar aceitável.
Ter três réplicas entra em transparência de replicação. Continuar usável quando a fila cresce entra em transparência de desempenho. Replicar pode ajudar o desempenho; o fato oculto continua outro.
Três outros nomes também se encostam e não são o mesmo fato. Localização esconde em qual máquina o recurso está agora. Migração esconde que ele mudou de máquina (o nome ficou). Falha esconde que uma máquina caiu e houve recuperação (dentro do que o serviço promete).
Um cliente que cola IP no código quebra localização; um que precisa "achar o host novo" depois da mudança quebra migração; um que vê o disco morto quebra falha.
Exemplo
Cada tipo com um caso mínimo. Em todos, o cliente usa o mesmo nome ou a mesma operação; o que muda é o fato oculto.
Acesso. As operações sobre o recurso remoto são as mesmas do recurso local. Abrir e ler /docs/nota.txt no disco da máquina ou num servidor de arquivos usa open/read (ou o equivalente); o programa não troca a API só porque o arquivo cruzou a rede.
A diferença de interface deixa de aparecer para o cliente. O endereço e o número de cópias são outros fatos.
Localização. O cliente não precisa do endereço físico nem do IP. Pede nota.txt pelo nome; o sistema resolve em qual máquina o arquivo está hoje.
Se amanhã o arquivo mudou de host, o mesmo nome continua válido: o cliente não cola um IP no código.
Replicação. Há várias cópias, e isso não aparece. Três servidores guardam nota.txt. O cliente lê "o arquivo". Não escolhe a cópia 2, nem vê que a escrita foi propagada às outras.
Se o cliente aponta "a réplica da sala 12", esse fato deixou de estar oculto.
Concorrência. Vários clientes usam o mesmo recurso ao mesmo tempo, e cada um vê um recurso bem-comportado. Ana e Bruno gravam nota.txt; o sistema serializa ou versiona por trás. Nenhum dos dois programa um protocolo de exclusão.
O conflito visível sobre o mesmo objeto não aparece na interface.
Migração. O recurso muda de máquina e o nome continua válido. O serviço de impressão sai do host A e passa a rodar no host B; os clientes seguem enviando ao mesmo nome lógico.
O movimento foi planejado. O fato oculto é onde o serviço corre agora.
Falha. Uma queda e a recuperação ficam ocultas (dentro do que o serviço promete). O servidor que atendia nota.txt cai; outro assume ou a requisição é refeita.
O cliente recebe o arquivo ou um erro de "arquivo inexistente", sem indicar qual disco falhou. O fato oculto é a queda.
Desempenho. Os programas clientes seguem aceitáveis enquanto a carga sobre o serviço varia dentro de um intervalo combinado. Às 10h há cinquenta aberturas de arquivo; ao meio-dia, cinco mil. O sistema acrescenta instâncias, desloca carga ou ajusta cache.
O cliente não reescreve o programa, nem precisa saber que o cluster cresceu. O fato oculto é a variação de carga. A existência de cópias é outro assunto. O "intervalo combinado" importa: fora dessa faixa o serviço não promete o mesmo. A transparência de desempenho não é "sempre rápido, qualquer carga".
Compare cópia e carga sobre o mesmo serviço de arquivos:
| O que o cliente não vê | Nome da transparência |
|---|---|
Existem três cópias de nota.txt |
replicação |
| A fila de aberturas foi de 50 para 5 000 e o serviço se reajustou | desempenho |
Replicar ajuda o desempenho, mas o fato oculto é outro. Se o cliente escolhe "réplica da sala 12", não há transparência de replicação. Se o cliente quebra quando a carga sobe, ainda que as réplicas existam, não há transparência de desempenho.
Catálogo sob pico de carga
Uma loja expõe catalogo.buscar("Dom Casmurro"). O programa da vitrine chama essa operação e espera uma lista. Por baixo há três servidores com o mesmo catálogo. O que segue classifica o que o cliente não vê, sem inventar um oitavo tipo.
A vitrine chama buscar com o título. Não passa IP, não escolhe servidor, não pergunta quantas cópias existem.
A operação é a de um catálogo "local" — acesso. O nome lógico catalogo basta para localização. Ainda não sabemos se há uma cópia ou três, nem se a fila está vazia.
Uma busca pode cair no servidor 1 hoje e no 2 amanhã. O estoquista atualiza o preço; a escrita propaga-se às três. A vitrine continua lendo "o catálogo", sem um parâmetro replica=2.
O fato oculto é a existência das cópias: replicação. Ainda não falamos de fila. Se a vitrine tivesse de escolher a cópia, este passo falharia, mesmo com três servidores no ar.
Das 10h ao meio-dia as buscas passam de dezenas para milhares (lançamento). O serviço acrescenta uma quarta instância e aquece o cache. A vitrine não troca a chamada nem adia o uso até a fila esvaziar: os programas seguem aceitáveis na faixa combinada.
O fato oculto agora é a variação de carga: desempenho. As três cópias do Passo 2 não substituem este fato. Podia haver réplicas e o cliente mesmo assim degradar (três cópias saturadas, sem reajuste). Podia haver uma só cópia com cache agressivo e o cliente continuar ok na faixa; aí haveria desempenho sem o fato "várias cópias".
O intervalo combinado é parte do nome: milhares de buscas ainda cabem; milhões podem não caber, e isso não anula a transparência de desempenho dentro da faixa.
O servidor 1 é desligado para manutenção; o nome catalogo passa a resolver no 2. A vitrine nem percebe a mudança de máquina. Isso é migração: o recurso andou, o nome ficou.
O servidor 1 morre durante buscar. Outro conclui ou a busca é refeita. A vitrine recebe a lista ou um erro de "título inexistente", não um relatório de disco.
Isso é falha: ninguém planejou o movimento. O fato oculto é a queda.
Ana e o estoquista gravam o preço ao mesmo tempo. Cada um vê um catálogo coerente; nenhum programa um protocolo de exclusão.
Isso é concorrência. O fato oculto é a intercalação de escritas. O número de cópias é outro assunto.
Os Passos 2 e 3 tratam de fatos distintos: cópias são replicação; carga que se reajusta é desempenho.
O Passo 4 escondeu a mudança de máquina entre buscas. Mover o recurso enquanto um acesso ainda corre é outro fato.
Relocação enquanto o acesso corre
Transparência de relocação oculta que o recurso é movido enquanto ainda está sendo usado. O cliente não reabre a sessão nem cola um endereço novo: o acesso em curso segue no mesmo nome.
Migração oculta que o recurso mudou de máquina e o nome ficou. Relocação exige o detalhe extra: o movimento ocorre durante um acesso aberto. Sem uso ainda aberto, trata-se só de migração. Ocultar a mudança de máquina sem alterar o modo de acesso ainda não caracteriza relocação.
A vitrine chama catalogo.buscar("Dom Casmurro") e a busca ainda não devolveu. O sistema passa o processo do servidor 1 para o 2 no meio dessa chamada. A vitrine recebe a lista pelo mesmo catalogo. Isso é relocação. Se o host só saísse entre buscas (Passo 4), seria migração.
Outro fato que aqueles sete tipos não nomeiam: várias operações em nós distintos que precisam parecer um único commit.
Transação como unidade atômica
Transparência de transação oculta a coordenação de uma transação distribuída: operações em nós distintos aparecem como uma unidade atômica (todas confirmam ou nenhuma).
O fato oculto não é a existência de cópias (replicação) nem o movimento de um recurso (migração ou relocação). É o acordo entre nós para o conjunto parecer um só commit.
A vitrine confirma uma compra: baixa o estoque no servidor 1 e cobra no servidor 2. O cliente chama comprar(...) uma vez. Se o cobrador recusa, o estoque desfaz; a vitrine não programa o protocolo. Isso é transparência de transação.
A queda no Passo 5 ficou oculta na interface. Tolerar falha também pode significar outra coisa: continuar útil com menos.
Continuar útil sob falha
Tolerância a falhas, neste recorte, é o contrato de continuar operando na presença de problemas, com degradação aceitável de desempenho e/ou de funcionalidades. O sistema permanece útil; não promete o mesmo tempo nem o mesmo conjunto de funções.
Transparência de falha esconde a queda da interface (o cliente recebe o dado ou um erro de recurso). Redundância mascara a falha para o cliente continuar atendido e correto. Transparência de falha e redundância são assuntos distintos. Neste contrato admite-se ficar mais lento ou desligar funções extras, desde que o serviço essencial siga.
Um dos três servidores do catálogo cai. As buscas passam a levar o dobro do tempo e a recomendação "quem comprou isto" some; buscar pelo título continua. Há degradação aceitável. Se o sistema parasse por completo, não haveria tolerância neste sentido.
A faixa combinada do Passo 3 esconde variação de carga. Escalar o conjunto pede um teto por máquina que não cresça com o número de nós.
Teto de carga independente de
Escalabilidade, neste recorte, exige que a carga em cada máquina fique limitada por uma constante independente do número de nós . Acrescentar máquinas não pode inflar a demanda num equipamento até um teto que cresce com .
Transparência de desempenho esconde a variação de carga na faixa combinada. O critério de escalabilidade é outro: nenhum nó vira gargalo só porque o sistema cresceu. A constante não é função de .
Com 4 servidores, cada um atende no máximo buscas por segundo, fixo. Com 40 servidores, cada um ainda tem teto — não . Um despachante único que recebe todas as buscas viola o critério: a carga nele cresce com . Particionar o catálogo por faixa de título, cada nó só a sua fatia, respeita a constante independente de .
Nada disso restaura um relógio comum. Os modelos síncrono e assíncrono dizem o que se pode assumir sobre tempo.
Sem medida de tempo global
Dois modelos classificam o que o algoritmo pode supor sobre tempo.
No modelo síncrono há medida de tempo global e prazos: existe um teto conhecido para atraso de mensagem e para a diferença entre relógios. Um silêncio além de conta como queda.
No modelo assíncrono não há relógio global nem prazos: não existe medida de tempo global. Mensagens podem atrasar sem teto. Silêncio pode ser queda ou só lentidão; o modelo não distingue os dois por um relógio comum.
A comunicação, nos dois modelos, continua sendo por mensagens. O que muda é o que se pode assumir sobre relógio e atraso.
Dois nós do catálogo trocam buscar. No síncrono, se a resposta não chega em milissegundos, o remetente trata o destino como fora. No assíncrono, o mesmo silêncio não autoriza essa conclusão: não há e não há medida de tempo global com a qual carimbar os dois lados. Sem essa medida, a ordem entre eventos não vem de um relógio compartilhado.
Relação acontece-antes
Não há relógio global compartilhado. Cada nó tem um relógio local, sujeito a desvio. Para falar de ordem entre eventos usa-se a relação acontece-antes, escrita , com três axiomas:
- Se e estão no mesmo processo e ocorre antes de , então .
- Se é o envio de uma mensagem e é o recebimento dessa mesma mensagem, então .
- A relação é transitiva: se e , então .
Sem relógio compartilhado, a única ordem em que se pode confiar é a que o próprio processo observa na sua linha e a que uma mensagem impõe (o envio antecede aquele recebimento). A transitividade fecha a cadeia: o que a linha local ordena e o que a mensagem ordena passam a uma só relação.
Sem desenhar eixos, em sequência: o processo envia a mensagem (evento ). O processo recebe (evento ) e, na sequência, grava um log (evento ).
- pelo axioma 2 (envio daquela antecede o recebimento dela).
- pelo axioma 1 (no mesmo , o recebimento vem antes do log).
- Logo pelo axioma 3.
Um evento noutro processo que nunca trocou mensagem com nem com não tem nem o contrário: e são concorrentes. Concorrente aqui significa que a relação não os ordena. Dois eventos podem aparecer com o mesmo instante no relógio e ainda ser concorrentes.
Os relógios locais de e de podem até mostrar o mesmo número; isso não cria .
Relógios lógicos e o diagrama espaço-tempo que ordenam esses eventos ficam na coordenação de processos. Esta página só fixa os três axiomas.
Em Resumo
Sistema distribuído: nós independentes, só mensagens, aparência de um sistema só; falhas podem ser parciais. Sem relógio global.
Transparência oculta um aspecto da distribuição; acesso, localização, replicação, concorrência, migração, falha, desempenho, relocação e transação nomeiam aspectos distintos.
Relocação esconde movimento durante um acesso em curso; migração esconde que o recurso mudou de máquina. Transação esconde a coordenação de operações em nós distintos como unidade atômica (não é sobre cópias).
Replicação esconde cópias; desempenho esconde variação de carga (o cliente segue aceitável numa faixa). São fatos distintos.
Tolerância a falhas: continuar útil sob problema, com degradação aceitável de desempenho e/ou funções. Escalabilidade: carga em cada máquina limitada por constante independente de .
Modelo síncrono: há medida de tempo global e prazos (). Modelo assíncrono: sem relógio global nem prazos — não há medida de tempo global.
Acontece-antes: mesma linha de processo; envio precede o recebimento daquela mensagem; transitividade. Sem relógio global nesta página.