Prévia do material em texto
7
CONSISTÊNCIA E REPLICAÇÃO
Uma questão importante em sistemas distribuídos é a replicação de dados. Os dados geralmente são replicados para 
aumentar a confiabilidade ou melhorar o desempenho. Um dos principais problemas é manter as réplicas consistentes. 
Informalmente, isso significa que quando uma cópia é atualizada, precisamos garantir que as outras cópias também 
sejam atualizadas; caso contrário, as réplicas deixarão de ser as mesmas. Neste capítulo, examinaremos mais de perto 
o que realmente significa consistência de dados replicados e as diferentes maneiras de obter essa consistência.
Começamos com uma introdução geral que explica por que a replicação é útil e como ela se relaciona com a 
escalabilidade. Em seguida, continuamos com o que realmente significa consistência. Uma classe importante do que 
conhecemos como modelos de consistência pressupõe que vários processos acessem dados compartilhados 
simultaneamente. Nessas situações, a consistência pode ser formulada em relação ao que os processos podem esperar ao 
ler e atualizar os dados compartilhados, sabendo que outros processos estão acessando esses dados também.
Modelos de consistência para dados compartilhados geralmente são difíceis de implementar em sistemas 
distribuídos de grande escala. Além disso, em muitos casos é possível usar modelos mais simples, mas também mais 
fáceis de implementar. Uma classe específica é composta de modelos de consistência centrados no cliente, que se 
concentram na consistência da perspectiva de um único cliente (possivelmente móvel). Em uma seção separada, 
explicaremos os modelos de consistência centrados no cliente.
A consistência é apenas metade da história. Devemos também considerar como ele é implementado. Existem 
basicamente duas questões, mais ou menos independentes, que devemos ter
273
274 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
presente. Em primeiro lugar, começaremos nos concentrando no gerenciamento de espelho, que leva em consideração não 
apenas a localização dos servidores espelho, mas também como o conteúdo é distribuído para esses servidores.
O segundo problema é como as réplicas permanecem consistentes. Na maioria dos casos, os aplicativos 
exigem uma forma forte de consistência. Informalmente, isso significa que as atualizações se espalharão mais ou 
menos imediatamente entre as réplicas. Existem várias alternativas para implementar consistência forte, que 
explicaremos em uma seção separada. Também veremos protocolos de cache, que constituem um caso especial de 
protocolos de consistência.
7.1 INTRODUÇÃO
Nesta seção, começamos explicando os motivos importantes para desejar a replicação de dados. Nós nos 
concentramos na replicação como uma técnica útil para alcançar escalabilidade e entender por que raciocinar 
sobre consistência é tão importante.
7.1.1 Razões para replicação
Existem dois motivos principais para replicar dados: confiabilidade e desempenho. Primeiro, os dados são replicados para 
aumentar a confiabilidade de um sistema. Se um sistema de arquivos foi replicado, é possível continuar trabalhando depois 
que uma réplica falhar, simplesmente alternando para uma das outras réplicas. Além disso, manter várias cópias torna 
possível fornecer melhor proteção contra dados corrompidos. Por exemplo, suponha que haja três cópias de um arquivo e 
cada operação de leitura e gravação seja executada em cada cópia. Podemos nos proteger contra uma operação de 
gravação defeituosa, se considerarmos que o valor retornado por pelo menos duas cópias está correto.
O outro motivo para replicar dados é o desempenho. A replicação é importante para o desempenho quando o sistema 
distribuído precisa ser dimensionado em números e área geográfica. Por exemplo, a escala em números ocorre quando um 
número crescente de processos precisa acessar dados que são gerenciados por um único servidor. Nesse caso, o 
desempenho pode ser melhorado replicando o servidor e subsequentemente dividindo o trabalho.
O dimensionamento em relação ao tamanho de uma área geográfica também pode exigir replicação. A ideia básica é 
que, ao colocar uma cópia dos dados bem próxima ao processo que os usa, o tempo de acesso aos dados diminui. 
Conseqüentemente, o desempenho percebido desse processo aumenta. Este exemplo também mostra que pode ser difícil 
avaliar os benefícios de desempenho da replicação. Embora um processo do cliente possa perceber um melhor 
desempenho, também pode ser o caso de que mais largura de banda da rede seja consumida para manter todas as 
réplicas atualizadas.
SEÇÃO 7.1 INTRODUÇÃO 275
Se a replicação ajudar a melhorar a confiabilidade e o desempenho, quem será contra ela? Infelizmente, há um 
preço a pagar quando os dados são replicados. O problema com a replicação é que ter muitas cópias pode causar 
problemas de consistência. Sempre que uma cópia é modificada, ela se torna diferente das outras cópias. Portanto, 
para garantir a consistência, modificações devem ser feitas em todas as cópias. O preço da replicação é determinado 
exatamente por quando e como essas modificações devem ser feitas.
Para entender o problema, considere melhorar os tempos de acesso à página da web. Se nenhuma medida especial for 
tomada, às vezes a solicitação de uma página de um servidor da Web remoto pode levar vários segundos. Para melhorar o 
desempenho, os navegadores da web armazenam uma cópia de uma página solicitada anteriormente localmente (ou seja, eles 
procuram uma página da Web). Se um usuário exigir essa página novamente, o navegador retornará automaticamente a 
cópia local. O tempo de acesso percebido pelo usuário é excelente. No entanto, se o usuário sempre deseja a versão mais 
recente de uma página, ele pode estar sem sorte. O problema é que se a página foi modificada nesse ínterim, as 
modificações não serão propagadas para as cópias em cache, o que tornará essas cópias desatualizadas.
Uma solução para o problema de devolver uma cópia antiga ao usuário é, primeiro, proibir o navegador de 
manter cópias locais e deixar que o servidor cuide totalmente da replicação. No entanto, essa solução pode causar 
tempos de acesso ruins se uma réplica não for colocada perto do usuário. Outra solução é deixar o servidor da web 
invalidar ou atualizar cada cópia em cache, mas isso requer que o servidor controle todos os caches e envie 
mensagens para eles. Isso, por sua vez, pode degradar todo o desempenho do servidor. Voltaremos aos problemas 
de desempenho mais tarde versus escalabilidade.
7.1.2 Replicação como uma técnica de escalonamento
A replicação e o armazenamento em cache para desempenho são amplamente usados como técnicas de dimensionamento. 
Os problemas de escalabilidade geralmente aparecem na forma de problemas de desempenho. Colocar cópias de dados perto 
dos processos que os utilizam pode melhorar o desempenho, reduzindo o tempo de acesso, resolvendo problemas de 
escalabilidade.
Uma compensação necessária é que manter as cópias atualizadas requer uma largura de banda de rede 
maior. Considere um processo P que acessa um espelho local N vezes por segundo, enquanto a réplica é atualizada 
M vezes por segundo. Suponha que uma atualização atualize completamente a versão anterior do espelho local. 
sim N << M, ou seja, a velocidade de acesso à atualização é muito baixa, situação ocorre em que o processo P Ele 
nunca acessa muitas versões atualizadas do espelho local, o que torna a comunicação de rede inútil para essas 
versões. Neste caso, pode ter sido melhor não instalar um espelho local próximo P, ou aplique uma estratégia 
diferente para atualizar a réplica. Voltaremos a essas questões mais tarde.
No entanto, um problema ainda mais sério é que manter várias cópias consistentes pode, por si só, estar 
sujeito a sérios problemas de escalabilidade. Por intuição, uma coleção de
276 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
cópias é consistente quando as cópias são sempre as mesmas. Isso significa que uma operação de leiturarealizada em 
qualquer cópia sempre retornará o mesmo resultado. Conseqüentemente, quando uma operação de atualização é executada 
em uma cópia, a atualização deve ser propagada para todas as cópias antes que uma operação subsequente ocorra, 
independentemente de em qual cópia a operação foi iniciada ou executada.
Este tipo de consistência é às vezes informalmente (e imprecisamente) chamado de consistência hermética, como 
no caso da chamada replicação síncrona. (Na próxima seção, daremos definições precisas de consistência e 
apresentaremos uma variedade de modelos de consistência.) A ideia principal é que uma atualização seja realizada em 
todas as cópias como uma única operação atômica ou transação. Infelizmente, a implementação de atomicidade 
envolvendo um grande número de réplicas, que podem ser amplamente dispersas em uma rede de grande escala, é 
inerentemente difícil quando as operações precisam ser concluídas rapidamente.
As dificuldades surgem do fato de que precisamos sincronizar todas as réplicas. Em essência, isso significa que 
todos os espelhos precisam primeiro concordar exatamente quando uma atualização local ocorrerá. Por exemplo, as 
réplicas podem precisar decidir uma ordem global de operações, usando carimbos de data / hora Lamport ou deixar que 
um coordenador atribua o pedido. A sincronização global simplesmente requer muito tempo de comunicação, 
especialmente quando as réplicas estão espalhadas por uma rede de longa distância.
Agora enfrentamos um dilema. Por um lado, os problemas de escalabilidade podem ser reduzidos aplicando 
replicação e armazenamento em cache, o que resulta em melhor desempenho. Por outro lado, manter todas as cópias 
consistentes geralmente requer sincronização global e isso é inerentemente caro em termos de desempenho. A cura pode 
ser pior do que a doença.
Em muitos casos, a única solução real é reduzir as restrições de consistência. Em outras palavras, se pudermos 
relaxar o requisito de que as atualizações precisam ser executadas como operações atômicas, talvez possamos evitar 
sincronizações globais (instantâneos) e talvez também aumentar o desempenho. O preço a pagar é que as cópias 
podem não ser as mesmas em todos os lugares. Obviamente, até que ponto relaxar a consistência depende muito dos 
padrões de acesso e atualização dos dados replicados, bem como da finalidade de usar esses dados.
Nas seções a seguir, primeiro consideramos uma variedade de modelos de consistência e fornecemos 
definições precisas do que realmente significa consistência. Em seguida, continuamos com uma explicação das 
diferentes maneiras de implementar esses modelos, por meio do que é conhecido como protocolos de distribuição e 
consistência. Diferentes métodos para classificar consistência e replicação podem ser encontrados em Gray et al. 
(1996) e em Wiesmann et al. (2000).
7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM 
DADOS
Tradicionalmente, a consistência é explicada no contexto de operações de leitura e gravação em dados compartilhados, 
disponíveis por meio da memória compartilhada (distribuída), um banco de dados compartilhado (distribuído) ou um 
sistema de arquivos (distribuído). Nesta seção, usamos
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 277
Usamos o termo mais amplo chamado Armazem de dados. Um data warehouse pode ser fisicamente distribuído em várias 
máquinas. Em particular, presume-se que qualquer processo que possa acessar os dados do warehouse tenha uma cópia 
local (ou próxima) disponível de todo o warehouse. As operações de gravação se propagam para as outras cópias, conforme 
mostrado na Figura 7-1. Uma operação de dados é classificada como uma operação de gravação quando altera os dados, 
caso contrário, é classificada como uma operação de leitura.
Processo
Processo Processo
Cópia local
Armazém de dados distribuído
Figura 7-1. Organização geral de um data warehouse lógico, fisicamente distribuído e replicado 
por meio de múltiplos processos.
UMA modelo de consistência é basicamente um contrato entre os processos e o data warehouse. Este contrato diz 
que se os processos concordarem em obedecer a certas regras, o warehouse promete funcionar corretamente. Em geral, 
um processo que executa uma operação de leitura em um item de dados espera que a operação retorne um valor que 
mostra os resultados da última operação de gravação nos dados.
Na ausência de um relógio global, é difícil definir precisamente qual é a última operação de gravação. Como 
alternativa, precisamos fornecer outras definições, o que nos leva a uma variedade de modelos de consistência. Cada 
modelo restringe efetivamente os valores que uma operação de leitura pode retornar em um item de dados. Como 
você pode esperar, os modelos com mais restrições são mais fáceis de usar, por exemplo, ao desenvolver aplicativos, 
enquanto aqueles com menos restrições são mais difíceis. A desvantagem é, claro, que os modelos fáceis de usar não 
têm um desempenho tão bom quanto os mais difíceis. Assim é a vida.
7.2.1 Consistência contínua
Pelo que explicamos até agora, deve ficar claro que não há nada que possa ser considerado a melhor solução para 
replicar dados. A replicação de dados tem problemas de consistência que não podem ser resolvidos com eficiência de 
uma maneira geral. Somente se relaxarmos a consistência, podemos esperar encontrar soluções eficientes. Infelizmente, 
também não existem regras gerais para afrouxar a consistência: exatamente o que pode ser tolerado depende, em 
grande parte, das aplicações.
278 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
Existem diferentes maneiras de os aplicativos especificarem as inconsistências que podem tolerar. Yu e Vahdat 
(2002) consideram um método geral para diferenciar três eixos independentes para definir inconsistências: desvio nos 
valores numéricos entre as réplicas, desvio na deterioração entre as réplicas e desvio no que diz respeito à ordem das 
operações de atualização. Yu e Vahdat referem-se a esses desvios como intervalos de consistência contínua.
A medição da inconsistência em termos de desvios numéricos pode ser usada em aplicativos para os 
quais os dados têm semântica numérica. Um exemplo óbvio é a replicação de registros contendo preços de 
ações. Nesse caso, um aplicativo pode especificar que duas cópias não devem desviar mais de $ 0,02, o que 
seria um desvio numérico absoluto. Alternativamente, um desvio numérico relativo, que afirma que duas cópias 
não devem diferir mais do que, digamos, 0,5%. Em ambos os casos, veríamos que se um estoque subir (e uma 
das réplicas for atualizada imediatamente) sem violar os desvios numéricos especificados, as réplicas ainda 
serão consideradas mutuamente consistentes.
O desvio numérico também pode ser entendido em termos do número de atualizações que foram aplicadas a uma 
determinada réplica, mas ainda não foram vistas por outras réplicas. Por exemplo, um cache da web pode não ter visto 
um lote de operações realizadas por um servidor da web. Neste caso, o desvio associado ao valor também conhecido 
como su pesagem.
Desvios antigos estão relacionados à última vez em que uma réplica foi atualizada. Para alguns aplicativos, é 
tolerável que um espelho forneça dados antigos, desde que não seja
também velho. Por exemplo, os relatórios meteorológicos costumam permanecer razoavelmente precisos por algum 
tempo, digamos algumas horas. Nesses casos, um servidor primário pode receber atualizações oportunas, mas decidir 
propagar as atualizações para as réplicas de tempos em tempos.
Por último, existem classes de aplicativos em que a ordem das atualizações pode ser diferente em várias 
réplicas, desde que as diferenças sejam limitadas. Uma maneira de visualizar essas atualizações é aplicá-las 
provisoriamente a uma cópia local, dependendo do acordo global de todas as réplicas. Consequentemente, algumas 
atualizações precisarão ser repetidas e aplicadas em uma ordem diferente antes de se tornarem permanentes.Por 
intuição, a ordenação dos desvios é muito mais difícil de entender do que as outras duas métricas de consistência. 
Posteriormente, forneceremos exemplos que esclarecerão as coisas.
A ideia de um conito
Para definir inconsistências, Yu e Vahdat apresentaram uma unidade de consistência, abreviada como
conit. Um conit especifica a unidade pela qual a consistência será medida. Assim, em nosso exemplo de bolsa de valores, um 
conito poderia ser definido como um registro que representa uma única ação. Outro exemplo é um boletim meteorológico 
individual.
Para dar um exemplo de um conito e, ao mesmo tempo, ilustrar os desvios numéricos e de ordenação, considere 
as duas réplicas mostradas na Figura 7-2. Cada réplica Eu mantém um
relógio vetorial bidimensional, VC Eu, como os relógios descritos no Capítulo 6. Usamos a notação t, eu para expressar uma 
operação que foi realizada pela réplica Eu no (seu) tempo lógico t.
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 279
Réplica A
Conit
x = 6; y = 3
Réplica B
Conit
x = 2; y = 5
Operação Resultado Operação Resultado
<5, B> x: = x + 2 <8, A> 
y: = y + 2 <12, A> y: = y 
+ 1 <14, A> x: = y * 2
[x = 2]
[y = 2]
[y = 3]
[X = 6]
<5, B> X: = X + 2 <10, 
B> y: = y + 5
[x = 2]
[y = 5]
Vector Clock A
Desvio da ordem = 3 Desvio 
numérico = (1, 5)
= (15, 5) Vector Clock B
Desvio da ordem = 2 Desvio 
numérico = (3, 6)
= (0, 11)
Figura 7-2. Exemplo de como rastrear desvios de consistência [adaptado de (Yu e Vahdat, 
2002)].
Neste exemplo, vemos duas réplicas que operam em um conit que contém os elementos de dados x Y Y. Assumimos 
que ambas as variáveis foram inicializadas com 0. A replicação A recebeu a operação
5, B: x ← x + 2
da réplica B, e o tornou permanente (ou seja, a operação foi confirmada em PARA e não pode ser desfeito). A réplica PARA tem 
três operações de atualização provisória: 8, PARA, 12, PARA, e 14, PARA,
o que leva ao seu desvio de ordem para 3. Observe também que, devido à última operação, o relógio vetorial 
de 14, A, A torna-se (15,5).
A única operação de B o que PARA ainda não viu é 10, B, levando seu desvio numérico a 1 em relação às operações. 
Neste exemplo, o peso deste desvio pode ser expresso como a diferença máxima entre os valores (confirmados) de x Y Y no 
PARA, e o resultado das operações em B não visto por PARA. O valor confirmado em PARA isto é ( x, y) = ( 2.0), 
enquanto a operação em B, não visto por PARA, joga uma diferença de y = 5. Raciocínio semelhante mostra que B tem 
duas operações de atualização provisória: 5, B
e 10, B, o que significa que ele tem um tipo de desvio de 2. Porque B você ainda não viu uma única operação de 
PARA, seu relógio vetorial torna-se (0,11). O desvio numérico é 3 com um peso total de 6. Este último valor 
vem do fato de que o valor confirmado de B
isto é ( x, y) = ( 0,0), enquanto as operações provisórias em PARA eles já vão levar 6 em x.
Observe que há compensações entre manter os conitos de granulação fina e os conitos de granulação grossa. Se 
um conit representar muitos dados, como um banco de dados inteiro, as atualizações se aplicam a todos os dados 
contidos no conit. Conseqüentemente, isso pode fazer com que as réplicas entrem em um estado de inconsistência mais 
rapidamente. Por exemplo, suponha
280 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
que na Figura 7-3 duas réplicas podem diferir em não mais do que uma atualização pendente. Nesse caso, quando 
cada um dos itens de dados na Figura 7-3 (a) tiver sido atualizado uma vez na primeira réplica, a segunda réplica 
também precisará ser atualizada. Este não é o caso quando um conito menor é escolhido, como mostra a Figura 7-3 
(b). Lá, as réplicas ainda são consideradas atualizadas. Em particular, este problema é importante quando os 
elementos de dados contidos em um conit são usados de forma completamente independente, caso em que diz
o que compartilhar falsamente o conit.
Conit Elemento de dados
Melhoria
Propagação
de
atualizações
Melhoria
Adiamento
da
propagação do
atualizações
Melhoria Melhoria
Réplica 1 Réplica 2 Réplica 1 Réplica 2
(para) (b)
Figura 7-3. Escolher a granularidade certa para um conito. (a) Duas atualizações levam à 
disseminação de atualizações. (b) Nenhuma atualização é necessária (ainda).
Infelizmente, implementar conits muito pequenos não é uma boa ideia, pelo simples motivo de que o número total de conits 
que precisam ser tratados também aumenta. Em outras palavras, existe uma sobrecarga relacionada ao tratamento de conitos que 
deve ser levada em consideração. Essa sobrecarga, por sua vez, pode afetar adversamente todo o desempenho, o que deve ser 
levado em consideração.
Embora de um ponto de vista conceitual os conits constituam um meio atraente de capturar os requisitos de 
consistência, há dois pontos importantes que devemos abordar antes de colocá-los em prática. Primeiro, para reforçar 
a consistência, precisamos de protocolos. Explicaremos esses protocolos posteriormente neste capítulo.
Um segundo ponto é que os desenvolvedores de programas devem especificar os requisitos de consistência 
necessários para seus aplicativos. A prática indica que a obtenção de tais requisitos pode ser extremamente difícil. 
Normalmente, os programadores não estão acostumados a lidar com replicação, deixando de fora o que significa 
fornecer informações detalhadas sobre consistência. Portanto, é muito importante que existam interfaces de 
programação simples e fáceis de entender.
A consistência contínua pode ser implementada como um conjunto de ferramentas que aparece para os 
desenvolvedores apenas como outra biblioteca para vincular a seus aplicativos. Um conit é simplesmente declarado 
próximo a uma atualização de item de dados. Por exemplo, o trecho de pseudo-código
AffectConit (ConitQ, 1, 1);
adicione a mensagem m à fila Q;
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 281
definido para adicionar uma mensagem à fila Q pertence a um conit denominado "ConitQ". Além disso, as operações 
agora podem ser declaradas dependentes de conits:
DependsOnTheConit (ConitQ, 4, 0, 60);
lê a mensagem m do chefe da fila Q;
Neste caso, a chamada para DependsOfLaConit () especifica que o desvio numérico, o desvio de classificação e o desvio 
antigo devem ser limitados aos valores 4, 0 e 60 (segundos), respectivamente. Isso pode ser interpretado como que deve 
haver no máximo 4 operações de atualização não vistas em outras réplicas, que não deve haver nenhuma tentativa de 
atualização local e que a idade da cópia local de Q ele deve ter sido verificado há não mais de 60 segundos. Se esses 
requisitos não forem satisfeitos, o middleware subjacente tentará transportar a cópia local do Q a um estado tal que a 
operação de leitura possa ser realizada.
7.2.2 Ordenação consistente de operações
Além da consistência contínua, desde a última década, tem havido um grande corpo de trabalho dedicado a modelos de 
consistência centrados em dados. Uma classe importante de modelos vem do campo da programação simultânea. 
Diante do fato de que na computação paralela e distribuída, vários processos precisarão compartilhar recursos e 
acessá-los simultaneamente, os pesquisadores têm buscado expressar a semântica do acesso concorrente quando 
recursos compartilhados são replicados. Isso levou a pelo menos um modelo de consistência importante que é 
amplamente usado. Agora vamos nos concentrar no que é conhecido como consistência sequencial e também 
explicaremos uma variante mais fraca, chamada consistência causal.
Os modelos que discutimos nesta seção lidam com operações de ordenação consistentes em dados 
compartilhados e replicados. Em princípio, os modelos superam aqueles de consistência contínua no sentido de que, 
quando for necessário comprometer atualizações nas réplicas, eles terão que concordar em uma ordem global dessas 
atualizações. Em outras palavras, eles precisam concordar em uma ordenação consistente dessas atualizações.Os 
modelos de consistência que explicaremos a seguir tratam de como obter classificações consistentes.
Consistência sequencial
A seguir, usaremos uma notação especial na qual traçaremos as operações de um processo ao longo de um eixo de 
tempo. O eixo do tempo é sempre desenhado horizontalmente, aumentando da esquerda para a direita. Os símbolos
W Eu ( para Y R Eu ( x) b
significa que o processo foi escrito respectivamente P Eu sobre o elemento de
dados x com o valor para e uma leitura desse elemento por P Eu devolvendo b. Assumimos que cada item de dados é 
inicialmente NADA. Quando não há confusão sobre qual processo é
acessar os dados, omitimos o subscrito dos símbolos W Y R.
282 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
Q1:
P2:
W (x) a
R (x) NIL R (x) a
Figura 7-4. Comportamento de dois processos operando no mesmo elemento de dados. O 
eixo horizontal representa o tempo.
Como exemplo, na Figura 7-4 P 1 executa uma gravação no elemento de dados x, modificando seu valor para para. Observe 
que, em princípio, esta operação, W 1 ( para, é feito primeiro em uma cópia do armazenamento de dados que é local para P 1, e 
então se espalha para outras cópias locais. Em nosso exemplo, P 2 leia o valor mais tarde NADA, e algum tempo depois li para ( de 
sua cópia local
do armazém). O que vemos aqui é que leva algum tempo para propagar a atualização do x em direção a P 2,
o que é perfeitamente aceitável.
o consistência sequencial é um importante modelo de consistência centrado em dados, que foi definido pela 
primeira vez por Lamport (1979) no contexto de memória compartilhada para sistemas multiprocessadores. Em geral, 
um armazenamento de dados é sequencialmente consistente quando satisfaz a seguinte condição:
O resultado de qualquer execução é o mesmo como se as operações (leitura e gravação) de todos os processos 
realizados no armazenamento de dados fossem executados em alguma ordem sequencial e as operações de cada 
processo individual aparecessem nessa sequência na ordem especificada por seu programa.
O que esta definição significa é que quando os processos estão sendo executados simultaneamente em (talvez) máquinas 
diferentes, qualquer interpolação válida de operações de leitura e gravação é um comportamento aceitável, mas todos os 
processos veem a mesma interpolação de operações.
Observe que nada é dito sobre o tempo; ou seja, não há referência à operação de gravação "mais recente" no item de 
dados. Observe que, neste contexto, um processo "vê" gravações de todos os processos, mas vê apenas suas 
próprias leituras.
Esse tempo não desempenha um papel importante, pode ser visto na Figura 7-5. Vamos considerar quatro
processos operando no mesmo elemento de dados x. Na Figura 7-5 (a), o processo P 1 primeiro desempenho W (x) a para x. Depois 
(em tempo absoluto), o processo P 2 também executa uma operação de gravação, definindo o valor de x para b. No entanto, os 
processos P 3 Y P 4 Primeiro eles lêem o valor b, e então o valor para. Em outras palavras, a operação de gravação do processo P 2 Parece 
ser
aconteceu antes de P 1
Em contraste, a Figura 7-5 (b) viola a consistência sequencial, uma vez que nem todos os processos veem
a mesma interpolação de operações de gravação. Em particular, para o processo P 3, parece
se o elemento de dados foi alterado primeiro para b, e então para para. Por outro lado, P 4 concluir que o valor final é b.
Para especificar ainda mais a ideia de consistência sequencial, vamos considerar os três processos, P 1, P 2,
Y P 3, na execução simultânea, mostrado na Figura 7-6 (Dubois et al., 1988). Os itens de dados neste exemplo são 
constituídos por três variáveis inteiras x, y, Y z, e eles são salvos
em um armazenamento de dados compartilhado sequencialmente consistente (possivelmente distribuído).
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 283
P1: W (x) a
P2:
Q3:
Q4:
P1: W (x) a
P2:
Q3:
Q4:
W (x) b
W (x) b
R (x) b R (x) a
R (x) b R (x) a
R (x) b R (x) a
R (x) a R (x) b
(para) (b)
Figura 7-5. ( a) Armazenamento de dados sequencialmente consistente. (b) Armazenamento de dados que não 
são sequencialmente consistentes.
Processo 1 Processo 2 Processo 3
x ← 1;
imprimir (y, z)
Y ← 1;
imprimir (x, z)
z ← 1;
imprimir (x, y)
Figura 7-6. Três processos em execução simultaneamente.
Assumimos que cada variável é inicializada com 0. Neste exemplo, uma atribuição corresponde a uma operação de 
gravação, enquanto uma instrução de impressão corresponde a uma operação de leitura simultânea de seus dois 
argumentos. Assumimos que todas as instruções são indivisíveis.
Várias sequências de execução interpoladas são possíveis. Com seis instruções independentes, existem 
potencialmente 720 (6!) Sequências de execução possíveis, embora algumas violem a ordem do programa. Vamos 
considerar as 120 (5!) Sequências que começam com x ← 1. Metade tem imprimir (x, z) antes que Y ← 1 e viola a ordem do 
programa. Metade também tem imprimir (x, y) antes que z ← 1, e também violam a ordem do programa. Apenas um quarto das 
120 sequências, ou
30, são válidos. Outras 30 sequências válidas são possíveis começando com Y ← 1 e mais 30 podem começar com z ← 1, 
para um total de 90 sequências de execução válidas. Quatro deles aparecem na Figura 7-7.
Na Figura 7-7 (a), os três processos estão em ordem de execução, primeiro P 1, então P 2, e des-
bem P 3 - Os outros três exemplos mostram interpolações diferentes, mas igualmente válidas, das instruções no 
tempo. Cada um dos três processos imprime duas variáveis. Devido a que
os únicos valores que cada variável pode assumir são o valor inicial (0) ou o valor atribuído (1), cada processo produz 
uma string de 2 bits. Números depois Impressões eles são as saídas reais que aparecem no dispositivo de saída.
Se concatenarmos a saída de P 1, P 2, Y P 3 Nessa ordem, obtemos uma string de 6 bits que caracteriza uma determinada 
interpolação de instruções. Esta string é aquela listada como Empresa no
Figura 7-7. Posteriormente caracterizaremos cada pedido por meio de sua assinatura, ao invés de sua impressão.
Nem todos os 64 padrões de assinatura são permitidos. Como um exemplo trivial, 000000 não é permitido, pois 
significaria que as instruções de impressão executam antes das instruções de atribuição, o que viola o requisito de que 
as instruções sejam executadas na ordem do programa. Um exemplo mais sutil é 001001. Os primeiros dois bits, 00, 
significam que Y Y z eles eram 0
284 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
x ← 1;
imprimir (y, z);
Y ← 1;
imprimir (x, z);
z ← 1;
imprimir (x, y)
x ← 1;
Y ← 1;
imprimir (x, z);
imprimir (y, z);
z ← 1;
imprimir (x, y)
Y ← 1;
z ← 1;
imprimir (x, y);
imprimir (x, z);
x ← 1;
imprimir (y, z)
Y ← 1;
x ← 1;
z ← 1;
imprimir (x, z);
imprimir (y, z);
imprimir (x, y);
Empresa:
Impressões: 001011
001011 Empresa:
Impressões: 101011
101011 Empresa:
Impressões: 110101
010111 Empresa:
Impressões: 111111
111111
(para) (b) (c) (d)
Figura 7-7. Quatro sequências válidas de execução para os processos da Figura 7-6. O eixo 
vertical representa o tempo.
quando P 1 deixou sua impressão. Esta situação só ocorre quando P 1 execute ambas as instruções antes de começarem 
P 2 ou P 3 - Os próximos dois bits, 10, significam que P 2 deve ser executado depois P 1 começou, mas antes P 3 começou. 
Os últimos dois bits, 01, significam que
P 3 deve ser completado antes P 1 começar, mas já vimos isso P 1 deve ir primeiro. Portanto, 001001 não é permitido.
Em resumo, as 90 ordens válidas diferentes produzem uma variedade de resultados de programa diferentes 
(embora menos de 64) que são permitidos sob a suposição de consistência sequencial. O contrato entre os processos 
e o data warehouse compartilhado e distribuído é que o processo deve aceitar todos esses resultados como válidos. 
Em outras palavras, os processos devem aceitar os quatro resultados mostrados na Figura 7-7 e todos os outros 
resultados válidos comorespostas apropriadas e devem funcionar corretamente se algum deles ocorrer. Um programa 
que funciona com alguns desses resultados e outros não viola o contrato do data warehouse e está incorreto.
Consistência causal
O tipo de consistência causal Hutto e Ahamad, 1990) representa uma fraqueza da consistência sequencial, uma vez que 
diferencia entre eventos que são potencialmente relacionados por causalidade e aqueles que não o são. No capítulo 
anterior, quando explicamos os registros de tempo vetorial, já tratamos da causalidade. Se o evento b é causado ou 
influenciado por um evento anterior para, causalidade requer que todos os outros eventos olhem primeiro para para, e então 
para b.
Considere uma interação simples usando um banco de dados distribuído compartilhado. Suponha
que o processo P 1 escrever um item de dados x. Depois de P 2 ler para x e escreve Y. Aqui, lendo x e a escrita de Y estão 
potencialmente relacionados por causalidade, uma vez que o cálculo de Y
pode ter dependido do valor de x quando P 2 leia-o (isto é, o valor escrito por P 1).
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 285
Por outro lado, se dois processos escrevem espontânea e simultaneamente dois itens de dados diferentes, eles não 
estão causalmente relacionados. Operações que não são causalmente relacionadas são consideradas concorrente.
Para que um data warehouse seja considerado causalmente consistente, ele deve obedecer à seguinte 
condição:
Os escritos que estão potencialmente relacionados por causalidade devem ser vistos por todos os processos na 
mesma ordem. As gravações simultâneas podem ser visualizadas em uma ordem diferente em máquinas diferentes.
Como exemplo de consistência causal, considere a Figura 7-8. Aqui temos uma sequência de eventos que é permitida com 
um armazenamento causalmente consistente, mas é proibida com um armazenamento sequencialmente consistente ou com 
um armazenamento estritamente consistente. Ponto a
nota é que as escrituras W 2 ( x) b Y W 1 ( x) c eles são simultâneos, portanto, não é necessário que todos os processos os vejam na 
mesma ordem.
P1: W (x) a
P2:
Q3:
Q4:
W (x) c
R (x) a W (x) b
R (x) a
R (x) a
R (x) c
R (x) b
R (x) b
R (x) c
Figura 7-8. Essa sequência é permitida com um armazenamento causalmente consistente, mas não com 
um armazenamento sequencialmente consistente.
Agora vamos considerar um segundo exemplo. Na Figura 7-9 (a), temos W 2 ( x) b potencialmente dependente de W 1 ( para, 
já que b pode ser o resultado de um cálculo envolvendo o valor lido
por R 2 ( para. Os dois escritos estão causalmente relacionados, portanto, todos os processos devem vê-los na mesma ordem. 
Portanto, a Figura 7-9 (a) está incorreta. Por outro lado, na Figura 7-9 (b)
a leitura foi removida, então W 1 ( para Y W 2 ( x) b eles agora são gravações simultâneas. Um armazenamento causalmente 
consistente não requer gravações simultâneas ordenadas globalmente, então
que a Figura 7-9 (b) está correta. Observe que a Figura 7-9 (b) reflete uma situação que não seria aceitável para um warehouse 
sequencialmente consistente.
P1: W (x) a
P2:
Q3:
Q4:
P1: W (x) a
P2:
Q3:
Q4:
R (x) a W (x) b
W (x) b
R (x) b R (x) a
R (x) a R (x) b
R (x) b R (x) a
R (x) a R (x) b
(para) (b)
Figura 7-9. ( a) Violação de um warehouse causalmente consistente. (b) Sequência correta de eventos em 
um armazenamento causalmente consistente.
A implementação de consistência causal requer o rastreamento de quais processos viram quais gravações. Com efeito, 
isso significa que um gráfico da dependência deve ser construído e mantido
286 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
qual operação depende de quais outras operações. Uma maneira de fazer isso é usando um registrador vetorial de tempo, 
conforme explicamos no capítulo anterior. Posteriormente neste capítulo, retornaremos ao uso de registros de tempo vetorial 
para capturar a causalidade.
Operações de agrupamento
A consistência sequencial e causal são definidas no nível das operações de leitura e gravação. Esse nível de granularidade se 
deve a razões históricas: esses modelos foram inicialmente desenvolvidos para sistemas multiprocessadores de memória 
compartilhada e, na verdade, foram implementados no nível do hardware.
A granularidade fina desses modelos de consistência não coincide em muitos casos com a granularidade fornecida 
pelos aplicativos. O que vemos é que a concorrência entre programas que compartilham dados geralmente é mantida sob 
controle por meio de mecanismos de sincronização para exclusão mútua e transações. Na verdade, acontece que no nível 
do programa, as operações de leitura e gravação são colocadas entre colchetes por meio do par de operações ENTER_CS Y
DEIXE CS, Onde " CS ”Significa seção crítica. Como explicamos no Capítulo 6, a sincronização entre os 
processos é realizada por essas duas operações. Em termos de nosso data warehouse distribuído, isso 
significa que um processo que foi executado com sucesso
ENTER_CS você terá certeza de que os dados em seu warehouse local estão atualizados. Nesse ponto, o processo 
pode executar com segurança uma série de operações de leitura e gravação nesse armazenamento e, em seguida, 
terminar chamando DEIXE CS.
Em essência, acontece que dentro de um programa, os dados tratados por meio de uma série de operações de 
leitura e escrita são protegidos contra acessos simultâneos que causariam uma visão diferente do resultado da 
execução da série como um todo. Dito de outra forma, os colchetes convertem a série de operações de leitura e 
gravação em uma unidade executada atomicamente, aumentando assim o nível de granularidade.
Para chegar a este ponto, precisamos de uma semântica precisa das operações ENTER_CS Y
DEIXE CS. Essa semântica pode ser formulada em termos de variáveis de sincronização compartilhado. Existem 
diferentes maneiras de usar essas variáveis. Veremos um método geral no qual cada variável possui alguns dados 
associados, que podem ser adicionados ao conjunto total de dados compartilhados. Adotamos a convenção de que quando 
um processo entra em sua seção crítica, ele deve adquirir variáveis de tempo importantes; Da mesma forma, quando você 
sair da seção crítica, você deve libertar essas variáveis. Observe que os dados incluídos na seção crítica do processo 
podem ser associados a diferentes variáveis de sincronização.
Cada variável de sincronização tem um proprietário atual, ou seja, o último processo que a adquiriu. O 
proprietário pode entrar e sair repetidamente de seções críticas sem ter que enviar nenhuma mensagem na rede. 
Um processo que atualmente não possui uma variável de sincronização, mas deseja adquiri-la, deve enviar uma 
mensagem ao proprietário atual solicitando sua propriedade e os valores atuais dos dados associados a essa 
variável de sincronização. Também é possível que vários processos tenham simultaneamente uma variável de 
sincronização de forma não exclusiva, o que significa que podem ler, mas não escrever, os dados associados.
SEÇÃO 7.2 MODELOS DE CONSISTÊNCIA CENTRADOS EM DADOS 287
Agora precisamos que os seguintes critérios sejam atendidos (Bershad et al., 1993):
1 Acesso para adquirir uma variável de sincronização em relação a um não-processo
é permitido até que todas as atualizações nos dados compartilhados referentes a esse processo 
sejam feitas.
2 Antes que um processo seja permitido um modo exclusivo de acesso a uma variável
sync, nenhum outro processo pode ter a variável sync, nem mesmo no modo não exclusivo.
3 - Depois de um acesso de modo exclusivo ter sido feito a uma variável em
sincronização, nenhum outro acesso não exclusivo de outro processo àquela variável de 
sincronização pode ser feito, até que tenha sido feito em relação ao dono daquela variável.
A primeira condição afirma que quando um processo faz uma aquisição, a aquisição não pode ser concluída (ou seja, 
retornar o controle para a próxima instrução) até que todos osdados compartilhados salvos tenham sido atualizados. Em 
outras palavras, em uma aquisição, todas as alterações remotas nos dados salvos devem ser tornadas visíveis.
A segunda condição afirma que antes de atualizar um item de dados compartilhados, um processo deve entrar em 
sua seção crítica em modo exclusivo para garantir que nenhum outro processo está tentando atualizar os dados 
compartilhados ao mesmo tempo.
A terceira condição afirma que se um processo deseja entrar em uma região crítica não exclusivamente, ele deve 
primeiro verificar com o proprietário da variável de sincronização que armazena a região crítica para encontrar as cópias 
mais recentes dos dados salvos compartilhados.
A Figura 7-10 mostra um exemplo do que é conhecido como consistência de entrada. Em vez de operar em todos 
os dados compartilhados, neste exemplo, associamos cadeados a cada
elemento de dados. Neste caso, P 1 faz uma aquisição para x, mudança x uma vez, após o qual ele também faz uma 
aquisição para Y. O processo P 2 faz uma aquisição para x mas não para
Y, então vai ler o valor para para x, mas pode ler NADA para Y. Porque o processo P 3 primeiro faça uma aquisição para Y, vai 
ler o valor b quando Y ser lançado por P 1
P1: Acq (Lx) W (x) a Acq (Ly) W (y) b Rel (Lx) Rel (Ly) P2: 
Acq (Lx) R (x) a
Q3: Acq (Ly) R (y) b
R (y) NIL
Figura 7-10. Sequência de eventos válida para consistência de entrada.
Um dos problemas de programação com consistência de entrada é associar dados adequadamente a variáveis 
de sincronização. Um método direto é informar explicitamente ao middleware quais dados acessar, como geralmente 
é feito ao declarar quais tabelas de banco de dados serão afetadas por uma transação. Em um método baseado em 
objeto, podemos associar
288 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
implicitamente, uma variável de sincronização exclusiva com cada objeto declarado, serializando assim com eficácia 
todas as invocações para tais objetos.
Consistência versus coerência
Neste ponto, é útil esclarecer a diferença entre dois conceitos intimamente relacionados. Os modelos que explicamos 
até agora lidam com o fato de que vários processos executam operações de leitura e gravação em um conjunto de 
elementos de dados. UMA modelo de consistência
descreve o que esperar em relação a esse conjunto quando vários processos operam simultaneamente nesses 
dados. Então, o conjunto é considerado consistente se aderir às regras descritas pelo modelo.
Embora a consistência lide com um conjunto de elementos de dados, o modelos de coerência descrever o que 
pode ser esperado de um único item de dados (Cantin et al., 2005). Nesse caso, assumimos que um item de dados é 
replicado em vários lugares; diz-se que é consistente quando as várias cópias aderem às regras definidas pelo seu 
modelo de consistência associado. Um modelo popular é a consistência sequencial, mas agora aplicado a um único 
item de dados. Na verdade, isso significa que, no caso de gravações simultâneas, todos os processos, em algum 
ponto, verão a mesma ordem de atualizações ocorrendo.
7.3 MODELOS DE CONSISTÊNCIA CENTRADOS NO 
CLIENTE
Os modelos de consistência que descrevemos na seção anterior ajudam a fornecer uma visão consistente em todo o sistema 
de um data warehouse. Uma suposição importante é que os processos simultâneos podem atualizar simultaneamente o 
armazenamento de dados e que é necessário fornecer consistência diante de tal simultaneidade. Por exemplo, no caso de 
consistência de entrada baseada em objeto, o armazenamento de dados garante que, quando um objeto é chamado, o 
processo de chamada é fornecido com uma cópia do objeto que reflete todas as alterações feitas no objeto até agora, 
provavelmente por outros processos. Durante a chamada, também é garantido que nenhum outro processo pode interferir; ou 
seja, você recebe acesso mútuo exclusivo ao processo de chamada.
Ser capaz de lidar com operações simultâneas em dados compartilhados, mantendo a consistência 
sequencial, é crítico para sistemas distribuídos. Por motivos de desempenho, a consistência sequencial pode 
provavelmente ser garantida apenas quando os processos usam mecanismos de sincronização, como transações 
ou bloqueios.
Nesta seção, veremos uma classe especial de armazenamentos de dados distribuídos. Os armazenamentos de dados 
que consideramos são caracterizados pela falta de atualizações simultâneas ou, quando essas atualizações ocorrem, podem 
ser facilmente resolvidos. A maioria das operações envolve a leitura de dados. Esses armazenamentos de dados oferecem um 
modelo de consistência muito fraco, denominado consistência momentânea. Ao introduzir modelos especiais de consistência 
centrada no cliente, torna-se aparente que muitas inconsistências podem ser ocultadas de uma maneira relativamente barata.
SEÇÃO 7.3 MODELOS DE CONSISTÊNCIA CENTRADOS NO CLIENTE 289
7.3.1 Consistência momentânea
A extensão em que os processos realmente operam simultaneamente e em que extensão a consistência precisa ser 
garantida pode variar. Existem muitos exemplos em que a simultaneidade aparece apenas de forma restritiva. Por 
exemplo, em muitos sistemas de banco de dados, a maioria dos processos quase nunca executa operações de 
atualização; eles leem principalmente dados do banco de dados. Apenas um ou poucos processos executam 
operações de atualização. Portanto, a questão é quão rápidas atualizações devem estar disponíveis para processos 
somente leitura.
Como outro exemplo, considere um sistema de nomenclatura global como o DNS. O namespace DNS é dividido 
em domínios, onde cada domínio é atribuído a uma autoridade de mapeamento que atua como proprietária desse 
domínio. Apenas essa autoridade tem permissão para atualizar sua parte do namespace. Consequentemente, os 
conflitos entre duas operações que desejam realizar uma atualização nos mesmos dados (ou seja, conflitos de 
escrita-escrita) eles nunca acontecem. A única situação que precisa ser tratada é a conflitos de leitura e gravação, em 
que um processo deseja atualizar um elemento de dados enquanto outro tenta, simultaneamente, ler esse elemento. 
Como resultado, geralmente é aceitável propagar uma atualização lentamente, o que significa que um processo de 
leitura verá uma atualização apenas algum tempo após a atualização ocorrer.
Outro exemplo é a World Wide Web. Em quase todos os casos, as páginas da web são atualizadas por uma única 
autoridade, como um webmaster ou o proprietário real da página. Normalmente, não há conflitos de gravação para resolver. 
Por outro lado, para melhorar a eficiência, os navegadores e proxies da web são frequentemente configurados para manter as 
páginas pesquisadas em um cache local e retorná-las na próxima solicitação.
Um aspecto importante de ambos os tipos de cache da web é que ambos podem retornar páginas da web desatualizadas. Em 
outras palavras, a página armazenada em cache que é retornada ao cliente solicitante é uma versão antiga, em comparação com a 
disponível no servidor da web real. Como resultado, muitos usuários consideram essa inconsistência aceitável (até certo ponto).
Esses exemplos podem ser considerados como casos de bancos de dados replicados e distribuídos (em grande escala) que 
toleram um grau relativamente alto de inconsistência. Eles têm em comum que, se as atualizações não ocorrerem por um longo 
tempo, todas as réplicas se tornarão gradualmente inconsistentes. Esta forma de consistência é conhecida como consistência 
momentânea.
Armazenamentos de dados que são momentaneamente consistentes têm a propriedade de que, na ausência de 
atualizações, todas as réplicas convergem em cópias idênticas umas das outras. Em essência, a consistência momentânea 
requer apenas a garantia de que as atualizações sejam propagadas para todas as réplicas. Os conflitos de 
gravação-gravação são geralmente fáceis de resolver quando se presume que apenas um pequeno grupo de processos 
pode realizar atualizações.A implementação de consistência momentânea é, portanto, barata.
Armazenamentos de dados consistentes funcionam bem momentaneamente, desde que os clientes sempre acessem a 
mesma réplica. No entanto, surgem problemas quando diferentes réplicas são acessadas em um curto período de tempo. Isso 
é mais bem ilustrado considerando um usuário móvel acessando um banco de dados distribuído, conforme mostrado na Figura 
7-11.
290 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
O cliente se muda para outro local 
e se conecta (de forma 
transparente)
com outra réplica
As réplicas precisam
manter uma consistência
centrado no cliente
Rede de longa distância
Operações de leitura e gravação
Banco de dados replicado e distribuído
Notebook
Figura 7-11. O princípio relativo ao acesso de um usuário móvel a diferentes réplicas de um banco 
de dados distribuído.
O usuário móvel acessa o banco de dados conectando-se de forma transparente a uma das réplicas. Em 
outras palavras, o aplicativo em execução no laptop do cliente não percebe em qual espelho está realmente 
operando. Suponha que o usuário execute várias operações de atualização e saia novamente. Posteriormente, 
você acessa o banco de dados novamente, provavelmente após mudar para um local diferente ou usar um 
dispositivo de acesso diferente. Nesse ponto, o usuário pode ser conectado a uma réplica diferente da anterior, 
conforme ilustrado na Figura 7-11. No entanto, se as atualizações feitas anteriormente ainda não foram 
propagadas, o usuário notará um comportamento inconsistente. Em particular, esperamos ver todas as 
mudanças feitas antes,
Este exemplo é típico de armazenamentos de dados momentaneamente consistentes e é causado pelo fato de que os 
usuários às vezes podem operar em réplicas diferentes. O problema pode ser aliviado com a introdução do consistência 
centrada no cliente. Em essência, a consistência centrada no cliente fornece garantias para um único cliente em relação à 
consistência do acesso ao armazenamento de dados desse cliente. Nenhuma garantia é fornecida com relação a acessos 
simultâneos por diferentes clientes.
Modelos de consistência centrados no cliente originaram-se do trabalho em Bayou [por exemplo, ver Terry et al. 
(1994) e Terry et al. (1998)]. Bayou é um sistema de banco de dados desenvolvido para computação móvel, onde se 
assume que a conectividade de rede não é confiável e que está sujeita a vários problemas de desempenho. As redes 
sem fio e aquelas que abrangem grandes áreas, como a Internet, se enquadram nesta categoria.
SEÇÃO 7.3 MODELOS DE CONSISTÊNCIA CENTRADOS NO CLIENTE 291
Bayou distingue essencialmente quatro tipos diferentes de modelos de consistência. Para explicar esses modelos, 
vamos considerar novamente um data warehouse fisicamente distribuído em várias máquinas. Quando um processo 
acessa o armazenamento de dados, ele geralmente se conecta à cópia local (ou mais próxima) disponível, embora em 
princípio qualquer cópia seria adequada. Todas as operações de leitura e gravação são executadas nessa cópia local. As 
atualizações são propagadas, em algum ponto, para as outras cópias. Para manter as coisas simples, assumimos que os 
itens de dados têm um proprietário associado, que é o único processo que tem permissão para modificar esse item. Desta 
forma, evitamos conflitos de escrita-escrita.
Modelos de consistência centrados no cliente são descritos pela seguinte nota-
ção. Estar x Eu [ t] quem denota a versão do elemento de dados x em cópia local eu Eu ao tempo t. A versão x Eu [ t] é o resultado de 
uma série de operações de gravação em eu Eu que ocorre desde a inicialização. Denotamos este conjunto como WS (x Eu [ t]). Se 
as operações em WS (x Eu [ t 1]) também se
feito na cópia local eu j Mais tarde t 2, nós escrevemos WS (x Eu [ t 1]; x j [ t 2]). Se a ordem das operações ou 
sincronização for algo claro no contexto, omitiremos
o índice de tempo.
7.3.2 Leituras monotônicas
O primeiro modelo de consistência centrado no cliente é o de leituras monotônicas. Diz-se que um data warehouse 
fornece consistência de leitura monotônica se a seguinte condição for atendida:
Se um processo lê o valor de um item de dados x, qualquer operação de leitura sucessiva em x fazer esse 
processo sempre retornará o mesmo valor ou um valor mais recente.
Em outras palavras, a consistência de leitura monotônica garante que se um processo viu um valor de x ao tempo t, você 
nunca verá uma versão mais antiga de x Mais tarde.
Como um exemplo de onde as leituras monotônicas são úteis, considere um banco de dados de e-mail 
distribuído. Nesse banco de dados, a caixa de correio eletrônica de cada usuário pode ser distribuída e 
replicada em várias máquinas. O correio pode ser inserido em uma caixa de e-mail em qualquer local. No 
entanto, as atualizações se espalham lentamente (ou seja, sob demanda). Somente quando uma cópia precisa 
de certos dados para consistência, esses dados são propagados para essa cópia. Suponha que um usuário leia 
seu e-mail em San Francisco. Suponha que apenas a leitura de e-mails não afete a caixa de correio, ou seja, as 
mensagens não são excluídas, armazenadas em subdiretórios ou mesmo marcadas como lidas etc. Quando o 
usuário voa para Nova York e reabre sua caixa de correio,
Usando uma notação semelhante à que usamos para modelos de consistência centrados em dados, a consistência 
de leitura monotônica pode ser representada graficamente como mostrado na Figura 7-12. Ao longo do eixo vertical, duas 
cópias locais diferentes do warehouse aparecem.
dados, eu 1 Y eu 2 O tempo aparece ao longo do eixo horizontal, como antes. Em todos os casos, nós
292 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
estamos interessados em operações realizadas por um único processo, P. Essas operações específicas aparecem em negrito e são 
conectadas por uma linha pontilhada que representa a ordem em que você as executa. P.
L1: WS (x 1)
L2: WS (x 1 ;; x 2)
R (x 1) L1: WS (x 1)
L2: WS (x 2)
R (x 1)
R (x 2) R (x 2)
(para) (b)
Figura 7-12. Leia as operações realizadas por um único processo, P, em duas cópias diferentes do 
mesmo armazenamento de dados. (a) Armazenamento de dados com consistência de leitura monotônica. 
(b) Armazenamento de dados que não fornece leituras monotônicas.
Na Figura 7-12 (a), o processo P primeiro execute uma operação de leitura em x no eu 1, e retorna o valor de x 1 ( nesse 
tempo). Este valor resulta de operações de gravação em WS (x 1)
criado em eu 1 Depois de, P executa uma operação de leitura em x no eu 2, mostrado como R (x 2).
Para garantir a consistência de leitura monotônica, todas as operações em WS (x 1) deve ter se espalhado para eu 2 antes 
que a segunda operação de leitura ocorra. Em outras palavras,
precisamos saber com certeza que WS (x 1) Faz parte de WS (x 2), que é expresso como WS (x 1; x 2).
Em contraste, a Figura 7-12 (b) mostra uma situação em que a consistência não é garantida.
leitura monotônica. Após o processo P ler x 1 no eu 1, realizar a operação R (x 2) no eu 2
No entanto, apenas escrever operações em WS (x 2) foram feitos em eu 2 Não há garantia de que este conjunto 
também incluirá todas as operações contidas em WS (x 1).
7.3.3 Escritas monotônicas
Em muitas situações, é importante que as operações de gravação se propaguem na ordem correta para todas as cópias do 
armazenamento de dados. Esta propriedade é expressa em consistência de escrita monotônica. Em um armazém com consistência 
de escrita monotônica, a seguinte condição for atendida:
Uma operação de gravação feita por um processo em um elemento x é concluída antes de qualquer 
outra operação de gravação sucessiva em x feito pelo mesmo processo.
Assim, completar uma operação de gravação significa que a cópia na qual uma operação sucessiva é realizada reflete o 
efeito de uma operação de gravação anterior realizada pelo mesmo processo, independentemente de onde essa operação foi 
iniciada. Em outras palavras, uma operação degravação em uma cópia do elemento x realizada apenas se essa cópia tiver 
sido atualizada por quaisquer operações de gravação anteriores, o que pode ter ocorrido em outras cópias de x. Se 
necessário, a nova escritura deve aguardar o término de outras escrituras anteriores.
SEÇÃO 7.3 MODELOS DE CONSISTÊNCIA CENTRADOS NO CLIENTE 293
Observe que a consistência de gravação monotônica se assemelha à consistência FIFO centrada em dados. O 
básico da consistência FIFO é que as operações de gravação do mesmo processo são realizadas na ordem correta em 
qualquer lugar. Essa restrição de ordenação também se aplica a gravações monotônicas, com a exceção de que agora 
consideramos apenas a consistência para um único processo, em vez de uma coleção de processos simultâneos.
Atualize uma cópia de x não é necessário quando cada operação de gravação sobrescreve completamente o 
valor atual de x. No entanto, as operações de gravação geralmente são executadas em apenas parte do estado de 
um item de dados. Por exemplo, vamos considerar uma biblioteca de software. Em muitos casos, a atualização de 
uma biblioteca desse tipo é feita com a substituição de uma ou mais funções, o que leva a uma próxima versão. Com 
a consistência de gravação monotônica, são fornecidas garantias de que, se uma atualização for feita em uma cópia 
da biblioteca, todas as atualizações anteriores serão feitas primeiro. A biblioteca resultante se tornará a versão mais 
recente e incluirá todas as atualizações que levaram a versões anteriores da biblioteca.
A Figura 7-13 mostra a consistência da escrita monotônica. Na subseção (a) da referida figura,
o processo P executa uma operação de gravação em x em cópia local eu 1, e é apresentado como a operação W (x 1). Depois de, 
P executa outra operação de gravação em x, mas desta vez em eu 2, e mostra como W (x 2). Para garantir a consistência da 
gravação monotônica, é necessário que as operações de gravação anteriores realizadas em eu 1 se espalharam para eu 2 Isso 
explica a operação W (x 1) no eu 2, e por que isso acontece antes W (x 2).
L1:
L2:
W (x 1) L1:
L2:
W (x 1)
MS (x 1) W (x 2) W (x 2)
(para) (b)
Figura 7-13. Operações de gravação realizadas por um único processo P em duas cópias locais 
diferentes do mesmo armazenamento de dados. (a) Armazenamento de dados com consistência de 
escrita monotônica. (b) Armazenamento de dados que não fornece consistência de gravação 
monotônica.
Em contraste, a Figura 7-13 (b) mostra uma situação em que a consistência não é garantida.
escrita monotônica. Comparado com a Fig. 7-13 (a), o que está faltando é a propagação de W (x 1)
copiar eu 2 Em outras palavras, não é possível garantir que a cópia do x, em que a segunda escrita está sendo 
realizada, tem o mesmo valor ou o mais recente no tempo W (x 1) completado
no eu 1
Observe que, por definição de consistência de escrita monotônica, as operações de
escrever o mesmo processo é executado na mesma ordem em que começou. Uma forma um pouco mais fraca de 
gravações monotônicas é aquela em que os efeitos de uma operação de gravação são vistos apenas se todas as 
gravações anteriores foram realizadas, embora talvez não na ordem em que originalmente se originaram. Essa 
consistência é aplicável aos casos em que as operações de gravação são comutativas, de modo que a ordem não é 
realmente necessária. Detalhes podem ser encontrados em Terry et al. (1994).
294 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
7.3.4 Leia suas ações
Um modelo de consistência centrado no cliente que está intimamente relacionado às leituras monotônicas é o seguinte. 
Diz-se que um data warehouse fornece consistência leia suas escrituras se atender à seguinte condição:
O efeito de uma operação de gravação feita por um processo em um item de dados x
sempre será visto por uma operação de leitura sucessiva em x feito pelo mesmo processo.
Em outras palavras, uma operação de gravação sempre é concluída antes de uma operação de leitura sucessiva do 
mesmo processo, independentemente de onde a operação de leitura ocorre.
Às vezes, ocorre uma falta de consistência na leitura de suas gravações ao atualizar documentos da web, 
e os efeitos são vistos posteriormente. As operações de atualização freqüentemente ocorrem por meio de um 
editor padrão ou um processador de texto, os quais salvam a nova versão em um sistema de arquivos que é 
compartilhado pelo servidor web. O navegador da Web do usuário acessa esse mesmo arquivo, provavelmente 
após solicitá-lo do servidor da Web local. No entanto, uma vez que o arquivo foi retirado, o servidor ou o 
navegador geralmente armazenará em cache uma cópia local para acesso posterior. Conseqüentemente, 
quando a página da web for atualizada, se o navegador ou o servidor retornar a cópia em cache em vez do 
arquivo original, o usuário não verá os efeitos.
Efeitos semelhantes ocorrem ao atualizar senhas. Por exemplo, para acessar uma biblioteca digital na 
web, muitas vezes é necessário ter uma conta e sua senha correspondente. No entanto, a alteração de uma 
senha pode levar algum tempo para fazer efeito, fazendo com que a biblioteca fique inacessível ao usuário por 
alguns minutos. O atraso pode ser causado por um servidor separado sendo usado para lidar com senhas e a 
propagação subsequente de senhas (criptografadas) para os diferentes servidores que compõem a biblioteca 
pode levar algum tempo.
A Figura 7-14 (a) mostra um armazenamento de dados que fornece consistência de leitura de suas gravações. Observe 
que a Figura 7-14 (a) é muito semelhante à Figura 7-12 (a), exceto que agora a consistência é determinada pela última 
operação de gravação do processo P, em vez de sua última leitura.
L1:
L2:
W (x 1) L1:
L2:
W (x 1)
WS (x 1; x 2) R (x 2) WS (x 2) R (x 2)
(para) (b)
Figura 7-14. ( a) Armazenamento de dados que fornece consistência na leitura de suas gravações. 
(b) Data warehouse que não o fornece.
Na Figura 7-14 (a), o processo P executou uma operação de escrita W (x 1) e, em seguida, uma operação de leitura em 
uma cópia local diferente. A consistência na leitura de seus atos garante que
SEÇÃO 7.3 MODELOS DE CONSISTÊNCIA CENTRADOS NO CLIENTE 295
Os efeitos da operação de gravação podem ser vistos pela operação de leitura sucessiva. Isto é
expresso através WS (x 1; x 2), que estabelece que W (x 1) Faz parte de WS (x 2). Em contraste, na Figura 7-14 (b) W (x 1) foi 
excluído de WS (x 2), isso significa que os efeitos da operação de gravação anterior do processo P ainda não se espalhou 
para eu 2
7.3.5 Escritas seguem leituras
O modelo de consistência centrado no cliente mais recente é aquele em que as atualizações são propagadas como 
resultado de operações de leitura anteriores. Diz-se que um data warehouse fornece consistência escrituras 
seguem leituras se atender ao seguinte:
É garantido que a operação de gravação de um processo em um elemento de dados x que segue uma operação 
de leitura anterior em x realizado pelo mesmo processo ocorrerá no mesmo valor ou no valor mais recente de x que 
foi lido.
Em outras palavras, qualquer operação sucessiva de um processo em um elemento de dados x será feito em uma cópia de x que 
é atualizado com o valor lido mais recentemente por esse processo.
As gravações de consistência seguem leituras podem ser usadas para garantir que os usuários de uma rede de 
newsgroup vejam o anúncio de uma resposta a um artigo somente após terem visto o artigo original (Terry et al., 1994). 
Para entender o problema, suponha que um usuário leia o artigo primeiro PARA; então reaja e poste a resposta B. Ao exigir 
consistência, as gravações seguem as leituras, B será gravado em qualquer cópia do grupo de notícias somente após PARA 
também está escrito. Observe que os usuários que apenas leem os artigos não precisam necessariamente de um modelo 
de consistência centrado no cliente específico. As gravações de consistência seguem leituras garantem que as reações 
aos artigos sejam armazenadasem uma cópia local somente se o original também estiver armazenado lá.
L1: WS (x 1)
L2: WS (x 1 ;; x 2)
R (x 1) L1: WS (x 1)
L2: WS (x 2)
R (x 1)
W (x 2) W (x 2)
(para) (b)
Figura 7-15. ( a) Armazém de dados com leitura de gravação de consistência. (b) O 
armazenamento de dados não fornece gravações de consistência após leituras.
Esse padrão de consistência aparece na Figura 7-15. Na parte (a) desta figura, um
o processo lê para x em uma cópia local eu 1 As operações de gravação que causaram o valor lido também aparecem 
no conjunto escrito em eu 2, onde o mesmo processo executa uma operação de gravação. (Observe que outros 
processos incluídos no eu 2 eles também veem essas operações de gravação.) Em contraste, a operação realizada em eu
2, como a figura ilustra
ra 7-15 (b), ser feito em uma cópia consistente com a que acabou de ler eu 1
Mais adiante neste capítulo, retornaremos aos modelos de consistência centrados no cliente,
quando explicamos as implementações.
296 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
7.4 ADMINISTRAÇÃO DE RESPOSTAS
Um ponto-chave para qualquer sistema distribuído que ofereça suporte à replicação é decidir onde, quando e por quem 
as réplicas devem ser localizadas e, subsequentemente, quais mecanismos usar para mantê-las consistentes. O 
problema de localização, por si só, deve ser dividido em dois subproblemas: o da localização de servidores espelho, e 
aquele de localização do conteúdo.
A diferença é sutil, mas importante, e as duas questões muitas vezes não são claramente separadas. A localização 
do servidor de réplica trata de encontrar os melhores lugares para colocar um servidor que possa hospedar (parte 
de) um armazenamento de dados. A colocação de conteúdo consiste em encontrar os melhores servidores para 
colocar conteúdo. Observe que isso geralmente significa que estamos procurando o local ideal para um único item 
de dados. Claro, antes que a colocação de conteúdo possa ocorrer, primeiro temos que localizar os servidores. 
Analisaremos esses dois problemas de posicionamento abaixo e continuaremos com uma explicação dos 
mecanismos básicos para gerenciar o conteúdo replicado.
7.4.1 Localização do servidor de réplica
O posicionamento do servidor de réplica não é um problema estudado intensamente, pelo simples motivo de que 
geralmente é mais uma questão comercial e administrativa do que um problema de otimização. No entanto, analisar 
as propriedades do cliente e da rede é útil para tomar decisões informadas.
Existem várias maneiras de calcular a melhor localização do servidor de réplica, mas todas elas se resumem a um 
problema de otimização em que você precisa selecionar o melhor K de entre N Localizações ( K <N). Sabe-se que esses 
problemas são computacionalmente complexos, e que só podem ser resolvidos por heurísticas. Qiu et al. (2001) medem a 
distância entre clientes e locais de um ponto de partida. A distância pode ser medida em termos de latência ou largura de 
banda. Sua solução seleciona um servidor por vez, de forma que a distância média entre esse servidor e seus clientes 
seja mínima, pois k servidores já foram localizados (isto significa que existem N 
k locais descartados).
Como alternativa, Radoslavov et al. (2001) propõem ignorar a posição dos clientes, e apenas tomar a 
topologia da internet como se ela fosse composta por sistemas autônomos. UMA sistema autônomo (AS, por sua 
sigla em inglês) pode ser considerada como uma rede na qual todos os nós executam o mesmo protocolo de 
roteamento e que é gerenciada por uma única organização. Em janeiro de 2006, já havia mais de 20.000 sistemas 
autônomos. Radoslavov et al., Considere primeiro o maior AS e coloque um servidor no roteador que tenha o maior 
número de interfaces de rede (ou seja, links). Esse algoritmo é então repetido com o segundo maior AS e assim 
por diante.
Como resultado, localizar um servidor sem o conhecimento do cliente atinge resultados semelhantes aos obtidos 
com o conhecimento do cliente, partindo do princípio de que os clientes estão uniformemente distribuídos pela Internet 
(com base na topologia existente). Até que ponto essa suposição é verdadeira não está claro; ainda não foi bem 
estudado.
SEÇÃO 7.4 ADMINISTRAÇÃO DE RESPOSTAS 297
Um problema com esses algoritmos é que eles são caros para computar. Por exemplo, os dois algoritmos anteriores 
têm uma complexidade maior que O ( N 2), Onde N é o número de locais a serem inspecionados. Na prática, isso significa 
que, mesmo para alguns milhares de locais, um cálculo pode precisar ser executado por dezenas de minutos. Isso pode ser 
inaceitável, especialmente quando ocorrem multidões instantâneas uma explosão repentina de pedidos de um site 
específico, o que acontece regularmente na Internet). Nesse caso, é essencial determinar rapidamente onde os servidores 
de réplica são necessários, após o que um servidor pode ser selecionado para o local do conteúdo.
Szymaniak e outros (2006) desenvolveram um método pelo qual uma região pode ser rapidamente identificada 
para localizar réplicas. Uma região é identificada como uma coleção de nós que acessam o mesmo conteúdo, mas 
para os quais a latência internodal é baixa. O objetivo do algoritmo é primeiro selecionar as regiões com maior 
demanda, ou seja, aquelas com mais nós, e então deixar um dos nós daquela região atuar como um servidor de 
réplica.
Para tanto, assume-se que os nós estão posicionados em um espaço geométrico m dimensional, como explicamos no 
capítulo anterior. A ideia básica é identificar o K clusters maiores e designar um nó de cada cluster para hospedar o 
conteúdo replicado. Para identificar esses aglomerados, todo o espaço é dividido em células. As K As células densas são 
então escolhidas para acomodar um servidor de réplica. Uma célula nada mais é do que um hipercubo m dimensional. Para 
um espaço bidimensional, isso corresponde a um retângulo.
Obviamente, o tamanho da célula é importante, conforme mostrado na Figura 7-16. Se as células forem escolhidas 
muito grandes, então vários clusters de nós podem ser encontrados na mesma célula. Nesse caso, poucos servidores 
de réplica seriam escolhidos para esses clusters. Por outro lado, a escolha de células pequenas pode fazer com que um 
único cluster se propague em várias células, resultando na escolha de muitos servidores de réplica.
Muito pequeno Demasiado grande
Célula Muito bem
Figura 7-16. Escolher o tamanho apropriado de uma célula para localizar um servidor.
Como resultado, um tamanho de célula adequado pode ser calculado como uma função simples da 
distância média entre dois nós e o número de réplicas necessárias. Com este tamanho de célula, pode-se 
mostrar que o algoritmo se comporta tão bem quanto o quase ótimo descrito por Qiu et al. (2001), mas com um 
grau de complexidade muito menor: O ( N x max { log (N), K}). Para ilustrar o que esse resultado significa: 
experimentos mostram
298 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
calcular as 20 principais localizações de réplicas para uma coleção de 64.000 nós é cerca de 50.000 vezes mais 
rápido. Consequentemente, a localização dos servidores de réplica agora pode ser feita em tempo real.
7.4.2 Localização e replicação de conteúdo
Agora vamos deixar o local do servidor e nos concentrar no local do conteúdo. Quando se trata de replicação e colocação de 
conteúdo, existem três tipos de réplicas organizadas logicamente que podem ser distinguidas, conforme ilustrado na Figura 
7-17.
Réplica iniciada pelo servidor Réplica 
iniciada pelo cliente
Réplicas
permanente
Réplicas iniciadas
pelo servidor
Réplicas iniciadas
para o cliente
clientes
Figura 7-17. Organização lógica de diferentes tipos de cópias de um armazenamento de dados em 
três anéis concêntricos.
Réplicas permanentes
As réplicas permanentes podem ser consideradas o conjunto inicial de réplicas que constituem um armazenamento de 
dados distribuído. Em muitos casos, o número de réplicas permanentes épequeno. Por exemplo, vamos considerar um 
site. O layout de um site geralmente vem em uma de duas formas. A primeira classe de distribuição é aquela em que os 
arquivos que constituem um site são replicados em um número limitado de servidores em um único local. Sempre que 
chega uma solicitação, ela é encaminhada para um dos servidores, por exemplo, por meio de uma estratégia
round-robin ( todos contra todos).
A segunda forma de sites distribuídos é conhecida como espelho. Nesse caso, um site é copiado para um 
número limitado de servidores, chamado sites espelho, que são distribuídos geograficamente pela Internet. Na 
maioria dos casos, os clientes simplesmente escolhem um dos diferentes sites espelho de uma lista oferecida a 
eles. Os sites espelhados têm em comum sites baseados em cluster que têm apenas algumas réplicas, que são 
mais ou menos configuradas estaticamente.
Organizações estáticas semelhantes também são apresentadas com bancos de dados distribuídos (Oszu e Valduriez, 
1999). Novamente, o banco de dados pode ser distribuído e replicado em uma série de servidores que compõem um cluster 
de servidores, geralmente conhecido como arquitetura
SEÇÃO 7.4 ADMINISTRAÇÃO DE RESPOSTAS 299
nada compartilhado, no qual é enfatizado que nem os discos nem a memória principal são compartilhados pelos 
processadores. Como alternativa, um banco de dados é distribuído, e provavelmente replicado, em vários locais 
geograficamente dispersos. Essa arquitetura é muito usada em bancos de dados federados (Sheth e Larson, 1990).
Réplicas iniciadas pelo servidor
Em contraste com as réplicas permanentes, as réplicas iniciadas pelo servidor são cópias de um armazenamento de 
dados que existe para melhorar o desempenho e que são criadas por iniciativa do (proprietário do) armazenamento de 
dados. Por exemplo, considere um servidor da web localizado em Nova York. Normalmente, este servidor pode lidar com 
as solicitações recebidas com muita facilidade, mas pode acontecer que durante alguns dias haja uma explosão repentina 
de solicitações de um local inesperado, longe do servidor. Nesse caso, pode valer a pena instalar várias réplicas 
temporárias nas regiões de onde vêm as solicitações.
O problema de colocar réplicas dinamicamente também está sendo abordado em serviços de hospedagem na 
web. Esses serviços oferecem um conjunto (relativamente estático) de servidores espalhados pela Internet que podem 
manter e fornecer acesso a arquivos da Web pertencentes a terceiros. Para fornecer recursos ideais, esses serviços de 
hospedagem podem replicar arquivos dinamicamente em servidores onde esses arquivos são necessários para 
melhorar o desempenho, ou seja, em clientes solicitantes próximos (grupos). Sivasubramanian et al. (2004b) fornecem 
um tratamento detalhado da replicação em serviços de hospedagem na web, ao qual retornaremos no Capítulo 12.
Uma vez que os espelhos já estão localizados, decidir onde colocar seu conteúdo é mais fácil do que colocar 
no servidor. Um método de implementação de replicação dinâmica de arquivos no caso de um serviço de 
hospedagem na web é descrito por Rabinovich et al. (1999). O algoritmo é projetado para oferecer suporte a páginas 
da web, portanto, assume que as atualizações são relativamente raras em comparação com as solicitações de 
leitura. Ao usar arquivos como unidade dos dados, o algoritmo funciona da seguinte maneira.
O algoritmo de replicação dinâmica leva dois pontos em consideração. Primeiro, a replicação pode ocorrer para 
reduzir a carga em um servidor. Em segundo lugar, os arquivos específicos de um servidor podem ser migrados ou 
replicados para outros servidores localizados nas proximidades de clientes que solicitam muito esses arquivos. Nas páginas 
seguintes, vamos nos concentrar apenas neste segundo ponto. Também omitimos vários detalhes, mas o leitor pode 
encontrá-los em Rabinovich et al. (1999).
Cada servidor controla o número de acessos por arquivo e registra de onde vêm as solicitações de acesso. 
Em particular, presume-se que, dado um cliente C, Cada servidor pode determinar qual dos servidores do serviço 
de hospedagem está mais próximo de C. ( Essas informações podem ser obtidas, por exemplo, nos bancos de 
dados de roteamento.) Se o
cliente C 1 e o cliente C 2 compartilhe o mesmo servidor "mais próximo" P, todas as solicitações de acesso ao arquivo F no servidor Q 
Desde a C 1 Y C 2 estão registrados em conjunto em Q como uma
conta de login único cnt Q ( P, F). Essa situação aparece na Figura 7-18.
Quando no servidor S o número de solicitações de acesso a um arquivo específico F diminui
abaixo de um limite para eliminação del (S, F), esse arquivo pode ser removido de S. Em consequência,
300 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
C 2
Servidor sem um
cópia do arquivo F
P
Cliente
Servidor com um
cópia de F
Q
C 1
Arquivo F
O servidor Q conta os acessos de C 1 e C 2 como 
se viessem de P
Figura 7-18. Contagem de solicitações de acesso de diferentes clientes.
o número de réplicas para esse arquivo é reduzido, o que provavelmente resultará em cargas de trabalho maiores em outros 
servidores. Para garantir que haja pelo menos uma cópia de cada arquivo, medidas especiais são tomadas.
Um limite de replicação rep (S, F), que é sempre escolhido acima do limite de exclusão, indica se o número de 
solicitações de acesso a um arquivo específico é tão alto que pode valer a pena replicá-lo em outro servidor. Se o 
número de solicitações cair entre os limites de exclusão e replicação, apenas o arquivo poderá ser migrado. Em outras 
palavras, nesse caso é importante manter pelo menos o mesmo número de réplicas daquele arquivo.
Quando um servidor Q decide reavaliar a localização dos arquivos que armazena, verifica o número de acessos por 
arquivo. Se o número total de solicitações de acesso a F no Q cai abaixo do limite de eliminação, del (Q, F), o servidor irá 
deletar F a menos que esta seja a última cópia.
Além disso, se estiver em qualquer servidor P, cnt Q ( P, F) excede em mais da metade do total de solicitações para F no
Q, para o servidor P você é convidado a assumir F. Em outras palavras, o servidor Q tentará migrar
F em direção a P.
Migração de arquivo F em direção ao servidor P nem sempre tem sucesso, por exemplo, porque P já está muito 
carregado ou não tem espaço em disco. Nesse caso, Q vai tentar replicar F em outros servidores. Claro, a replicação pode 
ocorrer apenas se o número total de solicitações de acesso para F no Q excede o limite de replicação rep (Q, F). O servidor Q verifica 
todos os outros servidores no serviço de hospedagem na web, começando pelo mais distante. Sim, em algum servidor R,
cnt Q ( R, F) excede uma certa fração de todas as solicitações de acesso a F no Q, é feita uma tentativa de replicar F no R.
A replicação iniciada pelo servidor continua a crescer em popularidade com o tempo, especialmente no contexto de 
serviços de hospedagem na web, como o que acabamos de descrever. Observe que, desde que sejam fornecidas garantias 
de que cada item de dados seja hospedado por pelo menos um servidor, isso pode ser suficiente para usar apenas a 
replicação iniciada pelo servidor e não ter réplicas permanentes. No entanto, os espelhos permanentes ainda são úteis 
como ferramentas de backup, ou para serem usados como os únicos espelhos que podem ser alterados para
SEÇÃO 7.4 ADMINISTRAÇÃO DE RESPOSTAS 301
garantir consistência. As réplicas iniciadas pelo servidor são usadas para colocar cópias somente leitura perto dos 
clientes.
Réplicas iniciadas pelo cliente
Um tipo importante de réplica é aquela iniciada por um cliente. Essas réplicas são mais comumente conhecidas como caches 
(cliente). Em essência, um cache é uma ferramenta de armazenamento local usada por um cliente para armazenar 
temporariamente uma cópia dos dados solicitados. Em princípio, o gerenciamento de cache é deixado inteiramente para o 
cliente. O armazenamento de dados do qual elessão trazidos não tem nada a ver com a consistência dos dados 
armazenados em cache. No entanto, como veremos, há muitas ocasiões em que o cliente pode contar com a intervenção 
do data warehouse para informá-lo quando os dados em cache desatualizados forem retornados.
Os caches do cliente são usados apenas para melhorar o tempo de acesso aos dados. Normalmente, quando um 
cliente deseja acessar certos dados, ele se conecta à cópia mais próxima do data warehouse, de onde traz os dados que 
deseja ler ou onde armazena os dados que acabou de modificar. Quando a maioria das operações envolve apenas dados 
de leitura, é possível melhorar o desempenho permitindo que o cliente armazene os dados solicitados em um cache 
próximo. Esse cache pode estar localizado na máquina do cliente ou em outra máquina na rede local do mesmo cliente. Na 
próxima vez que ele precisar ler os dados, o cliente pode simplesmente buscá-los em seu cache local. Este esquema 
funciona bem, desde que os dados buscados não tenham sido modificados.
Os dados geralmente são armazenados em cache por um tempo limitado, por exemplo, para evitar o uso de dados 
extremamente antigos ou simplesmente para abrir espaço para outros dados. Sempre que os dados podem ser obtidos do 
cache local, diz-se que um acerto de cache. Para melhorar o número de acessos de cache, os caches podem ser 
compartilhados entre clientes. A suposição
subjacente é que uma solicitação de dados do cliente C 1 também pode ser útil para um pedido de
outro cliente próximo C 2
Se essa suposição está correta depende muito do tipo de armazenamento de dados.
Por exemplo, em sistemas de arquivos tradicionais, os arquivos de dados raramente são totalmente compartilhados (ver Muntz 
e Honeyman, 1992; e Blaze, 1993), o que resulta em um cache compartilhado inútil. Acontece também que o uso de caches 
para compartilhamento de dados está perdendo espaço, em parte devido a melhorias no desempenho da rede e do servidor. 
Em vez disso, os esquemas de replicação iniciados pelo servidor estão se tornando mais eficazes.
Localizar caches de cliente é relativamente simples: normalmente, um cache é colocado na mesma máquina cliente ou 
em outra máquina compartilhada por clientes na mesma rede local. No entanto, em alguns casos, os administradores de 
sistema introduzem níveis adicionais de cache, colocando um cache compartilhado em vários departamentos ou 
organizações, ou mesmo colocando um cache compartilhado para uma região inteira, como uma província ou país.
Outro método é colocar servidores (cache) em pontos específicos em uma rede de longa distância e deixar o cliente 
localizar o servidor mais próximo. Quando o servidor é localizado, pode ser solicitado que você mantenha cópias dos dados 
que o cliente solicitou anteriormente de outro lugar,
302 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
conforme descrito por Noble et al. (1999). Voltaremos ao assunto de pat-down neste capítulo quando explicarmos os 
protocolos de consistência.
7.4.3 Distribuição de conteúdo
O gerenciamento de réplicas também lida com a propagação (atualização) de conteúdo para servidores de réplicas 
significativos.
Estado versus operações
Um ponto importante do design diz respeito ao que realmente vai se espalhar. Existem basicamente três possibilidades:
1. Propagar apenas a notificação de uma atualização.
2. Transfira os dados de uma cópia para outra.
3. Propague a operação de atualização para outras cópias.
Propagar uma notificação é o que protocolos de invalidação. Em um protocolo de invalidação, outras cópias são 
informadas de que ocorreu uma atualização e que os dados nelas contidos não são mais válidos. A substituição pode 
especificar qual parte do armazenamento de dados foi atualizada, de forma que apenas parte de uma cópia seja 
realmente inválida. O importante é que no máximo uma notificação seja divulgada. Sempre que uma cópia ou 
operação inválida é solicitada, essa cópia geralmente precisa ser atualizada primeiro, de acordo com o modelo de 
consistência específico a ser suportado.
A principal vantagem dos protocolos de substituição é que eles usam muito pouca largura de banda da rede. A única 
informação que precisa ser transferida é uma especificação de quais dados não são mais válidos. Esses protocolos 
geralmente funcionam melhor quando há muitas operações de atualização, em comparação com as operações de leitura; ou 
seja, a proporção de leitura / gravação é relativamente pequena.
Por exemplo, considere um armazenamento de dados no qual as atualizações são propagadas enviando dados 
alterados para todas as réplicas. Se o tamanho dos dados alterados for grande e as atualizações ocorrerem com 
frequência, em comparação com as operações de leitura, poderíamos enfrentar a situação em que duas atualizações 
ocorrem uma após a outra, sem que nenhuma operação de leitura seja realizada entre elas. Conseqüentemente, a 
propagação da primeira atualização para todos os espelhos é efetivamente inútil, pois será substituída pela segunda 
atualização. Em vez disso, enviar uma notificação de que os dados foram alterados seria mais eficiente.
A segunda alternativa é transferir os dados alterados entre as réplicas e é útil quando a proporção de leitura / gravação 
é relativamente grande. Nesse caso, a probabilidade de que uma atualização seja efetiva, no sentido de que os dados 
modificados serão lidos antes que ocorra a próxima atualização, é grande. Em vez de propagar os dados alterados, também 
é possível registrar as alterações e transferir apenas esses registros para economizar largura de banda. Além disso, 
frequentemente
SEÇÃO 7.4 ADMINISTRAÇÃO DE RESPOSTAS 303
as transferências são agrupadas no sentido de que várias modificações são agrupadas em uma única mensagem, evitando assim o 
overhead de comunicação.
O terceiro método não é transferir nenhuma modificação de dados, mas informar a cada réplica qual operação de 
atualização realizar (e enviar apenas os valores dos parâmetros de que essas operações precisam). Este método, 
também conhecido como replicação ativa, Ele assume que cada réplica é representada por um processo capaz de 
manter seus dados associados “ativamente” atualizados por meio de operações (Schneider, 1990). O principal 
benefício da replicação ativa é que as atualizações podem ser propagadas com custos mínimos de largura de banda 
porque o tamanho dos parâmetros associados a uma operação é relativamente pequeno. Além disso, as operações 
podem ser arbitrariamente complexas, permitindo aprimoramentos posteriores para manter as réplicas consistentes. 
Por outro lado, cada réplica pode exigir mais poder de processamento, especialmente quando as operações são 
relativamente complexas.
Protocolos de pull versus protocolos push
Outro problema de design é se as atualizações são empurradas ou puxadas. Em um método baseado em push, também 
conhecido como protocolos baseados em servidor, as atualizações são propagadas para outras réplicas sem sua solicitação. 
Os métodos baseados em push são freqüentemente usados entre réplicas permanentes e iniciadas pelo servidor, mas 
também podem ser usados para enviar atualizações para caches de cliente. Os protocolos baseados em servidor são 
aplicados quando as réplicas precisam manter um grau relativamente alto de consistência. Em outras palavras, é necessário 
que as réplicas permaneçam idênticas.
Essa necessidade de um alto grau de consistência está relacionada ao fato de que réplicas permanentes e 
iniciadas pelo servidor, bem como caches grandes, são freqüentemente compartilhados por muitos clientes que, por 
sua vez, basicamente realizam operações de leitura. Portanto, em cada réplica, a proporção de leitura-atualização é 
relativamente alta. Nestes casos, os protocolos baseados em push são eficientes no sentido de que cada atualização 
inserida pode ser usada por um ou mais leitores. Além disso, os protocolos baseados em push disponibilizam dados 
consistentesimediatamente sob demanda.
Em contraste, em um método baseado em pull, um servidor ou cliente solicita que outro servidor envie a ele todas as 
atualizações que possui até o momento. Protocolos baseados em pull, também conhecidos como protocolos baseados no 
cliente, eles são freqüentemente usados por caches de cliente. Por exemplo, uma estratégia comum, aplicada a caches da 
web, é primeiro verificar se os itens de dados em cache ainda estão atualizados. Quando um cache recebe uma solicitação de 
itens que ainda estão disponíveis localmente, o cache verifica com o servidor da web original se esses itens de dados foram 
modificados desde que foram armazenados em cache. No caso de uma modificação, os dados modificados são primeiro 
transferidos para o cache e, em seguida, devolvidos ao cliente solicitante. Se nenhuma modificação ocorreu, os dados em 
cache são retornados. Em outras palavras, o cliente consulta o servidor para ver se uma atualização é necessária.
Um método baseado em pull é eficiente quando a proporção leitura-atualização é relativamente baixa. Em geral, 
esse é o caso de caches de clientes (não compartilhados), que possuem apenas um cliente. No entanto, mesmo 
quando um cache é compartilhado por muitos clientes, um método baseado em pull também pode ser eficiente quando 
os itens de dados em cache são
304 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
compartilhado. A principal desvantagem de uma estratégia baseada em pull, em comparação com o método push, é que o 
tempo de resposta aumenta no caso de vazamento de cache.
Ao comparar soluções baseadas em push e pull, há muitos sacrifícios a serem feitos, conforme mostrado na Figura 
7-19. Para simplificar, considere um sistema cliente-servidor que consiste em um único servidor não distribuído e vários 
processos de cliente, cada um com seu próprio cache.
Questão Baseado em push Baseado em pull
Status no servidor 
Mensagens enviadas
Lista de réplicas e caches do cliente
Atualizar (e possivelmente trazer a 
atualização mais tarde)
Imediato (ou procure o tempo de 
atualização)
Nenhum
Pesquisa e atualização
Tempo de resposta
no cliente
Encontre o tempo de atualização
Figura 7-19. Comparação entre protocolos baseados em push e pull para sistemas de servidor 
único e múltiplos clientes.
Um ponto importante é que em protocolos baseados em push, o servidor precisa manter o controle de todos os 
caches do cliente. Além do fato de que os servidores de estado costumam ser menos tolerantes a falhas, como 
explicamos no Capítulo 3, manter o controle de todos os caches do cliente pode resultar em considerável sobrecarga do 
servidor. Por exemplo, em um método baseado em push, um servidor da web pode precisar controlar dezenas de 
milhares de caches de cliente. Cada vez que uma página da web for atualizada, o servidor precisará verificar sua lista de 
cache de cliente, manter uma cópia dessa página e, em seguida, propagar a atualização. Pior ainda, se um cliente limpar 
uma página por falta de espaço, ele terá que reportar ao servidor, o que leva a mais comunicação.
As mensagens que precisam ser enviadas entre um cliente e o servidor também são diferentes. Em um método 
baseado em push, a única comunicação é que o servidor envia atualizações para cada cliente. Quando as atualizações 
são apenas invalidações, é necessária uma comunicação adicional com o cliente para trazer os dados alterados. Em um 
método baseado em pull, o cliente terá que pesquisar o servidor e, se necessário, buscar os dados alterados.
Por fim, o tempo de resposta do cliente também é diferente. Quando um servidor introduz dados alterados no 
cache do cliente, fica claro que o tempo de resposta do lado do cliente é zero. Quando as substituições são 
introduzidas, o tempo de resposta é o mesmo do método baseado em pull e é determinado pelo tempo que leva 
para buscar os dados alterados do servidor.
Essas desvantagens levaram a uma forma híbrida de propagação de atualização baseada em contrato. UMA contrato 
é uma promessa do servidor de que enviará atualizações para o cliente pelo tempo especificado. Quando um contrato 
expira, o cliente é forçado a consultar o servidor em busca de atualizações e extrair os dados modificados, se 
necessário. Uma alternativa é o cliente solicitar um novo contrato para introduzir atualizações quando o anterior 
expirar.
Os contratos foram originalmente apresentados por Gray e Cheriton (1989). Eles forneceram um mecanismo 
conveniente para mudança dinâmica entre uma estratégia baseada em push e
SEÇÃO 7.4 ADMINISTRAÇÃO DE RESPOSTAS 305
outro baseado em pull. Duvvuri et al (2003) descrevem um sistema de contrato flexível que permite que o tempo de 
expiração seja adaptado dinamicamente, de acordo com os diferentes critérios de contratação. Eles distinguem os 
três tipos de contrato a seguir. (Observe que em todos os casos, as atualizações são introduzidas pelos servidores, 
desde que o contrato não tenha expirado.)
Em primeiro lugar, os contratos baseados no tempo são separados dos itens de dados de acordo com a 
última vez em que o item foi modificado. A suposição subjacente é que se espera que os dados que não foram 
alterados por muito tempo permaneçam assim por mais algum tempo. Esta suposição provou ser razoável no 
caso de dados baseados na web. Ao garantir contratos de longo prazo para itens de dados que devem 
permanecer inalterados, o número de mensagens de atualização pode ser significativamente reduzido em 
comparação com o caso em que todos os contratos têm o mesmo tempo de expiração.
Outro critério de contratação é a frequência com que um cliente específico solicita que sua cópia em cache seja 
atualizada. Com contratos baseados na frequência de renovação, um servidor irá lidar com um contrato de longo 
prazo com um cliente cujo cache precisa ser atualizado com frequência. Por outro lado, um cliente que apenas 
ocasionalmente solicita um dado específico terá um contrato de curto prazo para aquele item. O efeito dessa 
estratégia é que o servidor basicamente rastreia apenas os clientes com os quais seus dados são muito populares; 
além disso, esses clientes têm um alto grau de consistência.
O último critério é a sobrecarga do espaço de estado no servidor. Quando o servidor percebe que está 
gradativamente sendo sobrecarregado, ele diminui o tempo de expiração de novos contratos e os distribui aos 
clientes. O efeito dessa estratégia é que o servidor precisa monitorar alguns clientes, pois os contratos expiram 
mais rapidamente. Em outras palavras, o servidor muda dinamicamente para um modo de operação mais 
relaxado, descarregando-se assim para lidar com as solicitações com mais eficiência.
Difusão simples versus multicast
Relacionado ao envio ou recebimento de atualizações está a decisão de usar simplecast ou multicast. Na comunicação de 
transmissão simples, quando um servidor que faz parte do armazenamento de dados envia sua atualização para outros N servidores, 
ele faz isso enviando N mensagens separadas, uma para cada servidor. Com o multicast, a rede subjacente se encarrega de 
enviar com eficiência uma mensagem para vários destinatários.
Em muitos casos, é mais barato usar as ferramentas multicast disponíveis. Uma situação extrema é quando 
todos os espelhos estão na mesma rede local e o hardware de streaming está disponível. Nesse caso, transmitir ou 
fazer o multicast de uma mensagem não é mais caro do que uma única mensagem ponto a ponto. Então, 
simplesmente transmitir atualizações seria menos eficiente.
O multicast pode ser combinado de forma eficiente com um método baseado em push para propagar as atualizações. 
Quando os dois tipos de transmissão são cuidadosamente integrados, o servidor que decide enviar suas atualizações para 
outros servidores simplesmente usa um único grupo multicast para enviar suas atualizações. Em contraste, com um método 
baseado em pull, geralmente há apenas um cliente ou servidor solicitando a atualização de suacópia. Nesse caso, a 
difusão simples pode ser a solução mais eficiente.
306 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
7.5 PROTOCOLOS DE CONSISTÊNCIA
Até agora, nos concentramos principalmente em vários modelos de consistência e em questões gerais de design para 
protocolos de consistência. Nesta seção, nos concentramos na implementação real dos modelos de consistência, 
analisando vários protocolos de consistência. UMA protocolo de consistência descreve a implementação de um 
modelo de consistência específico. Continuaremos a organização de nossa discussão sobre modelos de consistência 
examinando primeiro os modelos centrados em dados e, em seguida, os protocolos para modelos centrados no 
cliente.
7.5.1 Consistência contínua
Como parte de seu trabalho de consistência contínua, Yu e Vahdat desenvolveram vários protocolos para abordar todas as 
três formas de consistência. A seguir, consideraremos brevemente várias soluções e, para maior clareza, pularemos os 
detalhes.
Limites para desvio numérico
Primeiramente, nos concentramos em uma solução para manter o desvio numérico limitado. Novamente, nosso objetivo 
não é entrar em detalhes para cada protocolo, mas dar uma ideia geral. Detalhes para limitar o desvio numérico podem 
ser encontrados em Yu e Vahdat (2000b).
Vamos nos concentrar em gravações em um único elemento de dados x. Cada escrita W (x) tem um peso 
associado que representa o valor numérico pelo qual x é atualizado e é indicado como ponderação (W (x)), ou 
simplesmente ponderação (W). Para simplificar, assumimos que
ponderação (W)> 0. Cada escrita W é inicialmente enviado para um dos N servidores de réplica disponíveis e, nesse 
caso, o referido servidor torna-se a fonte da escrita e é denotado como
origem (w). Se considerarmos o sistema em um momento específico, veremos vários escritos
enviado que ainda precisa se propagar para todos os servidores. Para este fim, cada servidor S Eu rastrear um registro eu Eu 
de gravações que você fez em sua própria cópia local do x.
Sean TW [i, j] as gravações executadas pelo servidor S Eu que se originou do servidor S j:
TW [i, j] = {peso (W) | origem (W) = S j & W ∈ eu Eu}
Observe que TW [i, j] representa o grupo de gravações enviadas para S Eu. Nosso objetivo é que para
qualquer tempo t, valor atual v Eu no servidor S Eu desvia dentro dos limites do valor real v (t) de x. Este valor real é 
completamente determinado por todas as gravações enviadas. Isto é
dizer sim v ( 0) é o valor inicial de x, tão
N
v (t) v ( 0) TW [k, k]
k 1
Y
SEÇÃO 7.5 PROTOCOLOS DE CONSISTÊNCIA 307
N
v Eu v ( 0) TW [i, k]
k 1
Observe que v Eu
vidor S Eu, nós associamos um limite superior Eu de modo que precisamos fazer cumprir que:
v (t)
v (t). Vamos nos concentrar apenas nos desvios absolutos. Em particular, para cada ser-
v Eu
Eu
Escritas enviadas para um servidor S Eu eles precisarão se propagar para todos os outros servidores. Existem diferentes 
maneiras de fazer isso, mas, em geral, um protocolo de epidemia permitirá
divulgação de atualizações. Em qualquer caso, quando um servidor S Eu propaga escrita originada de S j em direção a S k, o 
último será capaz de aprender o valor TW [i, j] no momento em que a escritura foi apresentada. Em outras palavras, S k pode 
manter um Visão TW k [ eu j] do que você pensa S Eu terá como valor para TW [i, j]. É evidente que,
0 TW [i, j] TW [j, j]TW k [ eu j]
A ideia é que quando o servidor S k avisar que S Eu não acompanhou as atualizações enviadas para S k, encaminha as 
escrituras de seu registro para S Eu. Este encaminhamento eficaz mexa-se a vista TW k [ i, k] o que S k tem de TW [i, k], fazendo 
o desvio pequeno TW [i, k]
TW k [ i, k]. Em particular, S k avance sua visão TW [i, k] quando um aplicativo envia um novo script que aumentaria TW 
[k, k] TW k [ i, k] além de S Eu / ( N 1). Deixamos isso como um exercício.
cício para mostrar que o avanço sempre garante que v (t) v Eu
Eu.
Limites para desvios descontinuados
Existem muitas maneiras de manter as réplicas descontinuadas dentro de limites específicos. Um método
simples é deixar o servidor S k segure um relógio vetorial em tempo real RVC k, Onde RVC k [ Eu]
Você) significa que S k vi todas as ações enviadas para S Eu ao tempo Você). Neste caso, assumimos que cada ação 
enviada é registrada por seu servidor de origem, e que Você) denota tempo
local no S Eu.
Se os relógios entre os servidores de réplica estiverem aproximadamente em sincronia, então
um protocolo aceitável para limitar a descontinuidade seria o seguinte. Sempre que o servidor S k
avisar que T (k) RVC k [ Eu] está prestes a exceder um limite especificado, basta começar
apresentar escritos que se originaram de S Eu com um carimbo de hora após RVC k [ Eu].
Observe que, neste caso, um servidor de réplica é responsável por manter seu
cópia de x em relação a ações que foram distribuídas em outro lugar. Por outro lado, quando os limites numéricos são 
mantidos, seguimos um método push que permite que um servidor de origem mantenha as réplicas atualizadas, 
encaminhando as gravações. O problema da inserção de escritas, no caso de descontinuidade, é que não há garantias de 
consistência quando não se sabe com antecedência qual será o spread máximo. Esta situação é um pouco melhorada 
com a extração de atualizações, pois vários servidores podem ajudar a manter a cópia das atualizações atualizadas 
(atualizadas) x de um servidor.
308
Limites para desvios de pedidos
CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
Lembre-se de que, na consistência contínua, os desvios de ordem são causados pelo fato de um servidor de réplica 
aplicar provisoriamente as atualizações que foram enviadas a ele. Como resultado, cada servidor terá uma fila local 
de gravações provisórias, para a qual a ordem em que serão aplicadas à cópia local do x ainda não foi determinado. O 
desvio de ordenação é limitado pela especificação do comprimento máximo da fila de gravações provisórias.
Portanto, detectar quando é necessário garantir a consistência do pedido é simples: quando o comprimento dessa 
fila local excede um comprimento máximo especificado. Nesse ponto, um servidor não aceitará mais gravações 
enviadas recentemente, mas concordará em confirmar gravações provisórias, negociando com outros servidores a 
ordem em que suas gravações devem ser executadas. Em outras palavras, precisamos impor uma ordenação global 
consistente de gravações provisórias. Há muitas maneiras de fazer isso, mas os protocolos também conhecidos como 
primários ou baseados em quorum são usados na prática. Explicaremos esses protocolos a seguir.
7.5.2 Protocolos de base primária
Na prática, vemos que os aplicativos distribuídos seguem modelos de consistência que são relativamente fáceis de 
entender. Esses modelos incluem aqueles que limitam o desvio de descontinuidade e, em menor medida, aqueles que 
limitam os desvios numéricos. Quando se trata de modelos que tratam da ordenação consistente de operações, ou 
consistência sequencial, os mais populares são aqueles em que as operações podem ser agrupadas por cadeados ou 
transações.
Assim que os modelos de consistência se tornam um pouco difíceis de serem entendidos pelos desenvolvedores 
de aplicativos, vemos que eles são ignorados, embora o desempenho possa ser melhorado. O resultado final é que, se a 
semântica de um modelo de consistência não for intuitivamente clara, os desenvolvedores terão dificuldade em construir 
aplicativos corretos. Simplicidade é muito apreciada (e talvez justificada).
No caso de consistência sequencial, verifica-se que prevalecem os protocolos baseados em primárias. Nestes 
protocolos, cada elemento de dados x O data warehouse tem um primário associado, que é responsável por coordenar as 
operações de gravação em x. É possível diferenciar se o primário está fixo em um servidor remoto ou se as operações de 
gravação podem ser realizadas localmente após mover o primário para o processo onde a operaçãode gravação foi 
iniciada. Vamos dar uma olhada nesses tipos de protocolos.
Protocolos de gravação remota
O protocolo mais simples de base primária que oferece suporte à replicação é aquele em que todas as operações de gravação 
precisam ser direcionadas a um único servidor fixo. Esses esquemas também são conhecidos como protocolos de backup 
primários ( Budhiraja et al., 1993). Um protocolo de backup primário funciona conforme mostrado na Figura 7-20. Um processo 
que espera para realizar uma operação de gravação em um item de dados x, encaminha essa operação para o servidor primário x.
SEÇÃO 7.5 PROTOCOLOS DE CONSISTÊNCIA 309
O primário realiza a atualização em sua cópia local do x, e então encaminha a atualização para os servidores de 
backup. Cada servidor de backup também executa a atualização e envia uma confirmação de volta ao primário. Quando 
todos os backups atualizam sua cópia local, o primário envia uma confirmação de volta ao processo inicial.
Cliente
Cliente
Servidor primário para
elemento x
Servidor de backup
W1 W5 R1 R2
W4 W4
W3 W3
Armazem de dados
W2 W3
W4
W1. Pedido de escrita
W2. Encaminha a solicitação para o principal
W3. Instrui backups para atualizar W4. Acusa a 
atualização
W5. Acusa a escritura consumada
R1. Leia a petição
R2. Resposta à leitura
Figura 7-20. Princípio de um protocolo de backup primário.
Um possível problema de desempenho com esse esquema é que pode levar muito tempo para que o 
processo que iniciou a atualização continue. Na verdade, uma atualização é implementada como uma operação 
de bloqueio. Uma alternativa é usar um método sem bloqueio. Assim que a escola primária atualizar sua cópia 
local do x, ele retorna uma confirmação; depois disso, ele instrui os servidores de backup a atualizarem também. 
Budhiraja e Marzullo (1992) explicam os principais protocolos de backup sem bloqueio.
O principal problema com os protocolos primários de backup sem bloqueio tem a ver com a tolerância a 
falhas. Em um esquema de bloqueio, o processo do cliente sabe com certeza que a operação de atualização é 
suportada por vários servidores. Este não é o caso de uma solução sem bloqueio. A vantagem, é claro, é que as 
operações de gravação podem ser incrivelmente rápidas. No próximo capítulo, retornaremos extensivamente às 
questões de tolerância a falhas.
Os protocolos primários de backup fornecem uma implementação direta de consistência sequencial, já que o 
primário pode classificar todas as gravações recebidas em uma ordem de tempo globalmente exclusiva. Obviamente, 
todos os processos veem todas as operações de gravação na mesma ordem, independentemente de qual servidor de 
backup eles usam para realizar as operações de leitura. Além disso, com protocolos de bloqueio, os processos sempre 
verão os efeitos de sua operação de gravação mais recente (observe que isso não pode ser garantido com um protocolo 
sem bloqueio sem tomar medidas especiais).
310
Protocolos de gravação locais
CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
Uma variante dos protocolos de backup primários é um protocolo no qual a cópia primária migra entre os processos que 
desejam executar uma operação de gravação. Como antes, sempre que um processo deseja atualizar o elemento x, localiza 
a cópia primária de x e então o leva para seu próprio local, conforme mostrado na Figura 7-21. A principal vantagem 
desse método é que várias operações sucessivas de gravação podem ser realizadas localmente, enquanto os 
processos de leitura ainda podem acessar sua cópia local. No entanto, essa melhoria só pode ser alcançada se um 
protocolo sem bloqueio for seguido por atualizações que são propagadas para as réplicas depois que o primário 
terminou de fazer as atualizações localmente.
Cliente
Pai anterior Novo pai do elemento x 
do elemento x
R1 R2 W1
Cliente
Servidor de backup
W3
W5 W5
W4 W4
Armazem de dados
W5 W2
W4
W1. Escreva o pedido
W2. Traga o elemento x para o novo W3 primário. Acusa 
a escritura consumada
W4. Instrui backups para atualizar W5. Acusa a 
atualização
R1. Leia a petição
R2. Resposta à leitura
Figura 7-21. Protocolo primário de backup em que o primário migra para o processo que deseja 
realizar uma atualização.
Este protocolo de backup de gravação local primário também pode ser aplicado a computadores móveis com 
capacidade de operação offline. Antes de desconectar, o computador móvel se torna o servidor primário para todos os 
itens de dados que deseja atualizar. Enquanto estiver desconectado, todas as operações de atualização são realizadas 
localmente para que outros processos ainda possam realizar operações de leitura (mas não atualizações). Então, 
quando fica online novamente, as atualizações se propagam do primário para os backups, trazendo o armazenamento 
de dados de volta a um estado consistente. No Capítulo 11, retornaremos à operação no modo desconectado quando 
discutirmos os sistemas de arquivos distribuídos.
Como uma variante final desse esquema, os protocolos baseados em primário de gravação local e sem 
bloqueio também são usados por sistemas de arquivos distribuídos em geral. Nesse caso, pode haver um servidor 
central fixo por meio do qual normalmente ocorrem todas as operações de gravação, como no caso do backup de 
gravação remoto primário. Sem
SEÇÃO 7.5 PROTOCOLOS DE CONSISTÊNCIA 311
Porém, temporariamente o servidor permite que uma das réplicas execute uma série de atualizações locais, pois isso 
pode aumentar significativamente o desempenho. Quando o servidor de réplica é encerrado, as atualizações são 
propagadas para o servidor central, de onde são distribuídas para os outros servidores de réplica.
7.5.3 Protocolos de gravação replicados
Em protocolos de gravação replicados, as operações de gravação podem ser realizadas em várias réplicas em vez de 
apenas uma, como no caso de réplicas baseadas em pai. É possível diferenciar entre replicação ativa, em que uma 
operação é encaminhada para todas as réplicas, e protocolos de consistência com base na maioria dos votos.
Replicação ativa
Na replicação ativa, cada réplica possui um processo associado que executa operações de atualização. Em contraste com 
outros protocolos, as atualizações geralmente são propagadas pela operação de gravação que causa a atualização. Em 
outras palavras, a operação é enviada para cada réplica. Porém, também é possível enviar a atualização, conforme 
explicamos anteriormente.
Um problema com a replicação ativa é que as operações devem ser feitas na mesma ordem em todos os lugares. 
Consequentemente, o que é necessário é um mecanismo multicast totalmente ordenado. Esse multicast pode ser 
implementado usando relógios lógicos Lamport, conforme explicamos no capítulo anterior. Infelizmente, esta 
implementação de multicast não se adapta bem em sistemas distribuídos. Alternativamente, o pedido total pode ser 
alcançado usando um coordenador central, também chamado sequenciador. Um método é primeiro encaminhar cada 
operação para o sequenciador, que atribui a ele um número de sequência exclusivo e, em seguida, encaminha a 
operação para todas as réplicas. As operações são realizadas na ordem de seus números de sequência. É claro que 
esta implementação multicast totalmente ordenada se assemelha muito aos protocolos de consistência baseados em 
primários.
Observe que o uso de um sequenciador não resolve o problema de escalabilidade. Na verdade, se o multicast 
totalmente ordenado for necessário, uma combinação de multicast simétrico usando registros de data e hora Lamport e 
sequenciadores também pode ser necessária. Essa solução é descrita em Rodrigues et al. (1996).
Protocolos baseados em quorum
Um método diferente para oferecer suporte a gravações replicadas é usar o voto como originalmente proposto por 
Thomas (1979) e generalizado por Gifford (1979). A ideia básica é exigir que os clientes solicitem e adquiram 
permissão de vários servidores antes de ler ou gravar um item de dadosreplicado.
Como um exemplo simples de como o algoritmo funciona, considere um sistema de arquivos distribuído e suponha que um 
arquivo seja replicado entre N servidores. Poderíamos implementar uma regra
312 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
que afirma que para atualizar um arquivo, um cliente deve primeiro contatar pelo menos metade dos servidores 
mais um (a maioria) e fazê-los concordar com a atualização. Quando eles concordam, o arquivo é alterado e um 
novo número de versão é associado ao arquivo resultante. O número da versão é usado para identificar a versão 
do arquivo e é o mesmo para todos os arquivos atualizados recentemente.
Para ler um arquivo replicado, um cliente também deve contatar pelo menos metade dos servidores mais um e 
solicitar que eles enviem os números de versão associados ao arquivo. Se todos os números de versão forem iguais, 
esta deve ser a versão mais recente, porque tentar atualizar apenas os servidores restantes falhará porque não há o 
suficiente.
Por exemplo, se houver cinco servidores e um cliente determinar que três deles são a versão 8, é impossível que os 
outros dois sejam a versão 9. Afinal, qualquer atualização bem-sucedida da versão 8 para a 9 requer que todos os três 
servidores concordo, e não apenas dois.
Na verdade, o esquema de Gifford é um pouco mais geral do que isso. Nele, para ler um arquivo do qual existe N réplicas, 
um cliente precisa reunir um lendo quorum, uma coleção qualquer-
quer de N R servidores ou mais. Da mesma forma, para modificar um arquivo, um o que-
escrever rum de pelo menos N W servidores. Os valores de N R Y N W estão sujeitos às duas restrições a seguir:
1 N R N W
N / 2
N
2 N W
A primeira restrição é usada para evitar conflitos de leitura e gravação, enquanto a segunda restrição evita conflitos de 
gravação e gravação. Somente após o número apropriado de servidores concordar em participar, um arquivo pode ser lido 
ou gravado.
Para ver como esse algoritmo funciona, considere a Figura 7-22 (a), na qual N R
10. Suponha que o quorum de gravação mais recente consista em 10 servidores, C para EU.
3 e
N W
Todos recebem a nova versão e o novo número da versão. Qualquer quorum de leitura
Os três servidores subsequentes terão que conter pelo menos um membro deste conjunto. Quando o cliente vir os 
números da versão, saberá qual é a mais recente e aceitará.
Nas Figuras 7-22 (b) e (c), vemos mais dois exemplos. Na Figura 7-22 (b) a
conflito escrever-escrever desde N W N / 2. Em particular, se um cliente escolher { A, B, C, E, F, G}
como seu conjunto de gravação e outro cliente escolhe { D, H, I, J, K, L} conforme sua definição de redação, então certamente 
cairemos no problema de que duas atualizações serão aceitas sem detectar que elas realmente estão em conflito.
A situação mostrada na Figura 7-22 (c) é especialmente interessante, pois estabelece N R em um, o que torna possível 
ler um arquivo replicado localizando qualquer cópia e usando-a. Contudo-
vá, o preço pago por esse bom desempenho de leitura é que as atualizações de leitura precisam adquirir todas as 
cópias. Este esquema, em geral, é conhecido como leia um, escreva tudo (ROWA, por suas siglas em inglês). Existem 
várias variantes de protocolos de replicação baseados em quorum. Uma boa visão geral é encontrada em Jalote (1994).
SEÇÃO 7.5 PROTOCOLOS DE CONSISTÊNCIA 313
Quorum de leitura
PARA B C D
PARA B C D PARA B C D
E F G H
E F G H E F G H
Eu J K eu
Eu J
N R = 7, N W = 6
Escrevendo quorum
K eu Eu J
N R = 1, N W = 12
K eu
N R = 3, N W = 10
(para) (b) (c)
Figura 7-22. Três exemplos do algoritmo de votação. (a) Escolha correta do conjunto de leitura e 
gravação. (b) Escolha que pode levar a conflitos de escrita-escrita. (c) Escolha correta, conhecida 
como ROWA (leia um, escreva tudo).
7.5.4 Protocolos de consistência de cache
Os caches são um caso especial de replicação, pois geralmente são controlados por clientes em vez de 
servidores. No entanto, os protocolos de coerência de cache, que garantem a consistência de cache com 
réplicas iniciadas pelo servidor, não são, em princípio, muito diferentes dos protocolos de consistência que 
explicamos até agora.
Muitas pesquisas são feitas hoje sobre o design e a implementação de caches, especialmente no contexto de 
sistemas de memória compartilhada multi-thread. Muitas soluções são baseadas no suporte do hardware subjacente, 
por exemplo, assumindo que a espionagem ou a multitransmissão podem ser realizadas. No contexto de sistemas 
distribuídos baseados em middleware que são construídos sobre sistemas operacionais de uso geral, as soluções 
baseadas em software são mais interessantes. Nesse caso, dois critérios separados são freqüentemente mantidos 
para classificar os protocolos pat-down (Min e Baer, 1992; Lilja, 1993; e Tartalja e Milutinovic, 1997).
Em primeiro lugar, as soluções de patch podem diferir em seus estratégia de detecção de consistência,
isto é, quando inconsistências são realmente detectadas. Em soluções estáticas, supomos que o compilador realiza a análise 
necessária antes da execução e para determinar efetivamente quais dados podem causar inconsistências porque podem ser 
armazenados em cache. O compilador simplesmente insere instruções que evitam inconsistências. Normalmente, as soluções 
dinâmicas são aplicadas nos sistemas distribuídos que discutimos aqui. Nessas soluções, inconsistências são detectadas em 
tempo de execução. Por exemplo, uma verificação é executada com o servidor para ver se os dados em cache foram 
modificados desde que foram armazenados em cache.
No caso de bancos de dados distribuídos, os protocolos baseados em descoberta dinâmica podem ser classificados 
posteriormente, considerando exatamente quando a descoberta ocorre durante uma transação. Franklin e outros (1997) 
diferenciam os três casos a seguir. Primeiro, quando um item de dados em cache é acessado durante uma transação, o 
cliente precisa verificar se
314 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
dito elemento de dados ainda é consistente com a versão armazenada em um servidor (possivelmente replicado). A 
transação não pode prosseguir com o uso da versão em cache até que sua consistência seja definitivamente 
validada.
Um segundo método otimista é permitir que a transação prossiga enquanto a verificação está ocorrendo. 
Nesse caso, presumimos que os dados em cache foram atualizados no início da transação. Se mais tarde essa 
suposição for falsa, a transação deverá ser abortada.
O terceiro método é verificar se os dados em cache estão atualizados apenas quando a transação é confirmada. 
Este método é comparável ao esquema otimista de controle de moeda explicado no capítulo anterior. Com efeito, a 
transação começa a operar diretamente nos dados em cache e simplesmente espera o melhor. Depois de todo o 
trabalho realizado, você verifica a consistência dos dados acessados. Quando dados antigos (descontinuados) são 
usados, a transação é abortada.
Outro problema de design com protocolos de coerência de cache é o estratégia de reforço de coerência, que 
determina o forma em que os caches são mantidos de acordo com o número de cópias armazenadas nos servidores. A 
solução mais simples é desativar todos os dados armazenados para serem armazenados em cache. Em vez disso, os 
dados compartilhados são mantidos apenas em servidores, que são mantidos consistentes usando um dos protocolos que 
explicamos anteriormente. Os clientes podem armazenar em cache apenas dados privados. Claro, esta solução só pode 
oferecer melhorias de desempenho limitadas.
Existem dois métodos para armazenar dados compartilhados em cache que reforçam a consistência do cache. O 
primeiro método é permitir que o servidor envie uma invalidação a todos os caches sempre que um item de dados for 
modificado. A segunda é simplesmente propagar a atualização. Muitos dos sistemas pat-down usam um desses dois 
esquemas. A escolha dinâmica entre enviar substituiçõesou atualizações às vezes é suportada por bancos de dados 
cliente-servidor (Franklin et al., 1997).
Por fim, também precisamos considerar o que acontece quando um processo modifica dados no cache. Quando 
caches somente leitura são usados, apenas os operadores podem executar operações de atualização, que 
subsequentemente seguem algum protocolo de distribuição para garantir que as atualizações sejam propagadas para os 
caches. Em muitos casos, uma abordagem baseada em pull é seguida. Nesse caso, um cliente detecta que seu cache foi 
descontinuado e solicita uma atualização do servidor.
Um método alternativo é permitir que os clientes modifiquem diretamente os dados armazenados em cache e 
encaminhem a atualização para os servidores. Este método de escrita é aplicado em escrever caches, que são 
freqüentemente usados em sistemas de arquivos distribuídos. Na verdade, o cache de gravação se assemelha ao 
protocolo de gravação local baseado em primário, onde o cache do cliente se torna um primário temporário. Para garantir a 
consistência (sequencial), o cliente deve receber permissões de gravação exclusivas, caso contrário, podem ocorrer 
conflitos de gravação / gravação.
Os caches de gravação oferecem uma melhoria potencial de desempenho em relação a outros esquemas quando 
todas as operações podem ser realizadas localmente. Podemos fazer mais melhorias, desacelerando a propagação das 
atualizações, permitindo que diferentes gravações ocorram antes de informar os servidores. Isso dá origem ao que é 
conhecido como cache pós-gravação, que, novamente, é aplicado principalmente em sistemas de arquivos distribuídos.
SEÇÃO 7.5 PROTOCOLOS DE CONSISTÊNCIA 315
7.5.5 Implementando consistência centrada no cliente
Em nosso último tópico sobre protocolos de consistência, vamos nos concentrar na implementação da consistência 
centrada no cliente. Implementar consistência centrada no cliente é relativamente simples se ignorarmos os problemas 
de desempenho. Nas páginas a seguir, descreveremos primeiro essa implementação, seguida por uma descrição de 
uma implementação mais realista.
Uma implementação simplista
Em uma implementação simplista de consistência centrada no cliente, para cada operação de gravação W é 
atribuído um identificador global exclusivo. O referido identificador é atribuído pelo servidor ao qual a escrita é 
solicitada. Como no caso de consistência contínua, nos referimos a este servidor como a origem de W. Portanto, 
para cada cliente, rastreamos dois conjuntos de gravações. O conjunto de leitura para um cliente consiste nas 
gravações importantes para as operações de leitura realizadas pelo cliente. Da mesma forma, o conjunto de 
gravações consiste em (identificadores de) gravações feitas pelo cliente.
A consistência de leitura monotônica é implementada da seguinte maneira. Quando um cliente executa uma 
operação de leitura em um servidor, o servidor manipula o conjunto de leituras do cliente para verificar se todas as 
gravações identificadas foram realizadas localmente. (O tamanho desse pool pode causar um problema de 
desempenho para o qual explicaremos uma solução mais tarde.) Caso contrário, antes de concluir a operação de 
leitura, ele contata os outros servidores para garantir que está atualizado. Como alternativa, a operação de leitura 
é encaminhada ao servidor onde as gravações foram realizadas. Uma vez que a operação de leitura foi realizada, 
as operações de gravação realizadas no servidor selecionado, e que são relevantes para a operação de leitura,
Observe que seria possível determinar exatamente onde as gravações identificadas foram realizadas no conjunto 
de leitura. Por exemplo, o identificador de gravação pode incluir o identificador do servidor para o qual a operação foi 
enviada. Esse servidor, por exemplo, é necessário para registrar a operação de gravação para que possa ser repetida 
em outro servidor. Além disso, as operações de gravação devem ser realizadas na ordem em que foram enviadas. A 
classificação pode ser feita permitindo que o cliente gere um número de sequência global exclusivo a ser incluído no 
identificador de gravação. Se cada item de dados só puder ser modificado por seu proprietário, o proprietário pode 
fornecer o número de sequência.
A consistência de escrita monotônica é implementada analogamente aos fabricantes monotônicos. Cada vez 
que um cliente inicia uma nova operação de gravação no servidor, o conjunto de gravações do cliente é transferido 
para o servidor. (Novamente, o tamanho do array pode ser proibitivamente grande para os requisitos de desempenho. 
Explicaremos uma solução alternativa mais tarde.) O servidor então garante que as operações de gravação 
identificadas sejam realizadas primeiro e na ordem correta. Depois de realizar a nova operação, o identificador da 
referida operação de gravação é adicionado ao conjunto de gravação. Observe que atualizar o servidor com o 
conjunto de gravação do cliente pode causar um aumento significativo no
316 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
tempo de resposta do cliente, pois o cliente então espera até que a operação seja totalmente concluída.
Da mesma forma, a leitura consistente de suas gravações requer que o servidor onde a leitura é realizada tenha 
visto todas as gravações no conjunto de gravações do cliente. As gravações podem simplesmente ser obtidas de 
outros servidores, antes que a operação de leitura seja executada, embora isso possa causar um tempo de resposta 
insatisfatório. Alternativamente, o software do lado do cliente pode procurar um servidor onde as operações de 
gravação identificadas no conjunto de gravação do cliente já foram realizadas.
Por último, as leituras de consistência após as gravações podem ser implementadas atualizando primeiro o 
servidor selecionado com as gravações realizadas no conjunto de leitura do cliente e, em seguida, adicionando o 
identificador da operação de gravação ao conjunto de gravação, junto com os identificadores no conjunto de 
leitura (que se tornou relevante para gravações realizadas recentemente).
Como melhorar a eficiência
É fácil ver que o conjunto de leitura / gravação associado a cada cliente pode se tornar muito grande. Para manter esses 
conjuntos gerenciáveis, as operações de leitura e gravação de um cliente são agrupadas em sessões. Normalmente um sessão 
está associado a um aplicativo: o aplicativo abre quando o aplicativo é iniciado e fecha quando termina. No entanto, as 
sessões também podem ser associadas a aplicativos interrompidos temporariamente, como agentes de usuário em 
e-mail. Cada vez que um cliente efetua logout, os conjuntos são simplesmente descarregados. Obviamente, se um 
cliente abrir uma sessão que nunca fecha, os conjuntos de leitura e gravação associados podem se tornar muito 
grandes.
O principal problema com a implementação simplista está na representação dos conjuntos de leitura e gravação. 
Cada conjunto consiste em vários identificadores para operações de gravação. Cada vez que um cliente encaminha 
uma solicitação de leitura ou gravação para um servidor, um conjunto de identificadores também é transmitido ao 
servidor para ver se todas as operações de gravação importantes para a solicitação foram realizadas naquele servidor.
Essas informações podem ser representadas de forma mais eficiente por registros de tempo vetoriais como segue. 
Primeiro, toda vez que um servidor aceita uma nova operação de gravação W, atribui um identificador único global a essa 
operação junto com o carimbo de data / hora ts (W).
Uma operação de gravação subsequente enviada para esse servidor recebe um registro de
hora de maior valor. Cada servidor S Eu mantém um registro vetorial de tempo WVC Eu, Onde
WVC Eu [ j] é igual ao carimbo de data / hora da operação de gravação mais recente originada de S j que foi processado por S Eu. 
Para fins de clareza, vamos supor que, para cada servidor, os scripts
turas de S j eles são processados na ordemem que foram enviados.
Sempre que um cliente envia uma solicitação para realizar uma operação de leitura ou gravação OU
em um servidor específico, esse servidor retorna seu carimbo de data / hora atual junto com os resultados de OU. Subseqüentemente, 
os conjuntos de leitura e gravação são representados por registradores de tempo vetoriais. Mais especificamente, para cada 
sessão PARA, nós criamos um registro de
tempo do vetor SVC PARA com SVC PARA[ Eu] igual ao tempo máximo de registro de todas as operações de gravação em PARA que 
se originam do servidor S Eu:
SEÇÃO 7.6 RESUMO 317
SVC PARA[ j]
Em outras palavras, o carimbo de data / hora de uma sessão sempre representa a última operação de gravação 
vista pelos aplicativos em execução como parte dessa sessão. A compactação é obtida representando todas as 
gravações observadas originadas do mesmo servidor por meio de um registro de data e hora simples.
Por exemplo, suponha que um cliente, como parte de uma sessão PARA, registra-se no servidor
S Eu. Para este fim, passe SVC PARA para S Eu. Suponha que SVC PARA[ j]> WVC Eu [ j]. O que isso significa é que S Eu
ainda não vi todas as escrituras originárias de S j, e que o cliente já viu. De acordo
com a consistência necessária, o servidor S Eu talvez seja necessário trazer esses scripts antes de obter uma 
resposta consistente do cliente. Assim que a operação for concluída, o
servidor S Eu retorna o carimbo de data / hora atual WVC Eu. Neste ponto, SVC PARA se encaixa como:
max { ts (W) | W ∈ A & origem (W) S j}
SVC PARA[ j] ← max { SVC PARA[ j], WVC Eu [ j]}
Novamente, vemos como os registros de tempo vetoriais podem fornecer uma maneira elegante e compacta de 
representar a história de um sistema distribuído.
7,6 RESUMO
Existem basicamente dois motivos para implementar a replicação de dados: para melhorar a confiabilidade de um sistema 
distribuído e para melhorar o desempenho. A replicação apresenta um problema de consistência: cada vez que uma réplica 
é atualizada, ela se torna diferente das outras réplicas. Para manter as réplicas consistentes, precisamos propagar as 
atualizações de forma que inconsistências temporais não sejam percebidas. Infelizmente, isso pode degradar gravemente o 
desempenho, especificamente em sistemas distribuídos de grande escala.
A única solução para esse problema é relaxar a consistência de alguma forma. Existem diferentes modelos 
de consistência. Para consistência contínua, o objetivo é estabelecer os limites para o desvio numérico entre as 
réplicas, o desvio da descontinuidade e os desvios na ordenação das operações.
O desvio numérico refere-se ao valor pelo qual as réplicas podem ser diferentes. Esse tipo de desvio é 
altamente dependente do aplicativo, mas pode, por exemplo, ser usado na replicação de ações. O desvio de 
descontinuidade se refere ao tempo em que uma réplica ainda é considerada consistente, embora as atualizações 
possam ter sido feitas há algum tempo. O desvio de descontinuidade é freqüentemente usado por caches da web. 
Finalmente, o desvio da ordem se refere ao número máximo de gravações provisórias que podem estar pendentes 
em qualquer servidor sem a necessidade de sincronização com os outros servidores de réplica.
A ordenação consistente das operações há muito constitui a base de muitos modelos de consistência. 
Existem muitas variantes, mas parece que apenas algumas prevalecerão entre os desenvolvedores de 
aplicativos. A consistência sequencial basicamente fornece a semântica que o programador espera na 
programação simultânea: todas as operações são
318 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
visto por todos na mesma ordem. Menos usada, mas ainda importante, é a consistência causal, que reflete que as 
operações potencialmente dependentes umas das outras são realizadas na ordem dessa dependência.
Modelos de consistência mais fracos consideram uma série de operações de leitura e gravação. Em particular, eles 
assumem que cada série está devidamente “entre colchetes” pelas operações que acompanham as variáveis de 
sincronização, na forma de cadeados. Embora isso exija um esforço explícito dos programadores, em geral, esses 
modelos são mais fáceis de implementar com eficiência do que, por exemplo, consistência de sequência pura.
Em oposição a esses modelos centrados em dados, os pesquisadores que trabalham na área de bancos de dados 
distribuídos para usuários móveis definiram vários modelos de consistência centrada no cliente. Tais modelos não 
consideram o fato de que os dados podem ser compartilhados por vários usuários; em vez disso, eles se concentram na 
consistência que deve ser oferecida a um cliente individual. A suposição subjacente é que um cliente se conecta a 
réplicas diferentes ao longo do tempo, mas que tais diferenças devem ser transparentes. Em essência, os modelos de 
consistência centrados no cliente garantem que, sempre que um cliente se conecta a uma nova réplica, essa réplica seja 
atualizada com dados que foram manipulados anteriormente por esse cliente e provavelmente residirão em outros sites 
de réplica.
Para propagar atualizações, diferentes técnicas podem ser aplicadas. Uma distinção precisa ser feita com relação 
a o que se espalha exatamente, para Onde as atualizações são propagadas e por quem a propagação começa. 
Podemos decidir propagar notificações, operações ou status. Além disso, nem toda réplica precisa ser atualizada 
imediatamente. Qual réplica é atualizada e quando depende do protocolo de distribuição. Finalmente, você pode 
escolher se as atualizações são enviadas por push para outras réplicas ou qual réplica puxa atualizações de outras 
réplicas.
Os protocolos de consistência descrevem implementações específicas de modelos de consistência. Com relação à 
consistência sequencial e suas variantes, é possível diferenciar entre protocolos primários e protocolos de gravação 
replicados. Em protocolos baseados em primários, todas as operações de atualização são roteadas para uma cópia 
primária, que subsequentemente garante que a atualização seja ordenada e encaminhada corretamente. Em protocolos 
de gravação replicados, uma atualização é encaminhada para várias réplicas ao mesmo tempo. Nesse caso, a 
ordenação adequada das operações torna-se mais difícil.
PROBLEMAS
1 O acesso a objetos Java compartilhados pode ser serializado declarando seus métodos como sincronizados.
zados. É o suficiente para garantir a serialização quando um objeto compartilhado é replicado?
2 Explique com suas próprias palavras qual é o principal motivo para considerar modelos de consistência.
fraco.
3 - Explique como ocorre a replicação no DNS e por que ela realmente funciona tão bem.
SEÇÃO 7.6 RESUMO 319
Quatro.Durante a discussão dos modelos de consistência, frequentemente nos referimos ao contrato entre o software e o data 
warehouse. Por que é necessário estabelecer tal contrato?
Dadas as réplicas na Figura 7-2, o que teríamos que fazer para finalizar os valores do conit de modo que ambos PARA Como 
B vê o mesmo resultado?
Na Figura 7-7, 001110 é uma saída legal para memória sequencialmente consistente? Explique sua resposta.
Costuma-se dizer que modelos de consistência fraca impõem uma carga adicional aos programadores. Até que ponto 
essa afirmação é verdadeira?
O multicast totalmente ordenado por meio de um sequenciador e em favor da consistência na replicação ativa viola o 
argumento de ponta a ponta do projeto de sistemas?
Que tipo de consistência você usaria para implementar um mercado de ações eletrônico? Explique sua resposta.
Considere uma caixa de correio eletrônica pessoal para um usuário móvel, implementada como parte de um banco de dados de 
área ampla distribuído. Que tipo de consistência centrada no cliente seria a melhor opção?
Descreva uma implementação simples de consistência, leia suas escrituras para exibir as páginas da web que acabaram de ser 
atualizadas.
Para manter as coisas simples, presumimos que não haviaconflitos de gravação e gravação em Bayou. Claro, esta é 
uma suposição irreal. Explique como os conflitos podem ocorrer.
Ao usar um contrato, os relógios do cliente e do servidor precisam estar razoavelmente bem sincronizados?
Estabelecemos que multicast totalmente ordenado usando relógios lógicos Lamport não é escalonável. Explique por 
quê.
Mostre que, no caso de consistência contínua, faça com que o servidor S k encaminhe sua visão
TW k ( i, k) desde que você receba uma atualização recente que aumentaria TW (k, k)
lá de Eu / N 1, garante que v (t)
Para consistência contínua, assumimos que cada gravação apenas incrementa o valor do elemento x. Descreva uma 
solução em que também seja possível diminuir o valor de x.
Considere um protocolo de backup sem bloqueio primário usado para garantir a consistência sequencial em um armazenamento de 
dados distribuído. Esse armazenamento de dados sempre fornece consistência na leitura de suas gravações?
Para que a replicação ativa funcione, em geral, todas as operações precisam ser realizadas na mesma ordem em 
cada réplica. Este pedido é sempre necessário?
Para implementar o multicast totalmente ordenado por meio de um sequenciador, um método é primeiro encaminhar uma 
operação para o sequenciador, que então atribui um número exclusivo a ele e, em seguida, multicast a operação. Cite dois 
métodos alternativos e compare as três soluções.
Um arquivo é replicado em 10 servidores. Liste todas as combinações de quorum de leitura e gravação que o 
algoritmo de votação permite.
5
6
7
8
9
10
onze.
12
13
14
quinze.
16
17
18
19
vinte.
TW k ( i, k) Mais
v Eu
Eu.
320 CAPÍTULO 7 CONSISTÊNCIA E REPLICAÇÃO
vinte e um.Os contratos baseados no estado são usados para descarregar um servidor, permitindo que você rastreie quantos clientes 
você precisar. Este método leva necessariamente a um melhor desempenho?
( Trabalho de casa para o laboratório.) Neste exercício, você implementará um sistema simples que suporta multicast RPC. 
Presumimos que haja vários servidores replicados e que cada cliente se comunique com um servidor usando RPC. No 
entanto, quando se trata de replicação, um cliente precisará enviar uma solicitação RPC para cada réplica. Programe o 
cliente de forma que pareça ao aplicativo como se apenas um RPC estivesse sendo enviado. Suponha que você esteja 
replicando para desempenho, mas os servidores são suscetíveis a falhas.
22
8
TOLERÂNCIA AO ERRO
Uma característica marcante dos sistemas distribuídos que os distingue dos sistemas de máquina única é a noção de 
falha parcial. Em um sistema distribuído, uma falha parcial pode ocorrer quando um componente falha. Essa falha 
pode afetar a operação de alguns componentes, enquanto outros não são afetados de forma alguma. Por outro lado, 
em um sistema não distribuído, uma falha geralmente é total no sentido de que afeta todos os componentes e pode 
facilmente derrubar o sistema.
Um objetivo importante no projeto de sistemas distribuídos é construí-los de forma que possam se recuperar 
automaticamente de falhas parciais sem afetar seriamente o desempenho geral. Em particular, sempre que ocorre uma 
falha, o sistema distribuído deve continuar a operar de forma aceitável enquanto os reparos estão sendo feitos, ou seja, 
deve tolerar falhas e continuar a operar em algum grau, mesmo na presença delas.
Neste capítulo, examinamos mais de perto as técnicas apropriadas para tornar os sistemas distribuídos tolerantes a 
falhas. Depois de fornecer alguns fundamentos gerais sobre tolerância a falhas, daremos uma olhada na atenuação do 
processo e na multitransmissão confiável. A atenuação de processo incorpora técnicas pelas quais um ou mais processos 
podem falhar sem perturbar seriamente o resto do sistema. Relacionado a este problema está a multitransmissão, graças 
à qual é garantida a transmissão bem-sucedida de uma mensagem a um conjunto de processos. A multitransmissão 
confiável geralmente é necessária para manter o processo sincronizado.
A atomicidade é uma propriedade importante em muitas aplicações. Por exemplo, em transações distribuídas, é 
necessário garantir que todas as operações envolvidas em um processo sejam realizadas ou que nenhuma seja 
realizada. A noção de protocolos de dedicação é fundamental
321
322 CAPÍTULO 8 TOLERÂNCIA AO ERRO
para implementar a atomicidade em sistemas distribuídos, e é apresentado em outra seção deste capítulo.
Por fim, examinaremos como se recuperar de uma falha. Em particular, quando e como o estado de um sistema 
distribuído deve ser salvo para recuperação posterior.
8.1 INTRODUÇÃO À TOLERÂNCIA DE FALHAS
A tolerância a falhas foi amplamente pesquisada na ciência da computação. Nesta seção, os conceitos básicos relacionados ao 
processamento de falhas são apresentados primeiro, seguidos por uma análise dos modelos de falhas. A principal técnica para 
gerenciamento de falhas é a redundância, que também estudamos. Para obter informações mais gerais sobre tolerância a 
falhas em sistemas distribuídos, consulte, por exemplo, Jalote (1994) ou (Shooman, 2002).
8.1.1 Conceitos básicos
Para entender a função da tolerância a falhas em sistemas distribuídos, primeiro você deve examinar minuciosamente o 
que realmente significa para um sistema distribuído tolerar falhas. Ser tolerante a falhas está fortemente relacionado ao 
que é chamado sistemas confiáveis. Confiabilidade é um termo que engloba vários requisitos úteis para sistemas 
distribuídos, incluindo os seguintes (Kopetz e Verissimo, 1993):
1. Disponibilidade
2. Confiabilidade
3. Segurança
4. Manutenção
Disponibilidade é definido como a propriedade de que um sistema está pronto para ser usado imediatamente. Em 
geral, refere-se à probabilidade de o sistema estar operando corretamente em um determinado momento e disponível 
para desempenhar suas funções em nome de seus usuários. Em outras palavras, um sistema altamente disponível é 
aquele que provavelmente funcionará a qualquer momento.
Confiabilidade refere-se à propriedade de um sistema ser capaz de operar continuamente sem falhas. Em 
contraste com a disponibilidade, a confiabilidade é definida com base em um intervalo de tempo, e não em um 
instante. Um sistema altamente confiável é aquele que provavelmente continuará a operar sem interrupção por um 
período de tempo relativamente longo. Esta é uma diferença sutil, mas importante, quando comparada à 
disponibilidade. Se um sistema quebrar por um milissegundo por hora, sua disponibilidade é mais do que
SEÇÃO 8.1 INTRODUÇÃO À TOLERÂNCIA DE FALHAS 323
99,9999 por cento, mas não confiável. Além disso, um sistema que nunca congela, mas para de funcionar por duas semanas todo 
mês de agosto, é altamente confiável, mesmo que esteja apenas 96% disponível. Essas duas situações não são iguais.
Segurança refere-se à situação em que nada catastrófico acontece quando um sistema para de funcionar 
adequadamente por um tempo. Por exemplo, muitos sistemas de controle de processo, como aqueles usados para 
controlar usinas nucleares ou enviar pessoas para o espaço sideral, são necessários para fornecer um alto grau de 
segurança. Se tais sistemas de controle falharem temporariamente por apenas um breve momento, os efeitos podem ser 
desastrosos. Muitos exemplos do passado (e provavelmente mais que ainda não aconteceram) demonstram como é difícil 
construir sistemas seguros.
finalmente, o manutenção refere-se à facilidade com que um sistema com falha pode ser reparado. Um sistema 
altamente sustentável também pode estar altamente disponível, especialmente se as falhas podem ser detectadas e 
reparadas automaticamente. No entanto, como você verá mais adiante neste capítulo, o failover automático é fácil de 
expressar, mas difícil de executar.
Freqüentemente, sistemas confiáveis também são necessários para fornecer um alto grau de segurança, especialmente 
quando se trata de questões como integridade. A segurança será discutidano próximo capítulo.
É dito que um sistema falha quando você não consegue cumprir suas promessas. Em particular, se um sistema 
distribuído é projetado para fornecer aos seus usuários vários serviços, o sistema falha quando um ou mais desses serviços 
não podem ser fornecidos (totalmente). UMA erro é uma parte do estado de um sistema que pode levar ao fracasso. Por 
exemplo, quando os pacotes são transmitidos por uma rede, é de se esperar que alguns cheguem danificados ao 
destinatário. Corrompido neste contexto significa que o destinatário pode detectar incorretamente um valor de bit (por 
exemplo, ler 1 em vez de 0), ou pode até ser incapaz de detectar que algo chegou.
A causa de um erro é chamada falha. Obviamente, descobrir a causa do erro é importante. Por exemplo, um 
meio de transmissão incorreto ou danificado pode facilmente danificar os pacotes. Nesse caso, é relativamente fácil 
eliminar a falha. No entanto, as condições meteorológicas também podem causar erros de transmissão, por exemplo, 
em redes sem fio. Mudar o clima para reduzir ou evitar erros é mais do que difícil.
Construir sistemas confiáveis tem muito a ver com controle de falhas. Uma distinção pode ser feita entre 
evitar, eliminar e prever falhas (Avizienis et al., 2004). Para nossos propósitos, a questão mais importante é a tolerância 
ao erro o que significa que um sistema pode fornecer seus serviços mesmo na presença de falhas. Em outras 
palavras, o sistema pode tolerá-los e continuar operando normalmente.
As falhas são geralmente classificadas como transitórias, intermitentes ou permanentes. As
falhas transitórias eles acontecem uma vez e depois desaparecem. Se a operação for repetida, a falha desaparece. Um pássaro 
voando através do feixe de sinal de um transmissor de micro-ondas pode causar a perda de bits em alguma rede (para não mencionar 
um pássaro assado). Se o fluxo for interrompido e for feita uma tentativa de restaurá-lo, provavelmente funcionará pela segunda vez.
UMA falha intermitente acontece, depois desaparece por si mesmo, depois reaparece e assim por diante. Um 
contato falso em um conector geralmente será a causa de uma falha intermitente. Falhas intermitentes causam uma 
série de problemas porque são difíceis de diagnosticar. Normalmente, quando o médico da falha aparece, o sistema 
funciona bem.
324 CAPÍTULO 8 TOLERÂNCIA AO ERRO
UMA falha permanente é aquele que continua a existir até que o componente defeituoso seja substituído. Chips 
queimados, erros de programa e quebras de cabeçote de leitura e gravação de disco são exemplos de falhas permanentes.
8.1.2 Modelos de falha
Um sistema com falha não fornece adequadamente os serviços para os quais foi projetado. Se você considerar um 
sistema distribuído como uma coleção de servidores que se comunicam entre si e com seus clientes, não fornecer os 
serviços adequadamente significa que os servidores, os canais de comunicação, ou possivelmente ambos, não estão 
fazendo o que deveriam. No entanto, um servidor com defeito nem sempre é a falha desejada. Se esse servidor depender 
de outros servidores para fornecer adequadamente seus serviços, a causa do erro deve ser encontrada em outro lugar.
Esses relacionamentos de dependência aparecem em abundância em sistemas distribuídos. Um disco com falha pode 
complicar a vida de um servidor de arquivos projetado para fornecer um sistema de arquivos altamente disponível. Se esse 
servidor de arquivos fizer parte de um banco de dados distribuído, o funcionamento adequado de todo o banco de dados pode 
ser comprometido, pois apenas uma parte de seus dados pode ser acessível.
Para se ter uma idéia melhor da gravidade de uma falha, vários esquemas de classificação foram 
desenvolvidos. Um deles é mostrado na Figura 8-1 e é baseado em esquemas descritos em Cristian (1991) e 
Hadzilacos e Toueg (1993).
Tipo de falha Descrição
Falha de congelamento
Falha de omissão
Omissão de recepção
Pular frete
Falha de tempo
Falha de resposta
Falha de valor
Falha de transição de estado O servidor desvia do fluxo correto de controle
Falha arbitrária Um servidor pode produzir respostas arbitrárias em momentos arbitrários
Um servidor para, mas funcionava corretamente até ser interrompido
Um servidor não responde às solicitações de entrada Um servidor 
não recebe mensagens de entrada Um servidor não envia 
mensagens
A resposta de um servidor está fora do intervalo de tempo especificado
A resposta de um servidor está errada O valor da 
resposta está errado
Figura 8-1. Diferentes tipos de falhas.
UMA falha de congelamento ocorre quando um servidor para prematuramente, mas que funcionava 
corretamente até então. Um aspecto importante das falhas de congelamento é que, depois que o servidor é 
interrompido, nada se sabe sobre ele. Um exemplo típico de falha
SEÇÃO 8.1 INTRODUÇÃO À TOLERÂNCIA DE FALHAS 325
Freeze é um sistema operacional que para repentinamente e para o qual existe apenas uma solução: reiniciá-lo. Muitos 
sistemas de computadores pessoais apresentam falhas de congelamento com tanta frequência que todos consideram isso 
normal. Consequentemente, a mudança do botão de reset da parte de trás do gabinete para a frente foi feita por um bom 
motivo. Talvez um dia ela possa ser deixada para trás ou até mesmo eliminada por completo.
UMA falha de omissão ocorre quando um servidor não atende a uma solicitação. Várias coisas podem estar erradas. No 
caso de uma falha de bypass, a solicitação possivelmente nunca foi obtida pelo servidor em primeiro lugar. Observe que pode 
muito bem ser o caso de a conexão entre um cliente e um servidor ter sido estabelecida corretamente, mas as solicitações de 
entrada não foram ouvidas. Além disso, uma falha de recebimento incorreto geralmente não afeta o estado atual do servidor, 
uma vez que ignora que uma mensagem foi enviada a ele.
Além disso, uma falha de envio incorreto ocorre quando o servidor fez seu trabalho, mas algo deu errado ao 
enviar uma resposta. Essa falha pode ocorrer, por exemplo, quando um buffer de envio está saturado e o servidor não 
estava preparado para lidar com isso. Observe que, em contraste com uma falha de ignorar recebimento, o servidor 
agora pode estar em um estado que reflete que acabou de concluir um serviço para o cliente. Consequentemente, se 
o envio de sua resposta falhar, o servidor deve estar preparado para que o cliente reenvie sua solicitação anterior.
Outros tipos de falhas de bypass que não estão relacionadas à comunicação podem ser causados por 
bugs de software, como loops infinitos ou gerenciamento de memória impróprio, para os quais o servidor 
“travou”.
Outra classe de falha tem a ver com o tempo. As falhas de tempo eles ocorrem quando a resposta fica fora 
de um intervalo de tempo real especificado. Como você viu no Capítulo 4, com fluxos de dados isócronos, 
fornecer dados muito cedo pode facilmente causar problemas para um destinatário se não houver espaço de 
buffer suficiente para conter todos os dados de entrada. Mais comum, entretanto, é um servidor responder tarde 
demais, caso em que ocorre uma falha. desempenho.
Um tipo sério de falha é um falha de resposta, onde a resposta do servidor está simplesmente errada. Podem 
ocorrer dois tipos de falhas de resposta. No caso de uma falha de valor, um servidor simplesmente responde da 
maneira errada a uma solicitação. Por exemplo, um mecanismo de pesquisa que retorna consistentemente páginas da 
web que não estão relacionadas a nenhum dos termos de pesquisa usados falhou.
O outro tipo de falha de resposta é conhecido como falha de transição de estado. Esse tipo de falha ocorre quando o 
servidor reage inesperadamente a uma solicitação recebida. Por exemplo, se um servidor receber uma mensagem que não pode 
reconhecer, uma falha de transição ocorrerá se as medidas apropriadas não forem tomadas para lidar com tais mensagens. Em 
particular, um servidor com defeito pode incorretamente executar ações predefinidasque nunca deveriam ter sido iniciadas.
Os mais sérios são falhas arbitrárias, também conhecido como Falhas bizantinas. Na realidade, quando 
ocorrem falhas arbitrárias, os clientes devem estar preparados para o pior. Em particular, muitas vezes acontece que 
um servidor produz uma saída que nunca deveria ter produzido, mas que não pode ser detectada como incorreta. Pior 
ainda, um servidor com defeito pode até mesmo estar trabalhando de forma maliciosa com outros servidores para 
produzir respostas erradas intencionalmente. Esta situação ilustra porque a segurança também é considerada
326 CAPÍTULO 8 TOLERÂNCIA AO ERRO
um requisito importante quando se trata de sistemas confiáveis. O termo "Bizantino" refere-se ao Império 
Bizantino, uma época (330-1453) e um lugar (os Bálcãs e a Turquia moderna) onde infindáveis conspirações, 
intrigas e desconfiança eram uma ocorrência diária nos círculos governamentais. . As falhas bizantinas foram 
analisadas pela primeira vez por Pease et al. (1980) e Lamport et al. (1982). Voltaremos ao assunto mais tarde.
As falhas arbitrárias estão intimamente relacionadas às falhas de congelamento. Definir as falhas de 
congelamento conforme apresentado acima é a maneira mais benigna de parar um servidor. Eles também são 
conhecidos como parar as falhas. Na verdade, um servidor que sofre esse tipo de falha simplesmente para de 
produzir uma saída de forma que sua parada possa ser detectada por outros processos. Na melhor das hipóteses, 
o servidor pode ter sido tão amigável para avisar que estava prestes a congelar - caso contrário, ele simplesmente 
para.
É claro que, na vida real, os servidores são parados por omissão ou congelamento e não avisam com 
antecedência que vão parar. Cabe a outros processos decidir se um servidor parou prematuramente. No entanto, em tal sistemas 
silenciosos, o servidor pode ficar inesperadamente lento, ou seja, apresentar falhas de desempenho.
Finalmente, também há momentos em que o servidor produz uma saída aleatória, embora essa saída possa ser 
reconhecida por outros processos como lixo simples. O servidor então exibe travamentos arbitrários, mas de uma forma 
benigna. Essas falhas também são conhecidas como
à prova de falhas.
8.1.3 Disfarçando falhas por redundância
Para que um sistema seja tolerante a falhas, o melhor que pode ser feito é tentar ocultar a ocorrência de falhas de outros 
processos. A técnica chave para disfarçar falhas é usar redundância. Três classes são possíveis: redundância de 
informação, redundância de tempo e redundância física [ver também Johnson (1995)]. Com a redundância de informações, 
bits extras são adicionados para recuperar os bits ilegíveis. Por exemplo, um código de Hamming pode ser adicionado aos 
dados transmitidos para recuperá-los do ruído presente na linha de transmissão.
Com redundância de tempo, uma ação é executada e, se necessário, é executada novamente. As transações 
(consulte o Capítulo 1) usam esse método. Se uma transação for abortada, ela pode ser refeita sem danos. A 
redundância de tempo é especialmente útil quando as falhas são transitórias e intermitentes.
Com a redundância física, equipamentos ou processos adicionais são adicionados para que o sistema como um todo 
tolere a perda ou mau funcionamento de alguns componentes. A redundância física pode então ser realizada em hardware 
ou software. Por exemplo, processos adicionais podem ser adicionados ao sistema para que, se algum travar, o sistema 
possa continuar a funcionar corretamente. Em outras palavras, a replicação de processos atinge um alto grau de tolerância 
a falhas. Voltaremos a esse tipo de redundância de software mais tarde.
A redundância física é uma técnica bem conhecida de criação de tolerância a falhas. É usado em biologia (os 
mamíferos têm dois olhos, duas orelhas, dois pulmões, etc.), aeronáutica (o
SEÇÃO 8.1 INTRODUÇÃO À TOLERÂNCIA DE FALHAS 327
Aeronaves 747 têm quatro motores, mas podem voar com três) e esportes (vários árbitros no caso de um perder 
um evento). A tolerância a falhas também é usada em circuitos eletrônicos há anos: é muito ilustrativo analisar 
como tem sido aplicada nesse campo. Considere, por exemplo, o circuito da Figura 8-2 (a). Sinais passam por 
dispositivos A, B Y C, em sequência. Se um dispositivo falhar, o resultado final provavelmente estará errado.
PARA B C
(para)
Eleitor
A1 V1 B1 V4 C1 V7
A2 V2 B2 V5 C2 V8
A3 V3 B3 V6 C3 V9
(b)
Figura 8-2. Redundância modular tripla.
Na Figura 8-2 (b), cada dispositivo é replicado três vezes. Após cada etapa do circuito, há um eleitor triplicado. 
Cada eleitor é um circuito que possui três entradas e uma saída. Se duas ou três das entradas são iguais, a saída é 
igual a essa entrada. Se as três entradas forem diferentes, a saída é indefinida. Esta classe de design é conhecida 
como TMR ( Modular Triplo
Redundância; redundância modular tripla).
Suponha que o elemento falhe PARA 2 Cada um dos eleitores V 1, V 2 Y V 3 obtém duas entradas boas (idênticas) e 
uma maliciosa, e cada entrada passa o valor correto para o segundo
etapa. Em essência, o efeito do PARA 2 está completamente disfarçado, para que as entradas para B 1, B 2 Y B 3 são 
exatamente as mesmas como se nenhuma falha tivesse ocorrido.
Agora vamos considerar o que acontece se B 3 Y C 1 também falham, além de PARA 2 Esses efeitos também são disfarçados, 
de modo que as três saídas finais ainda estão corretas.
A princípio, pode não ser óbvio por que três eleitores são necessários em cada estágio. Afinal, um eleitor 
também pode detectar e passar na inspeção da maioria. No entanto, o eleitor também é um componente e 
também pode falhar. Suponha, por exemplo, que o
tante V 1 funciona mal. Entrada para B 1 Ela estará errada então, mas enquanto todo o resto funcionar, B 2 Y B 3 irá produzir a 
mesma saída e V 4, V 5 Y V 6 eles enviarão o resultado correto para o estágio três. Uma falha em V 1 efetivamente não é diferente 
de uma falha em B 1 Em ambos os casos B 1
328 CAPÍTULO 8 TOLERÂNCIA AO ERRO
produz saída incorreta, mas em ambos os casos é rejeitada e o resultado final permanecerá correto.
Embora nem todos os sistemas distribuídos tolerantes a falhas usem TMR, a técnica é muito geral e deve nos 
dar uma boa idéia do que é um sistema tolerante a falhas, ao contrário de um sistema cujos componentes 
individuais são altamente confiáveis, mas cuja organização não pode. tolerar falhas (ou seja, operar corretamente, 
mesmo na presença de componentes com defeito). É claro que a redundância modular tripla pode ser aplicada 
repetidamente, por exemplo, para tornar um chip altamente confiável com redundância modular tripla interna, sem 
que os projetistas o utilizem sabendo, possivelmente em seu próprio circuito contendo várias cópias. fichas junto 
com os eleitores.
8.2 ATENUAÇÃO DE UM PROCESSO
Agora que as questões básicas de tolerância a falhas foram abordadas, vamos ver como a tolerância a falhas pode realmente ser 
alcançada em sistemas distribuídos. O primeiro problema a ser resolvido é a proteção contra falhas de processo, que é obtida 
replicando processos em grupos. Nas páginas a seguir, consideramos questões gerais de projeto de grupos de processos e 
discutimos o que realmente é um grupo tolerante a falhas. Além disso, vemos como chegar a um acordo dentro de um grupo de 
processos quando um ou mais de seus membros não são confiáveis para dar as respostas corretas.
8.2.1 Temas de design
A principal forma de lidar com a tolerância a falhas de processo é organizar vários processos idênticos em um grupo. 
A propriedade fundamental de todos os grupos é que, quando uma mensagem é enviada ao grupo, todos os 
membros do grupo a recebem. Dessa forma, se um processo falha em um grupo, felizmente um dos outros 
processos pode assumir (Guerraoui e Schiper, 1997).
Os grupos de processos podem ser dinâmicos. Você pode criar novos grupos e destruir os antigos. Um processo pode 
ingressar ou sair de um grupodurante a operação do sistema. Um processo pode ser membro de vários grupos ao mesmo 
tempo. Conseqüentemente, mecanismos adequados são necessários para gerenciar grupos e membros do grupo.
Os grupos são mais ou menos como organizações sociais. Alice pode ser membro de um clube do livro, um clube 
de tênis e uma organização ecológica. Em um determinado dia, você pode receber e-mails (mensagens) para informá-lo 
sobre um novo livro de confeitaria do clube do livro, um torneio de tênis do clube de tênis Dia das Mães e o início de 
uma campanha para salvar a marmota. organização ecológica do sul. A qualquer momento, Alice está livre para deixar 
qualquer um ou todos esses grupos e possivelmente ingressar em outros.
O objetivo da introdução de grupos é permitir que os processos lidem com conjuntos de processos como uma 
única abstração. Portanto, um processo pode enviar uma mensagem a um grupo de servidores sem ter que saber quais 
ou quantos existem ou onde estão, o que pode mudar de uma chamada para a próxima.
SEÇÃO 8.2 ATENUAÇÃO DE UM PROCESSO 329
Grupos de 4 companheiros contra grupos hierárquicos
Uma distinção importante entre os diferentes grupos tem a ver com sua estrutura interna. Em alguns, todos os processos 
são iguais; Ninguém está no comando e todas as decisões são tomadas coletivamente. Em outros grupos, existe algum tipo 
de hierarquia. Por exemplo, um processo é o coordenador e os outros são trabalhadores. Nesse modelo, quando um cliente 
externo ou um dos trabalhadores gera uma solicitação de emprego, ela é enviada ao coordenador. O coordenador então 
decide qual dos trabalhadores é o mais adequado para fazer o trabalho e o envia para lá. Hierarquias mais complexas 
também são possíveis, é claro. Esses padrões de comunicação são ilustrados na Figura 8-3.
Grupo simples
Grupo hierárquico
Coordenador
Empregado
(para) (b)
Figura 8-3. ( a) Comunicação em grupo simples. (b) Comunicação em um grupo hierárquico 
simples.
Cada uma dessas organizações tem suas próprias vantagens e desvantagens. O grupo de pares é simétrico e não 
possui um único ponto de falha. Se um dos processos congelar, o grupo fica menor, mas pode continuar de outra forma. 
Uma desvantagem é que a tomada de decisões é mais complicada. Por exemplo, para decidir qualquer coisa, muitas 
vezes você tem que colocar em votação, o que implica em atrasos e custos indiretos.
O grupo hierárquico possui as propriedades opostas. A perda do coordenador faz com que todo o grupo pare 
abruptamente, mas enquanto ele está em andamento você pode tomar decisões sem perturbar ninguém.
Associação a um grupo
Quando há comunicação em um grupo, algum método é necessário para criar e excluir grupos, bem como permitir 
que processos ingressem ou saiam de grupos. Um método possível é ter um servidor de grupo para o qual todas 
essas solicitações podem ser enviadas. O servidor de grupo pode então manter um banco de dados completo para 
todos os grupos e seus
330 CAPÍTULO 8 TOLERÂNCIA AO ERRO
adesão exata. Este método é simples, eficiente e bastante fácil de implementar. Infelizmente, ele compartilha uma grande 
desvantagem com todas as técnicas centralizadas: um único ponto de falha. Se o servidor do grupo congelar, o 
gerenciamento do grupo deixará de existir. Provavelmente, a maioria ou todos os grupos terão que ser reconstruídos do 
zero, talvez encerrando qualquer trabalho que esteja sendo feito.
O método oposto é gerenciar os membros de forma distribuída. Por exemplo, se a multitransmissão (confiável) estiver 
disponível, um estranho pode enviar uma mensagem a todos os membros do grupo para comunicar seu desejo de ingressar 
no grupo.
O ideal é que, para sair de um grupo, um membro simplesmente envie uma mensagem de adeus a todos. No contexto 
de tolerância a falhas, a suposição de semântica de interrupção de falha geralmente não é apropriada. O problema é que 
não há aviso educado de que o processo congelou como ocorre quando um processo é encerrado voluntariamente. Os 
outros membros têm que descobrir isso experimentalmente quando percebem que o membro congelado não está mais 
respondendo a nada. Assim que tivermos certeza de que o membro está realmente travado (e não apenas lento), podemos 
removê-lo do grupo.
Outro problema intrincado é que o drop and join deve ser sincronizado com as mensagens de dados enviadas. Ou 
seja, a partir do momento em que um processo entra em um grupo, ele deve receber todas as mensagens enviadas ao 
grupo. Além disso, assim que um processo sai do grupo, ele não deve mais receber mensagens do grupo e outros 
membros não devem receber mais mensagens dele. Uma maneira de garantir que uma entrada ou saída seja integrada ao 
fluxo de mensagens no local apropriado é converter essa operação em uma sequência de mensagens enviadas para todo o 
grupo.
Uma questão final relacionada à associação ao grupo é o que fazer quando muitas máquinas são desligadas de tal 
forma que o grupo não pode mais funcionar. Requer um protocolo para reconstruí-lo. Invariavelmente, algum processo terá 
que tomar a iniciativa de colocar a bola em jogo, mas o que acontece se dois ou três processos tentarem fazê-lo ao mesmo 
tempo? O protocolo deve ser capaz de suportá-lo.
8.2.2 Máscara de falha e replicação
Os grupos de processos são parte da solução implementada para construir sistemas tolerantes a falhas. Em particular, ter um 
grupo de processos idênticos torna possível disfarçar um ou mais processos defeituosos presentes naquele grupo. Em outras 
palavras, podemos replicar os processos e organizá-los em um grupo para substituir um único processo (vulnerável) por um 
grupo de processos (tolerante a falhas). Conforme visto no capítulo anterior, há duas maneiras de lidar com a replicação: por 
meio de protocolos baseados em um protocolo primário ou por meio de protocolos de gravação replicados.
A replicação com base em um protocolo primário, no caso de tolerância a falhas, geralmente aparece na forma de 
um protocolo de backup primário. Assim, um grupo de processos é organizado de forma hierárquica, em que um 
protocolo primário coordena todas as operações de gravação. Na prática, o primário é fixo, embora sua função possa ser 
assumida por um dos backups, se necessário. Na realidade, quando o primário congela, os backups executam algum 
algoritmo de sua escolha para selecionar um novo primário.
SEÇÃO 8.2 ATENUAÇÃO DE UM PROCESSO 331
Conforme explicamos no capítulo anterior, os protocolos de gravação replicados são usados na forma de replicação 
ativa, bem como por meio de protocolos baseados em quorum. Essas soluções correspondem a organizar um conjunto de 
processos idênticos em um grupo simples. A principal vantagem é que esses grupos não possuem um único ponto de 
falha, devido à coordenação distribuída.
Uma questão importante com o uso de grupos de processos para tolerar falhas é a quantidade de replicação 
necessária. Para simplificar a análise, consideraremos apenas os sistemas de escrita replicados. É dito que um sistema é 
tolerante a falhas se você pode sobreviver às falhas de k componentes e continuar a atender às suas especificações. 
Se componentes, por exemplo processos, falham silenciosamente, é suficiente ter k 
1 deles para fornecer tolerância
k às falhas. sim k dos componentes apenas param, podemos usar a resposta do outro componente.
Por outro lado, se os processos exibirem falhas bizantinas e continuarem funcionando e enviando respostas erradas ou 
aleatórias, um mínimo de 2 é necessário k 1 processador para alcançar
tolerância para k falhas. Na pior das hipóteses, k Os processos que falham acidentalmente (ou intencionalmente a 
longo prazo) podem gerar a mesma resposta. Contudo, k 1 processos
os restantes também darão a mesma resposta, de modo que o cliente ou o eleitor só podem acreditar na maioria.
Claro, em teoria, é bom dizer que um sistema é tolerante com k falhar e deixar o k
respostas idênticas votam contra k respostas idênticas,mas na prática é difícil imaginar circunstâncias em que se 
possa afirmar com certeza que k processos podem falhar, mas k 1
não. Portanto, mesmo em um sistema tolerante a falhas, algum tipo de análise estatística pode ser necessária.
Uma pré-condição implícita relevante para este modelo é que todas as solicitações cheguem a todos os 
servidores na mesma ordem, também é chamado problema de multitransmissão atômica. Na verdade, essa 
condição pode ser atenuada um pouco, já que as operações de leitura não importam e algumas gravações 
podem ser trocadas, mas o problema geral permanece. A multitransmissão atômica é discutida em detalhes em 
uma seção posterior.
1
8.2.3 Acordo sobre sistemas defeituosos
Organizar processos replicados em um grupo aumenta a tolerância a falhas. Como já mencionamos, se um cliente 
pode basear suas decisões em um mecanismo de votação, pode até ser tolerado que k de 2 k 
1 processos mentem sobre seu resultado. A suposição feita,
no entanto, é que os processos não se agrupam para produzir o resultado errado.
Em geral, as coisas ficam complicadas quando um grupo de processos é necessário para chegar a um acordo, o 
que é necessário em muitos casos. Alguns exemplos são: a escolha de um coordenador, a decisão de realizar ou não 
uma transação, a divisão de tarefas entre os trabalhadores e a sincronização, entre muitas outras possibilidades. Quando 
todos os processos e comunicação são perfeitos, chegar a esse acordo geralmente é simples, mas quando não são, 
surgem problemas.
332 CAPÍTULO 8 TOLERÂNCIA AO ERRO
O objetivo geral dos algoritmos de concordância distribuída é fazer com que todos os processos sem falhas 
cheguem a um consenso sobre alguma questão e estabelecer esse consenso em um número finito de etapas. O 
problema é agravado pelo fato de que diferentes suposições sobre o sistema subjacente exigem soluções diferentes, 
mesmo supondo que existam soluções. Turek e Shasha (1992) distinguem os seguintes casos.
1. Sistemas síncronos contra sistemas assíncronos. Um sistema é síncrono sim e só sim,
os processos são conhecidos por operar em etapas. Formalmente, isso significa que deve haver uma constante c 
1, então, se algum processo levou c 1 passo, todos
os outros processos terão realizado pelo menos 1 etapa. Diz-se que um sistema não
crono é assíncrono.
2. O atraso de comunicação é ou não limitado. O atraso é limitado se, e somente se, cada mensagem for 
conhecida por ser entregue com um tempo máximo globalmente predeterminado.
3. A entrega das mensagens é feita ou não em ordem. Por outras palavras, é possível distinguir uma situação em 
que as mensagens do mesmo remetente são entregues pela ordem em que foram enviadas, de uma situação 
em que não existem tais garantias.
4. As mensagens são transmitidas por transmissão única ou multitransmissão.
Acontece que chegar a um acordo só é possível na situação mostrada na Figura 8-4. Em todos os outros casos, 
pode-se demonstrar que não há solução. Observe que a maioria dos sistemas distribuídos pressupõe que os 
processos se comportam de forma assíncrona, que as mensagens são transmitidas pela transmissão da unidade e que 
os atrasos na comunicação não são limitados. Conseqüentemente, a entrega de mensagens ordenada (confiável), 
conforme fornecida pelo TCP, deve ser usada. A Figura 8-4 ilustra a natureza não trivial do acordo distribuído quando 
os processos podem falhar.
O problema foi originalmente estudado por Lamport et al. (1982) e também é conhecido como Problema 
de acordo bizantino, no que se refere a numerosas guerras nas quais vários exércitos tiveram que chegar a 
um acordo, por exemplo, reforçando as tropas enquanto lutavam com generais traiçoeiros, tenentes coniventes 
e assim por diante. Considere a seguinte solução, descrita em Lamport et al. (1982). Neste caso, assumimos 
que os processos são síncronos, que as mensagens são enviadas por transmissão da unidade enquanto a 
ordem é preservada e que o atraso de comunicação é delimitado. É para existir
ter N processos, onde cada processo Eu fornecerá um valor v Eu Aos demais. O objetivo é permitir que cada processo crie um 
vetor V de comprimento N, então se o processo Eu não está com defeito,
Serra] v Eu. Pelo contrário, Serra] é indefinido. Presumimos que haja no máximo k processos defeituosos.
A Figura 8-5 ilustra a operação do algoritmo para o caso de N 4 e k 1. Com
esses parâmetros, o algoritmo opera em quatro etapas. Na etapa 1, cada processo Eu não com defeito
enviar v Eu a todos os outros processos por transmissão de unidade confiável. Processos defeituosos
SEÇÃO 8.2 ATENUAÇÃO DE UM PROCESSO 333
Classificando as mensagens
Não encomendado Organizado
X
X
X
X
Macaco-
Limitado
Ilimitado
Limitado
Ilimitado
Síncrono
X X
X
Multi-
Assíncrono
Macaco-
transmitido transmitido transmitido transmitido
Multi-
Transmissão de mensagens
Figura 8-4. Circunstâncias em que o acordo distribuído pode ser alcançado.
eles podem enviar qualquer coisa. Além disso, como estamos usando multi-streaming, você pode enviar
valores diferentes para processos diferentes. Estar v Eu Eu. A Figura 8-5 (a) mostra que o Processo 1
relatórios 1, 2 relatórios 2, 3 mentiras para todos, envia-os x, y Y z, respectivamente, e o Processo 4 reporta um valor de 4. 
Na Etapa 2, os resultados dos anúncios da Etapa 1 são montados na forma dos vetores na Figura 8-5 (b).
2
1 2
1
2
1
4
Y
1
x
6 4
1 Obtido (1, 2, x, 4) 2 
Obtido (1, 2, y, 4) 3 
Obtido (1, 2, 3, 4) 4 
Obtido (1, 2, z, 4)
1 obtido
(1, 2 e 4)
(a, b, c, d)
(1, 2, z, 4)
2 obtido
(1, 2, x, 4) (1, 2, x, 4) (e, f, g, 
h) (1, 2, y, 4) (1, 2, z, 4) (i, j, 
k, l)
3 obtidos
4
z
3 4
Processo defeituoso
(para) (b) (c)
Figura 8-5. Problema de acordo bizantino de três processos não falhos e um falho. (a) Cada 
processo envia seu valor para os outros. (b) Os vetores que cada processo monta com base em 
(a). (c) Os vetores que cada processo recebe na etapa 3.
Na etapa 3, cada processo transfere seu vetor da Figura 8-5 (b) para todos os outros processos. Desta forma, cada 
processo obtém três vetores, um de cada processo. Neste caso, também, o processo 3 mente e inventa 12 novos valores, para 
para eu. Os resultados da etapa 3 aparecem na Figura 8-5 (c). Finalmente, na etapa 4, cada processo examina o elemento Eu-
th de cada um dos
A
tra
s
o
 n
a
 c
o
m
u
n
ic
a
ç
ã
o
C
o
m
p
o
rt
a
m
e
n
to
 d
e
 u
m
 p
ro
c
e
s
s
o
334 CAPÍTULO 8 TOLERÂNCIA AO ERRO
vetores recém-recebidos. Se algum valor tiver maioria, esse valor é colocado no vetor de resultado. Se nenhum valor 
tiver maioria, o elemento correspondente do vetor de resultado é marcado
através DESCONHECIDO. Na Figura 8-5 (c), vemos que 1, 2 e 4 concordam com os valores de v 1, v 2
Y v 4, qual é o resultado correto. O que esses processos concluem sobre v 3 não pode ser decidido, embora também 
não seja relevante. O objetivo do acordo bizantino é chegar a um
sentido quanto ao valor de apenas processos não defeituosos.
Voltaremos agora a este problema com N 3 e k 1, ou seja, apenas dois processos não defeituosos
tuoso e um se, conforme ilustrado na Figura 8-6. Neste caso, vemos que na Figura 8-6 (c) nenhum dos processos que estão se 
comportando corretamente vê uma maioria para o elemento 1, elemento 2 ou elemento 3, portanto, todos estão marcados como DESCONHECIDO. 
O algoritmo não permitiu que um acordo fosse alcançado.
1
1 2
x
1
2
3 2
1 Obtido (1, 2, x) 2 
Obtido (1, 2, y) 3 
Obtido (1, 2, 3)
(b)
1 obtido
(12 e)
(a, b, c)
2 obtido
(1, 2, x)
(d, e, f)
Y
Processo defeituoso
(para) (c)
Figura 8-6. O mesmo que na Figura 8-5, exceto que agora existem dois processos bons e um 
processo ruim.
Em seu artigo, Lamport et al. (1982) mostraram que em um sistema com k processos defeituosos, o acordo pode ser 
alcançado apenas se 2 estiverem presentes k 1 processo em execução
nadar corretamente, para um total de 3 k 1. Em outras palavras, o acordo só é possívelse
Mais dois terços dos processos estão funcionando corretamente.
Outra maneira de encarar esse problema é a seguinte. Basicamente, o que precisamos alcançar é uma votação majoritária 
entre um grupo de processos não defeituosos, independentemente de haver também processos defeituosos entre eles. Se há k processos 
defeituosos, deve-se assegurar que o seu voto, juntamente com o de quaisquer processos corretos que tenham sido enganados 
pelos defeituosos, continue a corresponder à maioria dos votos dos processos não defeituosos. Com 2 k 
1 processo não
defeituoso, isso pode ser alcançado exigindo que um acordo seja alcançado somente se mais de dois terços dos votos 
forem iguais. Ou seja, se mais de dois terços dos processos concordarem com a mesma decisão, essa decisão 
corresponderá à mesma maioria dos votos do grupo dos processos não defeituosos.
No entanto, chegar a um acordo pode ser ainda pior. Fischer et al. (1985) mostraram que em um sistema 
distribuído no qual não pode ser garantido que as mensagens serão enviadas dentro de um tempo finito conhecido, 
não é possível chegar a um acordo se mesmo um processo for defeituoso (mesmo quando tal processo tiver falhou 
silenciosamente). O problema com
SEÇÃO 8.2 ATENUAÇÃO DE UM PROCESSO 335
sistemas como esse é que processos arbitrariamente lentos são indistinguíveis de processos congelados (ou seja, você 
não pode diferenciar ocioso de ativo). Muitos outros resultados teóricos são conhecidos sobre quando um acordo é ou não 
possível. Esses resultados são estudados em Barborak et al. (1993) e Turek e Shasha (1992).
É importante notar que os esquemas descritos até agora assumem que os nós são ou bizantinos ou 
colaboradores. Este último nem sempre pode ser simplesmente assumido quando os processos são de domínios 
administrativos diferentes. Nesse caso, é muito provável que apresentem comportamento racional, por exemplo, relatar 
tempos limite ao fazer isso é mais barato do que executar uma operação de atualização. Uma vez que lidar com esses 
casos não é trivial, um primeiro passo para uma solução é capturado na forma de Tolerância a falhas BAR, o que 
significa bizantino, altruísmo e racionalidade. A tolerância a falhas de BAR é descrita em Aiyer et al. (2005).
8.2.4 Detecção de falha
Pode ser que o que foi dito até agora deixe claro que, para mascarar adequadamente as falhas, geralmente também 
é necessário detectá-las. A detecção de falhas é um dos pilares da tolerância a falhas em sistemas distribuídos. O 
que isso significa é que, para um grupo de processo, os membros não defeituosos devem ser capazes de decidir 
quem continua sendo membro e quem não é. Em outras palavras, devemos ser capazes de detectar quando um 
membro falhou.
Quando se trata de detectar falhas de processo, existem basicamente apenas dois mecanismos. Ou os 
processos estão enviando ativamente "você está ativo?" uns com os outros (para o qual, é claro, esperam por 
uma resposta) ou aguardam passivamente até que cheguem mensagens dos diferentes processos. A segunda 
só faz sentido quando pode ser garantido que há comunicação suficiente entre os processos. Na prática, um
ping aos processos.
Há uma enorme quantidade de trabalho teórico sobre detectores de falhas. O que se resume a usar um 
mecanismo de tempo limite para verificar se um processo falhou. Em situações reais, existem dois problemas 
principais com essa forma de proceder. Primeiro, devido a redes não confiáveis, simplesmente declarar que um 
processo falhou porque não respondeu a uma mensagem de ping pode estar errado. Em outras palavras, é muito 
fácil gerar falsos positivos. Se um falso positivo tiver o efeito de remover um processo perfeitamente saudável de 
uma lista de membros, é claro que algo está errado.
Outro problema sério é que os tempos limite acontecem com muita facilidade. Como Birman (2005) aponta, há pouco 
trabalho na construção de subsistemas de detecção de falhas apropriados que levem em consideração mais do que a 
simples falta de resposta a uma mensagem. Essa afirmação é ainda mais evidente quando se considera os sistemas 
distribuídos usados na indústria.
Existem várias questões a serem consideradas ao projetar um subsistema de detecção de falhas [ver também 
Zhuang et al. (2005)]. Por exemplo, a detecção de falhas pode ocorrer por meio de conversas nas quais cada nó relata 
regularmente que ainda está ativo e em execução. Como já mencionamos, uma alternativa é permitir que eles façam 
pesquisas ativas entre si.
336 CAPÍTULO 8 TOLERÂNCIA AO ERRO
A detecção de falhas também pode ocorrer como um efeito colateral da troca regular de informações com os 
vizinhos, como no caso da disseminação de informações baseada em fofoca (que foi discutida no Capítulo 4). Esta 
abordagem também é essencialmente adotada em Obduro (Vogels, 2003): os processos reportam periodicamente a 
disponibilidade do serviço. Essas informações são disseminadas gradativamente pela rede por meio de chats. Com 
o tempo, cada processo aprenderá da existência de todos os outros processos, mas o mais importante, ele terá 
informações suficientes localmente disponíveis para decidir se um processo falhou ou não. Um membro cujas 
informações de disponibilidade estão desatualizadas provavelmente falhou.
Outra questão importante é que um subsistema de detecção de falhas deve ser idealmente capaz de distinguir falhas de 
rede de falhas de nó. Uma maneira de resolver esse problema é não deixar um único nó decidir se um de seus vizinhos falhou. 
Em vez disso, quando um nó observa que não há resposta a uma mensagem de ping, ele pede a outros vizinhos para ver se 
eles podem se comunicar com o nó que provavelmente falhou. Claro, informações positivas também podem ser compartilhadas: 
se um nó ainda estiver ativo, essa informação pode ser encaminhada para outras partes interessadas (que podem estar 
detectando uma falha de link com o nó suspeito).
Isso leva a outra questão importante: quando uma falha de membro é detectada, como ela deve ser relatada a 
outros processos sem falha? Um método simples e um tanto radical é o seguido em FUSE (Dunagan et al., 2004). No 
FUSE, os processos podem ser unidos em um grupo que compreende uma rede de longa distância. Os membros do 
grupo criam uma árvore abrangente ( árvore geradora) usado para monitorar membros com falha. Membros enviam 
pings para seus vizinhos. Quando um vizinho não responde, o nó que enviou o ping muda imediatamente para um 
estado no qual também não responde aos pings enviados por outros nós. Por recursão, a falha de um único nó é 
rapidamente relatada ao grupo. O FUSE não apresenta muitas falhas de link pelo simples motivo de usar conexões 
TCP ponto a ponto entre os membros do grupo.
8.3 COMUNICAÇÃO CONFIÁVEL
ENTRE CLIENTE E SERVIDOR
Em muitos casos, a tolerância a falhas em sistemas distribuídos concentra-se em processos com falha. No entanto, 
as falhas de comunicação também devem ser consideradas. Os modelos de falha discutidos anteriormente aqui 
também são válidos principalmente para canais de comunicação. Em particular, um canal de comunicação pode 
apresentar falhas de congelamento, salto, temporização e arbitrárias. Na prática, ao construir canais de comunicação 
confiáveis, atenção especial é dada à ocultação de falhas por congelamento e desvio. Falhas arbitrárias podem se 
apresentar como mensagens duplicadas, como resultado do fato de que em uma rede de computadores as 
mensagens podem ser armazenadas em buffer por um longo tempo e são encaminhadas para a rede após o 
remetente original emitir um comando de retransmissão [ver, por exemplo ,
SEÇÃO 8.3 COMUNICAÇÃO CONFIÁVEL ENTRE CLIENTE E SERVIDOR 337
8.3.1 Comunicação ponto a ponto
Em muitos sistemas distribuídos, a comunicação ponto a ponto confiável é estabelecida por meio de um protocolo de 
transporte confiável, como o TCP. Esconde por defeito as falhas, que se apresentam sob a forma de mensagens 
perdidas, através de confirmaçõese retransmissões. Essas falhas permanecem completamente ocultas de um cliente 
TCP.
No entanto, as falhas de congelamento não são ocultadas. Uma falha de congelamento pode ocorrer (por 
qualquer motivo) quando uma conexão TCP é interrompida repentinamente de forma que nenhuma outra mensagem 
possa ser transmitida pelo canal. Na maioria dos casos, o cliente é informado que o canal travou por apresentar 
exceção. A única maneira de ocultar essas falhas é permitir que o sistema distribuído estabeleça automaticamente 
uma nova conexão, simplesmente encaminhando uma solicitação de conexão. O pressuposto subjacente é que o 
outro lado pode, ou está novamente no poder, responder a essas solicitações.
8.3.2 Semântica RPC na presença de falhas
A seguir, examinaremos com mais detalhes a comunicação entre o cliente e o servidor ao usar meios de comunicação 
de alto nível, como chamadas de procedimento remoto (RPCs). Chamadas de procedimento remoto). O objetivo dos 
RPCs é ocultar a comunicação de forma que as chamadas de procedimento remoto pareçam locais. Com poucas 
exceções, o problema está perto de ser resolvido. A propósito, contanto que o cliente e o servidor funcionem bem, os 
RPCs fazem bem o seu trabalho. O problema ocorre quando surgem erros. É então que as diferenças entre chamadas 
locais e remotas nem sempre são fáceis de esconder.
Para estruturar nossa análise, faremos uma distinção entre as cinco classes diferentes de falhas que podem ocorrer 
em sistemas RPC, como segue:
1. O cliente não consegue localizar o servidor.
2. A mensagem de solicitação (solicitação) do cliente para o servidor é perdida.
3. O servidor congela após receber uma solicitação.
4. A mensagem de resposta do servidor para o cliente foi perdida.
5. O cliente congela após enviar uma solicitação.
Cada uma dessas categorias apresenta problemas diferentes e requer soluções diferentes.
O cliente não consegue localizar o servidor
Em primeiro lugar, muitas vezes o cliente não consegue localizar um servidor adequado. Todos os servidores 
podem estar desligados, por exemplo. Como alternativa, suponha que o cliente foi compilado com uma versão 
específica do stub do cliente e que o binário não foi usado por um período de tempo considerável. Enquanto 
isso, o servidor evolui e instala
338 CAPÍTULO 8 TOLERÂNCIA AO ERRO
uma nova versão da interface; novas salvaguardas são geradas e colocadas em uso. Quando o cliente finalmente for 
executado, o conector de arquivo não será capaz de acompanhar o servidor e relatará um travamento. Embora esse 
mecanismo seja usado para proteger o cliente contra uma tentativa acidental de comunicação com um servidor que possa 
discordar dele dependendo de quais parâmetros são necessários ou do que deve ser feito, o problema permanece como 
deveria ser feito. lidar com a falha.
Uma solução possível é fazer o erro gerar um exceção. Em algumas linguagens (por exemplo, Java), os 
programadores podem escrever procedimentos especiais que são chamados por erros específicos, como divisão por 
zero. Em C, é possível usar manipuladores de sinais para essa finalidade. Ou seja, um novo tipo de sinal poderia ser 
definido SIGNO-SERVER,
que seriam tratados da mesma forma que os outros sinais.
Esse método também tem vantagens. Em primeiro lugar, nem todas as linguagens têm exceções ou sinais. Outro 
ponto é que tentar escrever uma exceção ou manipulador de sinal destrói a transparência que você está tentando 
alcançar. Suponha que você seja um programador e seu chefe lhe peça para escrever o procedimento soma. Você sorri 
e diz a ele que vai escrever, testar e documentar em cinco minutos. Em seguida, ela menciona que você também deve 
escrever um manipulador de exceção, caso o procedimento não esteja pronto no mesmo dia. Nesse ponto, é muito 
difícil manter a ilusão de que os procedimentos remotos não são diferentes dos locais, já que escrever um manipulador 
de exceção para "O servidor não pode ser localizado" seria uma solicitação um tanto incomum em um sistema de 
processador único. . Tudo é para transparência.
Perda de mensagens de solicitação
O segundo item da lista tem a ver com as mensagens de solicitação ausentes. É o mais fácil de abordar: você 
só precisa obter o sistema operacional ou o tíquete do cliente para iniciar um cronômetro ao enviar a 
solicitação. Se o cronômetro expirar antes de uma resposta ou confirmação retornar, a mensagem será 
encaminhada. Se a mensagem for realmente perdida, o servidor não conseguirá distinguir entre a 
retransmissão e a entrega original, e tudo funcionará bem. A menos, é claro, que muitas mensagens sejam 
perdidas de tal forma que o cliente desista e conclua erroneamente que o servidor está fora do ar, caso em que 
ele reverte para a situação em que "O servidor não pode ser localizado". Se a solicitação não foi perdida, tudo o 
que precisa ser feito é permitir que o servidor detecte que é uma retransmissão. Infelizmente,
Congelamento de servidor
A próxima falha na lista é o congelamento do servidor. A sequência normal de eventos em um servidor é mostrada na 
Figura 8-7 (a). Uma solicitação chega, é atendida e uma resposta é enviada. Agora considere a Figura 8-7 (b). Uma 
solicitação chega e é atendida, como antes, mas o servidor congela antes de responder. Finalmente, vamos dar uma 
olhada na Figura 8-7 (c). Mais uma vez, chega um pedido, mas o servidor congela antes mesmo de poder atendê-lo. 
E, claro, não envia nenhuma resposta.
SEÇÃO 8.3 COMUNICAÇÃO CONFIÁVEL ENTRE CLIENTE E SERVIDOR 339
SOL (APLICAÇÃO)
Servidor
Recebe
Corre
Responda
ANIMAL
Servidor
Recebe
Corre
eu sei
congela
Sem RESP
Servidor PET
Recebe
Nenhum RESP Se
congela
RESP (RESPOSTA)
(para) (b)
(c)
Figura 8-7. Um servidor no caso de comunicação cliente-servidor. (a) O caso normal. (b) 
Congelamento após a execução. (c) Congelamento antes da execução.
A parte estranha da Figura 8-7 é que o tratamento correto é diferente em (b) e (c). Em (b), o sistema deve relatar 
novamente a falha ao cliente (por exemplo, lançando uma exceção), enquanto em (c) apenas a solicitação pode ser 
retransmitida. O problema é que o sistema operacional do cliente não consegue dizer qual é qual. Tudo que você 
sabe é que seu cronômetro expirou.
Existem três escolas de pensamento sobre o que fazer neste caso (Spector, 1982). Uma filosofia é esperar até 
que o servidor seja reinicializado (ou reconectado a um novo servidor) e tentar a operação novamente. A ideia é 
continuar tentando até que uma resposta seja recebida e então entregá-la ao cliente. Esta técnica é chamada semântica 
de pelo menos uma vez e garante que o RPC foi executado pelo menos uma vez, mas possivelmente mais vezes.
A segunda filosofia cede imediatamente e relata o fracasso. Esta forma é chamada semântica no máximo uma vez e 
garante que o RPC foi executado no máximo uma vez, mas possivelmente não foi executado.
A terceira filosofia é não garantir nada. Quando um servidor congela, o cliente não recebe ajuda e nenhuma 
promessa sobre o que aconteceu. O RPC pode ter sido executado em qualquer lugar do zero um grande número 
de vezes. A principal virtude desse esquema é que ele é fácil de implementar.
Nenhuma dessas filosofias é totalmente atraente. O que seria necessário seria um semântica de exatamente uma 
vez, embora em geral não haja como resolver esse problema. Imagine que a operação remota consista em imprimir 
algum texto e que o servidor remoto envie uma mensagem de encerramento ao cliente quando o texto já tiver sido 
impresso. Suponha também que, quando um cliente emite uma solicitação, ele recebe uma confirmação de que a 
solicitação foi entregue ao servidor. O servidor pode então seguir duas estratégias: enviar uma mensagem de conclusão 
exatamente antes de instruir a impressora a fazer seu trabalho ou enviá-la após a impressão do texto.
Suponha que o servidor congele e depois se recupere. Notifique todos os clientes de que ele acabou de ser 
congelado,mas está funcionando novamente. O problema é que o cliente não sabe se seu pedido de impressão de um 
texto foi de fato atendido.
Existem quatro estratégias que o cliente pode seguir. Primeiro, o cliente pode decidir Nunca
reemitir um pedido, com o risco do texto não ser impresso. Em segundo lugar, você pode decidir reeditar
sempre um pedido, mas isso faz com que seu texto seja impresso duas vezes. Terceiro, você pode decidir
340 CAPÍTULO 8 TOLERÂNCIA AO ERRO
reenvie um pedido apenas se ainda não tiver recebido uma confirmação de que o seu pedido de impressão foi 
entregue ao servidor. Nesse caso, o cliente confia que o servidor travou antes que a solicitação pudesse ser 
entregue. A quarta e última estratégia é reemitir um pedido, desde que um aviso de recebimento do pedido de 
impressão tenha sido recebido.
Com duas estratégias para o servidor e quatro para o cliente, há um total de seis combinações a serem 
consideradas. Infelizmente, nenhum dos dois é satisfatório. Para explicar, vamos notar que três eventos podem acontecer 
no servidor: enviar a mensagem de encerramento (M), imprimir o texto (P) e congelar (C). Esses eventos podem ocorrer 
em seis ordens diferentes.
1 M → P → C: Um congelamento ocorre após o envio da mensagem de rescisão e
imprimir o texto.
2 M → C ( → P): Um congelamento ocorre após o envio da mensagem de rescisão,
mas antes que o texto possa ser impresso.
3 - P → M → C: Um congelamento ocorre após o envio da mensagem de rescisão e
imprimir o texto.
Quatro. P → C ( → M): O texto é impresso, após o qual o servidor congela antes
a mensagem de encerramento pode ser enviada.
5 C ( → P → M): Um congelamento ocorre antes que o servidor possa fazer qualquer coisa.
6 C ( → M → P): Um congelamento ocorre antes que o servidor possa fazer qualquer coisa.
Os parênteses indicam um evento que não pode mais acontecer porque o servidor já travou. A Figura 8-8 mostra 
todas as combinações possíveis. Você fica imediatamente ciente de que não existe uma combinação de estratégia de 
cliente e estratégia de servidor que funcione corretamente em todas as sequências de eventos possíveis. A linha 
inferior indica que o cliente nunca pode dizer se o servidor travou um pouco antes ou depois de imprimir o texto.
Cliente Servidor
Estratégia M → P
MC (P) C (MP)
Estratégia P → M
PC (M) C (PM)Estratégia de reemissão MPC PMC
Sempre
Nunca
Somente quando confirmado Somente 
quando não confirmado
DUP
OK
DUP
OK
OK
ZERO
OK
ZERO
OK
ZERO
ZERO
OK
DUP
OK
DUP
OK
DUP
OK
OK
DUP
OK
ZERO
ZERO
OK
OK
DUP
ZERO = O texto não é impresso de todo
= O texto é impresso uma vez
= O texto é impresso duas vezes
Figura 8-8. Diferentes combinações de estratégias de cliente e servidor na presença de 
congelamento de servidor.
SEÇÃO 8.3 COMUNICAÇÃO CONFIÁVEL ENTRE CLIENTE E SERVIDOR 341
Em suma, a possibilidade de um congelamento do servidor muda radicalmente a natureza do RPC e distingue 
claramente os sistemas de processador único dos sistemas distribuídos. No primeiro caso, um congelamento de 
servidor também implica um congelamento de cliente, portanto, a recuperação não é possível nem necessária. No 
segundo caso, é possível e necessário agir.
Perda de mensagens de resposta
Respostas perdidas também são difíceis de controlar. A solução mais óbvia é confiar novamente em um cronômetro 
que foi definido pelo sistema operacional do cliente. Se nenhuma resposta chegar dentro de um período de tempo 
razoável, a solicitação é simplesmente enviada mais uma vez. O problema com essa solução é que o cliente não tem 
certeza do motivo pelo qual não houve resposta. O servidor respondeu e a resposta foi perdida ou o servidor está 
lento? Isso pode fazer a diferença.
Em particular, algumas operações podem ser repetidas com segurança quantas vezes forem necessárias sem 
que ocorra qualquer dano. Uma solicitação como solicitar os primeiros 1024 bytes de um arquivo não tem efeitos 
colaterais e pode ser executada com a freqüência necessária sem danos. Uma solicitação que tem essa propriedade 
é considerada idempotente.
Agora considere uma solicitação a um servidor de banco para transferir um milhão de dólares de uma conta para outra. 
Se o pedido chega e é realizado, mas a resposta se perde, o cliente não saberá e voltará a transmitir a mensagem. O servidor 
do banco interpretará esta solicitação como nova e também a executará. Dois milhões de dólares serão transferidos. 
Esperançosamente, a resposta não foi perdida 10 vezes. A transferência de dinheiro não é idempotente.
Uma maneira de resolver esse problema é tentar estruturar todas as solicitações de maneira idempotente. Na 
prática, porém, muitas solicitações (por exemplo, transferência de dinheiro) são inerentemente não idempotentes, 
portanto, algo mais é necessário. Outro método é fazer com que o cliente atribua um número de sequência a cada 
solicitação. Ao fazer com que o servidor controle o número de sequência recebido mais recentemente de cada cliente 
que o está usando, o servidor pode distinguir entre uma solicitação original e uma retransmissão e pode se recusar a 
fazer qualquer solicitação uma segunda vez. No entanto, o servidor ainda precisará continuar respondendo ao cliente. 
Observe que essa abordagem requer que o servidor mantenha a administração de cada cliente. Mais longe, não está 
claro por quanto tempo essa administração deve ser mantida. Uma proteção adicional é usar um bit no cabeçalho da 
mensagem para diferenciar as solicitações iniciais das retransmissões (a ideia é que isso sempre garante a execução de 
uma solicitação original; as retransmissões podem exigir mais cuidado).
Cliente congela
O item final na lista de falhas é o congelamento do cliente. O que acontece se um cliente enviar uma solicitação a 
um servidor para fazer o trabalho e ele congelar antes de responder? Nesse ponto, um cálculo é acionado e 
nenhum pai está esperando pela resposta. Esse cálculo indesejado é chamado órfão.
342 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Os órfãos costumam causar vários problemas que interferem na operação normal de um sistema. No mínimo, eles 
desperdiçam ciclos de CPU. Eles também podem bloquear arquivos ou vinculá-los a recursos valiosos. Por último, se o 
cliente reinicializar e executar RPC, mas a resposta do órfão chegar imediatamente, pode haver confusão.
O que pode ser feito com os órfãos? Nelson (1981) propôs quatro soluções. Na Solução 1, antes de um 
stub do cliente enviar uma mensagem RPC, ele cria uma entrada de log para relatar o que está prestes a fazer. 
O registro é mantido no disco ou em algum outro meio que sobreviva ao congelamento. Após a reinicialização, 
o log é verificado e o órfão é removido explicitamente. Esta solução é conhecida como externo
filho de órfãos.
A desvantagem desse esquema é a despesa horrível de gravar um log de disco para cada RPC. Como se 
isso não bastasse, pode até não funcionar, já que os próprios órfãos podem fazer RPCs, criando assim netos 
órfãos ou mais difícil ou impossível localizar descendentes. Finalmente, a rede pode ser particionada devido a 
um gateway com defeito, tornando impossível removê-los, embora possam ser localizados. Em última análise, 
esta não é uma abordagem promissora.
Na solução 2, ligue reencarnação, todos esses problemas são resolvidos sem a necessidade de gravar logs de disco. 
A forma como funciona é dividindo o tempo em épocas numeradas sequencialmente. Quando um cliente é reinicializado, ele 
transmite uma mensagem para todas as máquinas para indicar o início de uma nova época. Quando essa transmissão 
chega, todos os cálculos feitos em nome do referido cliente são eliminados. Claro, se a rede for particionada, alguns órfãos 
podem sobreviver. Infelizmente, no entanto, quando eles são relatados novamente, suas respostas conterão um número de 
época desatualizado, tornando-as mais fáceis de detectar.
A solução 3 é uma variante dessa ideia, mas um pouco menos draconiana. Se chamareencarnação benevolente. Quando 
chega uma transmissão de época, cada máquina vê se tem cálculos remotos em execução localmente e, em caso afirmativo, faz o 
que pode para localizar seus proprietários. Somente se os proprietários não puderem ser localizados em nenhum lugar, o cálculo 
será removido.
Finalmente, temos a solução 4, expiração, em que cada RPC é alocado por um período de tempo padrão, T, para 
fazer o trabalho. Se você não conseguir terminar, terá que solicitar explicitamente outro período de tempo, o que é 
um incômodo. Por outro lado, se após congelar o cliente espera um certo tempo T Antes de começar de novo, todos 
os órfãos certamente terão desaparecido. O problema a ser resolvido neste caso é selecionar um valor razoável de T enfrentando 
RPCs com requisitos totalmente diferentes.
Na prática, todos esses métodos são rudimentares e indesejáveis. Pior ainda, remover um órfão pode ter 
consequências imprevisíveis. Por exemplo, suponha que um órfão tenha obtido direitos sobre um ou mais arquivos 
ou registros de banco de dados. Se o órfão for removido repentinamente, esses direitos podem permanecer para 
sempre. Além disso, um órfão pode já ter feito entradas em várias filas remotas para iniciar outros processos em 
algum momento futuro, portanto, mesmo a remoção do órfão pode não remover todos os rastros. Além disso, pode 
até ter reiniciado, com consequências imprevisíveis. Panzieri e Shrivastava (1988) lidam com mais detalhes com a 
eliminação de órfãos.
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 343
8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL
Ao considerar a importância de mitigar um processo por replicação, não é surpreendente que serviços de 
multitransmissão confiáveis também sejam importantes. Infelizmente, a multitransmissão confiável é 
surpreendentemente complicada. Nesta seção, examinaremos mais de perto os problemas envolvidos na 
entrega confiável de mensagens a um grupo de processos.
8.4.1 Esquemas de multitransmissão básicos confiáveis
Embora a maioria das camadas de transporte ofereça canais de comunicação ponto-a-ponto confiáveis, raramente 
oferecem comunicação confiável para um conjunto de processos. Sua melhor oferta é permitir que cada processo 
estabeleça uma conexão ponto a ponto com qualquer outro processo com o qual deseja se comunicar. Obviamente, essa 
organização não é muito eficiente, pois pode desperdiçar largura de banda da rede. No entanto, quando o número de 
processos é pequeno, obter confiabilidade por meio de vários canais ponto a ponto confiáveis é uma solução simples e 
direta.
Para ir além desse caso simples, temos que definir precisamente o que é multitransmissão confiável. Intuitivamente, 
significa que uma mensagem enviada a um grupo de processos deve ser entregue a cada um dos membros desse grupo. 
Porém, o que acontece se durante a comunicação um processo entrar no grupo? Você também deve receber a 
mensagem? Além disso, devemos determinar o que acontece se um processo (remetente) congela durante a 
comunicação.
Para cobrir tais situações, devemos distinguir entre comunicação confiável na presença de processos 
defeituosos e comunicação confiável quando se presume que os processos estão operando corretamente. No 
primeiro caso, a multitransmissão é considerada confiável quando pode garantir que todos os membros não 
defeituosos do grupo receberão a mensagem. A parte complicada é que será necessário chegar a um acordo sobre 
a aparência real do grupo antes que uma mensagem possa ser entregue, bem como várias restrições na ordem de 
entrega. Quando voltarmos a essas questões mais tarde na discussão das multitransmissões atômicas.
A situação é simplificada quando assumimos que há um acordo sobre quem é membro do grupo e quem não é. 
Em particular, assumindo que os processos não falham e que eles não entram ou saem do grupo enquanto a 
comunicação está ocorrendo, a multitransmissão confiável significa simplesmente que cada mensagem deve ser 
entregue a todos os membros atuais do grupo. No caso mais simples, não há exigência de que todos os membros do 
grupo recebam mensagens na mesma ordem, embora às vezes seja necessário atender a essa característica.
Esta forma mais fraca de multitransmissão confiável é relativamente fácil de implementar, novamente sujeita à 
condição de que o número de destinatários seja limitado. Considere o caso em que um único remetente deseja enviar uma 
mensagem a vários destinatários. Suponha que o sistema de comunicação que emprega multitransmissão oferece apenas 
multitransmissão confiável, que
344 CAPÍTULO 8 TOLERÂNCIA AO ERRO
significa que uma mensagem multitransmissão pode ser parcialmente perdida e entregue a alguns, mas não a todos os remetentes 
pretendidos.
O destinatário
não recebe a mensagem # 24
Remetente
M25
Destinatário Destinatário Destinatário Destinatário
Amortecedor
registro
Mais recentes 24
M25
Mais recentes 24
M25
Mais recentes 2,3
M25
Mais recentes 24
M25
Internet
(para)
Remetente Destinatário Destinatário Destinatário Destinatário
Mais recentes 25
M25
ACR DE 25
Mais recentes 24
M25
Não chego
24º
Mais recentes 2,3
M25
Mais recentes 24
M25
ACR (RECONHECIMENTO
DE RECEBIMENTO) DE 25
ACR de 25
Internet
(b)
Figura 8-9. Uma solução simples para multitransmissão confiável quando todos os destinatários 
são conhecidos e presumidos que não falharão. (a) Transmissão de mensagens. (b) Relatório de 
feedback.
Uma solução simples é mostrada na Figura 8-9. O processo de envio atribui um número de sequência a cada mensagem que 
é multi-broadcast. As mensagens são consideradas recebidas na ordem em que foram enviadas. Isso torna mais fácil para um 
destinatário detectar que não recebeu uma mensagem. Cada mensagem multi-broadcast é armazenada localmente em um buffer 
de histórico no remetente. Assumindo que o remetente conhece os destinatários, o remetente simplesmente mantém a mensagem 
em seu buffer de histórico até que cada destinatário tenha retornado uma confirmação. Se um destinatário detectar que uma 
mensagem foi perdida, ele retornará uma confirmação negativa, solicitando que o remetente retransmita a mensagem. Caso 
contrário, o remetente pode retransmitir automaticamente a mensagem quando não tiver recebido todas as confirmações dentro de 
um determinado período.
Existem várias alterações de design que podem ser feitas. Por exemplo, para reduzir o número de mensagens devolvidas 
ao remetente, as confirmações podem ser incorporadas a outras mensagens. Além disso, a retransmissão de uma mensagem 
pode ser feita por meio de comunicação ponto a ponto para cada processo solicitante, ou por meio de uma única mensagem 
transmitida a todos os processos. Em Defago et al. (2004), um estudo extenso e detalhado de multitransmissões de ordem 
completa é encontrado.
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 3. 4. 5
8.4.2 Escalabilidade multitransmissão confiável
O principal problema com o esquema de multitransmissão confiável que acabamos de descrever é que ele não pode 
suportar um grande número de destinatários. Se eles existem N destinatários, o remetente deve estar preparado para 
aceitar pelo menos N avisos de recebimento. Com muitos destinatários, o remetente pode ficar sobrecarregado por 
mensagens de feedback, também conhecidas como implosão de feedback. Além disso, também pode ser necessário levar 
em consideração que os destinatários estão espalhados pela rede de longa distância.
Uma solução para esse problema é não fazer os destinatários confirmarem o recebimento de uma mensagem. Em 
vez disso, o destinatário retorna uma mensagem de feedback apenas para relatar que o remetente não enviou a 
mensagem. Retornar apenas confirmações negativas geralmente pode ser feito em uma escala maior [ver, por exemplo, 
Towsley et al. (1997)], embora nenhuma garantia estrita possa ser dada de que nunca ocorrerão implosões de feedback.
Outro problema em retornar apenas confirmações negativas é que o remetenteserá, em teoria, forçado a 
manter uma mensagem para sempre em um buffer de histórico. Como o remetente pode nunca saber se uma 
mensagem foi entregue com êxito a todos os destinatários, você deve estar sempre preparado para o caso de um 
destinatário solicitar a retransmissão de uma mensagem antiga. Na prática, o remetente excluirá uma mensagem de 
seu buffer de histórico após um determinado período de tempo, para evitar que o buffer sobrecarregue. No entanto, 
a exclusão de uma mensagem corre o risco de uma solicitação de retransmissão não ser atendida.
Existem várias propostas para implementar multitransmissão escalonável e confiável. Em Levine e 
García-Luna-Aceves (1998) diferentes esquemas são comparados. Aqui estão duas abordagens muito diferentes 
que são representativas de muitas soluções existentes.
Controle de feedback não hierárquico
O principal problema em relação a soluções escaláveis para multitransmissão confiável é reduzir o número de 
mensagens de feedback retornadas ao remetente. Um modelo popular usado em várias aplicações de área 
ampla é o supressão de feedback. Este esquema serve como base para o Multitransmissão confiável 
escalável (SRM, de Inglês
Multicast confiável escalável) desenvolvido por Floyd et al. (1977), e funciona da seguinte forma.
Em primeiro lugar, no SRM, os destinatários nunca confirmam a entrega bem-sucedida de uma mensagem de difusão 
múltipla, mas relatam apenas quando não recebem uma mensagem. Como detectar a perda de uma mensagem é deixado para o 
aplicativo. Apenas reconhecimentos negativos são retornados como feedback. Sempre que um destinatário perceber que uma 
mensagem está faltando, multi-stream seu feedback para o resto do grupo.
A multitransmissão de feedback permite que outro membro do grupo cancele seu próprio feedback. Suponha que 
vários destinatários não recebam a mensagem m. Cada pessoa terá que retornar uma confirmação negativa ao 
remetente, Sim, de modo que m pode ser retransmitido. No entanto, se for assumido que as retransmissões são sempre 
multicast para todo o grupo, é suficiente que S receber apenas um pedido de retransmissão.
346 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Por este motivo, um remetente R você não recebeu uma mensagem m agenda uma mensagem de feedback com 
algum atraso aleatório. Ou seja, ele não envia a solicitação de retransmissão até que um determinado tempo aleatório tenha 
decorrido. Sim, entretanto R recebe outro pedido de retransmissão de Sr cancelar seu próprio feedback, sabendo que m ele 
será retransmitido em breve. Desta forma, idealmente, S você receberá apenas uma mensagem de feedback, que por sua 
vez, retransmite m. Esse esquema é mostrado na Figura 8-10.
O remetente recebe apenas 
uma não confirmação
Remetente 
Destinatário Destinatário
T = 3 T = 4
Os destinatários suprimem seu feedback
Destinatário
T = 1
Destinatário
T = 2
NACR (NO
RECONHECIMENTO DE
RECIBO)
NACR (NO
RECONHECIMENTO DE
RECIBO)
NACR (NO
RECONHECIMENTO DE
RECIBO)
NACR (NO
RECONHECIMENTO DE
RECIBO)
NACR (NO
RECONHECIMENTO DE
RECIBO)
Internet
Figura 8-10. Vários destinatários agendaram uma solicitação de retransmissão, mas a primeira 
solicitação leva à exclusão das outras.
A supressão de feedback mostrou escalar razoavelmente bem e tem sido usada como o mecanismo fundamental 
em vários aplicativos colaborativos na Internet, como um quadro branco compartilhado ( Quadro branco compartilhado) compartilhado. 
No entanto, esse método também apresenta vários problemas sérios. Em primeiro lugar, garantir que o remetente 
receba apenas um pedido de retransmissão requer uma programação razoavelmente precisa das mensagens de 
feedback de cada destinatário. Caso contrário, muitos destinatários continuarão enviando seus comentários ao mesmo 
tempo. Não é tão fácil definir os temporizadores adequadamente em um grupo de processos dispersos por uma rede de 
longa distância.
Outro problema é que a multitransmissão do feedback também interrompe os processos que receberam a 
mensagem com sucesso. Em outras palavras, outros destinatários são forçados a receber e processar mensagens que 
são inúteis para eles. A única solução para este problema é permitir que os destinatários que não receberam a 
mensagem m junte-se a um grupo de transmissão diferente para m, conforme explicado em Kasera et al. (1997). 
Infelizmente, essa solução exige que os grupos sejam gerenciados de maneira altamente eficiente, o que é difícil de se 
conseguir em um sistema de área ampla. Uma abordagem melhor é, portanto, permitir que os destinatários propensos 
a não receber a mensagem m unir-se e compartilhar o mesmo canal de transmissão para alimentar e retransmitir 
mensagens. Detalhes deste método são encontrados em Liu et al. (1998).
Para aumentar a escalabilidade do SRM, é útil que os destinatários ajudem na recuperação local. Em particular, se 
um destinatário que recebeu a mensagem com sucesso m receber uma solicitação para retransmiti-lo, você pode decidir 
fazer multitransmissão m mesmo antes do remetente
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 347
o original recebe o pedido de retransmissão. Mais detalhes são fornecidos em Floyd et al. (1997) e Liu et al. 
(1998).
Controle de feedback hierárquico
A supressão de feedback, conforme descrito acima, é basicamente uma solução não hierárquica. No entanto, 
alcançar escalabilidade para grupos-alvo muito grandes requer a adoção de abordagens hierárquicas. Em essência, 
uma solução hierárquica para multitransmissão confiável funciona conforme mostrado na Figura 8-11.
Remetente
Conexão (longa distância)
Rede local
Coordenador
S
C
C
R
Raiz
Destinatário
Figura 8-11. A essência da multitransmissão confiável hierárquica. Cada coordenador local 
encaminha a mensagem para seus filhos e, em seguida, trata as solicitações de retransmissão.
Para manter as coisas simples, suponha que haja apenas um remetente que deve transmitir mensagens a um grupo muito 
grande de destinatários. O grupo de destinatários é dividido em vários subgrupos, que são posteriormente organizados em uma 
árvore. O subgrupo que contém o remetente forma a raiz de sua árvore. Dentro de cada subgrupo, qualquer esquema de 
multitransmissão confiável que funcione para pequenos grupos pode ser usado.
Cada subgrupo designa um coordenador local, que é responsável pelo tratamento das solicitações de retransmissão 
dos destinatários contidos em seu subgrupo. O coordenador local terá, portanto, seu próprio buffer de histórico. Se o 
coordenador não enviar mensagem m, pede ao coordenador do subgrupo pai para retransmiti-lo. Em um esquema baseado 
em confirmação, um coordenador local envia uma confirmação para seu pai se ele recebeu a mensagem. Se um 
coordenador receber confirmações da mensagem m de todos os membros que compõem seu subgrupo, e também de seu 
filho, você pode excluir m de seu buffer de histórico.
O principal problema com as soluções hierárquicas é a construção da árvore. Em muitos casos, ele deve ser 
construído dinamicamente. Uma maneira é usar a árvore de multitransmissão da rede subjacente, se houver. Em princípio, 
o método consiste em atualizar cada roteador de multitransmissão na camada de rede de forma que ele atue como um 
coordenador local na camada de rede.
348 CAPÍTULO 8 TOLERÂNCIA AO ERRO
da maneira que acabamos de descrever. Infelizmente, na prática, tais adaptações em redes de computadores 
existentes não são fáceis de realizar. Por esses motivos, as soluções de multitransmissão no nível do aplicativo 
discutidas no Capítulo 4 estão ganhando aceitação.
Concluindo, construir esquemas de multitransmissão que possam ser escalonados para um número maior de 
destinatários em uma rede de longa distância é um problema difícil. Não existe uma solução única e cada solução 
apresenta novos problemas.
8.4.3 Multitransmissão atômica
Em seguida, retornamos à situação em que a multitransmissão confiável deve ser alcançada na presença de falhas no 
processo.Em particular, o que geralmente é necessário em um sistema distribuído é a garantia de que uma mensagem 
será entregue a todos os processos ou a nenhum. Além disso, em geral, todas as mensagens também precisam ser 
entregues na mesma ordem para todos os processos. Isso também é conhecido como problema de multitransmissão 
atômica.
Para ver por que a atomicidade é tão importante, vamos considerar um banco de dados replicado construído como um 
aplicativo sobre um sistema distribuído. O sistema distribuído oferece serviços confiáveis de multitransmissão. Em particular, 
permite construir grupos de processos para os quais as mensagens podem ser enviadas com total confiança. O banco de 
dados replicado é, portanto, construído como um grupo de processos, um processo para cada réplica. As operações 
atualizadas são sempre transmitidas por fluxo múltiplo para todas as réplicas e subsequentemente realizadas localmente. Em 
outras palavras, assumimos que um protocolo de replicação ativo é usado.
Suponha que agora uma série de atualizações deva ser realizada, mas durante a execução de uma delas 
uma réplica é congelada. Como resultado, a atualização dessa réplica é perdida, mas, caso contrário, é 
bem-sucedida nas outras réplicas.
Quando um tremor recém-congelado se recupera, na melhor das hipóteses, ele será capaz de se recuperar ao mesmo 
estado em que estava antes de congelar; no entanto, várias atualizações podem ter sido perdidas. Nesse ponto, é essencial 
que você alcance as outras réplicas. Trazer a réplica para o mesmo estado que as outras exige saber exatamente quais 
operações foram perdidas e em que ordem devem ser realizadas.
Agora, suponha que o sistema distribuído subjacente suporte multitransmissão atômica. Nesse caso, a operação 
de atualização enviada a todas as réplicas pouco antes de uma delas congelar é executada em todas as réplicas sem 
falha ou em nenhuma. Em particular, com multitransmissão atômica, a operação pode ser realizada por todas as 
réplicas que estão operando corretamente somente se eles chegaram a um acordo sobre a associação ao grupo. Ou 
seja, a atualização é realizada se as réplicas restantes decidirem que a réplica congelada não pertence mais ao grupo.
Quando a réplica congelada se recupera, ela é forçada a se juntar ao grupo mais uma vez. Nenhuma atualização será 
enviada a você até que seja registrado como membro novamente. Para ingressar no grupo, é necessário que seu status seja 
igual ao dos demais membros. Conseqüentemente, a multitransmissão atômica garante que processos sem falhas manterão 
uma visão consistente do banco de dados e forçarão a reconciliação quando uma réplica se recuperar e se juntar novamente 
ao pool.
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 349
Sincronia Virtual
A multitransmissão confiável na presença de falhas de processo pode ser definida com precisão com base em grupos de 
processos e alterações de associação de grupo. Como antes, fazemos uma distinção entre receber Y entregar uma mensagem. Em 
particular, adotamos novamente um modelo no qual o sistema distribuído é composto de uma camada de comunicação, conforme 
mostrado na Figura 8-12. Dentro dessa camada de comunicação, as mensagens são enviadas e recebidas. Uma mensagem 
recebida é armazenada em buffer localmente na camada de comunicação até que possa ser entregue ao aplicativo colocado 
logicamente em uma camada superior.
Inscrição
A mensagem é entregue ao aplicativo
Camada de
comunicação
A mensagem é recebida pela camada de comunicação
SO (sistema
operacional)
local
A mensagem vem da rede
Internet
Figura 8-12. Organização lógica de um sistema distribuído para distinguir entre o recebimento e a 
entrega de uma mensagem.
Toda a ideia da multitransmissão atômica é que uma mensagem de multitransmissão m está associado apenas a 
uma lista de processos aos quais deve ser entregue. Esta lista de entrega corresponde a um visão de grupo, ou seja, a 
visão do conjunto de processos contidos no grupo, aquele que o remetente tinha no momento da mensagem m foi 
multi-transmissão. Uma observação importante é que cada processo que aparece na lista tem a mesma visualização. Ou 
seja, todos os processos devem concordar que m deve ser entregue a cada um deles e não a outros processos.
Agora suponha que a mensagem m é multi-stream no momento em que o remetente tem uma visão de grupo G. 
Além disso, suponha que, enquanto a multitransmissão está ocorrendo, outro processo entra ou sai do grupo. Esta 
mudança de adesão ao grupo é naturalmente anunciada a todos os processos incluídos no G. Expresso de uma 
forma um pouco diferente, um mudança de visão quando uma mensagem é transmitida a vários destinatários vc para 
relatar a entrada ou saída de um processo. Agora você tem duas mensagens multi-broadcast em trânsito ao mesmo 
tempo: m Y vc. O que deve ser garantido é que m ser entregue a todos os processos incluídos em G antes de cada 
um deles receber a mensagem vc o que m não será entregue. Observe que esse requisito é comparável em parte à 
multitransmissão totalmente ordenada, que estudamos no Capítulo 6.
350 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Uma questão que imediatamente vem à mente é se m não é entregue a nenhum processo, como se pode falar 
de protocolo de multitransmissão confiável? Em princípio, há apenas um caso em que a entrega de m permissão para 
falhar: quando a alteração da associação do grupo é o resultado do congelamento do remetente m. Nesse caso, ou 
todos os membros de G
eles devem descobrir sobre o aborto do novo membro, ou nenhum. Alternativamente, m pode ser ignorado por cada 
membro, o que corresponde à situação em que o remetente congelou antes de enviar m.
Esta forma mais poderosa de multitransmissão confiável garante que uma mensagem de multitransmissão na exibição 
de grupo G ser entregue a cada processo não defeituoso incluído em G. Se o remetente da mensagem congelar durante a 
multitransmissão, a mensagem pode ser entregue a todos os processos restantes ou ignorada por cada um deles. Um 
multistream confiável com esta propriedade é considerado virtualmente síncrono Birman e Joseph, 1987).
Considere os quatro processos mostrados na Figura 8-13. Em um determinado momento, o
processo P 1 junta-se ao grupo, que consiste em P 1, P 2, P 3 Y P Quatro. Depois que algumas mensagens foram 
multi-broadcast, P 3 se congela. No entanto, antes de congelar
transmitiu com sucesso uma mensagem aos processos P 2 Y P 4, mas não para P 1 No entanto, a sincronia virtual garante que a 
mensagem não seja entregue, estabelecendo efetivamente a situação.
indicação de que a mensagem nunca foi enviada antes P 3 vai congelar.
Multitransmissão confiável por meio de
várias mensagens ponto a ponto
P1 se junta ao grupo
P3 congela
P3 reingressa
P1
P2
3º T
Q4
G = {P1, P2, P3, P4}
parcial de P3 é descartado
G = {P1, P2, P4}
Multitransmissão
G = {P1, P2, P3, P4}
Clima
Figura 8-13. Princípio de multistreams síncronos virtuais.
Uma vez que P 3 foi removido do grupo, a comunicação continua entre os respectivos membros.
tantes. Mais tarde quando P 3 se recuperar, você pode entrar no grupo novamente assim que seu status for atualizado.
O princípio da sincronização virtual decorre do fato de que todos os fluxos múltiplos ocorrem entre as mudanças de 
visualização. Em outras palavras, uma mudança de visão atua como uma barreira pela qual nenhum multistream pode 
passar. Em certo sentido, é comparável ao uso de uma variável de sincronização em armazenamentos de dados distribuídos, 
conforme discutido no capítulo anterior. Todos os fluxos múltiplos que estão em trânsito enquanto ocorre uma mudança de 
visão são concluídos antes que a mudança de visão entre em vigor. A implementação da sincronização virtual não é trivial, 
como será visto com mais detalhes posteriormente.
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 351
Classificando as mensagens
A sincronização virtual permite que um desenvolvedor de aplicativos considereque multistreams ocorrem em 
momentos separados devido a mudanças na associação do grupo. No entanto, nada foi dito ainda sobre a 
ordenação de multistreams. Em geral, quatro ordens diferentes são distinguidas.
1. Multistreams não ordenados
2. Multistreams ordenados no modo FIFO (primeiro a entrar, primeiro a sair)
3. Multi-streams causalmente ordenados
4. Multi-streams totalmente ordenados
UMA multitransmissão não ordenada confiável Trata-se de uma multitransmissão virtualmente síncrona em que não existem 
garantias quanto à ordem em que as mensagens recebidas são entregues pelos diferentes processos. Para explicar, suponha que 
uma biblioteca de envio e recebimento ofereça suporte a multitransmissão confiável. A operação de recebimento bloqueia o 
processo de invocação até que receba uma mensagem.
Processo 1 Processo 2 Processo 3
enviar m1
enviar m2
receber m1
receber m2
receber m2
receber m1
Figura 8-14. Três processos de comunicação no mesmo grupo. A ordem dos eventos por 
processo é exibida ao longo do eixo vertical.
Agora suponha que um remetente P 1 multi-transmite duas mensagens para um grupo enquanto dois outros processos no 
grupo aguardam a chegada das mensagens, conforme mostrado na Figura 8-14.
Supondo que os processos não congelem ou saiam do pool durante esses multistreams, é
É possível que a camada de comunicação localizada em P 2 pegue a mensagem primeiro m 1 e logo m 2
Como não há restrições quanto à ordem de chegada das mensagens, elas podem ser
entregue a P 2 na ordem em que são recebidos. Em contraste, a camada de comunicação localizada em
P 3 você pode receber a mensagem primeiro m 2 seguido por m 1 e entregá-los na mesma ordem para P 3 -
cation é obrigada a entregar as mensagens que chegam do mesmo processo na mesma ordem em que foram enviadas. Vamos 
considerar a comunicação dentro de um grupo de quatro processos, como mostrado
mostrado na Figura 8-15. Com o pedido FIFO, a única coisa importante é que a mensagem m 1 sempre ser entregue 
antes m 2, e também que a mensagem m 3 sempre ser entregue antes
m Quatro. Esta regra deve ser obedecida por todos os processos presentes no grupo. Em outras palavras, quando a camada de 
comunicação localizada em P 3 recebe m 2 primeiro, ele vai esperar para entregá-lo
P 3 até que você tenha recebido e entregue m 1
Em caso de multistreams confiáveis ordenados no modo FIFO, a camada de comunicação
352 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Processo 1 Processo 2 Processo 3 Processo 4
enviar m1
enviar m2
receber m1
receber m3
receber m2
receber m4
receber m3
receber m1
receber m2
receber m4
enviar m3
enviar m4
Figura 8-15. Quatro processos no mesmo grupo com dois remetentes diferentes, e uma possível 
ordem de entrega de mensagens em multitransmissão em ordem FIFO.
No entanto, não há restrição à entrega de mensagens enviadas por
processos diferentes. Em outras palavras sim P 2 recebe m 1 antes que m 3, você pode entregar as duas mensagens nessa ordem. 
Enquanto isso, pode ser que o processo P 3 recebeu m 3 antes que m 1 O sistema FIFO afirma que P 3 pode entregar m 3 antes que m
1, Embora esta ordem de entrega seja diferente daquela de P 2
forma que a causalidade entre as diferentes mensagens seja preservada. Em outras palavras, se uma mensagem
m 1 precede causalmente outra mensagem m 2, independentemente de terem sido transmitidos por multitransmissão pelo mesmo remetente, 
a camada de comunicação localizada em cada destinatário sempre entregará m 2
uma vez que você recebeu e entregou m 1 Observe que multistreams ordenados causalmente podem ser 
implementados por timestamps de vetor, conforme visto no capítulo
Título 6.
Além dessas três ordens, pode haver a restrição adicional de que a entrega das mensagens também seja feita de 
maneira totalmente ordenada. Entrega totalmente encomendada Isso significa que embora a entrega das mensagens seja 
feita sem ordem, em ordem FIFO, ou em ordem causal, é adicionalmente exigido que quando as mensagens forem 
entregues, sejam entregues na mesma ordem a todos os membros do grupo.
Por exemplo, com a combinação de multitransmissão em ordem completa e ordem FIFO, o
processos P 2 Y P 3 ilustrado na Figura 8-15 pode entregar a mensagem primeiro m 3 e então a mensagem m 1 No entanto, se P 2 Entrega 
m 1 antes que m 3, em tanto que P 3 Entrega m 3 antes de entregar
m 1, eles violariam a restrição total da ordenança. Observe que o pedido FIFO deve continuar a ser respeitado. Em 
outros termos, m 2 deve ser entregue após m 1 e, da mesma forma,
m 4 deve ser entregue após m 3 -
Multitransmissão síncrona confiável que oferece entrega de mensagens em ordem total é
sabe virtualmente como multitransmissão atômica. Com as três diferentes restrições de ordenação de mensagens 
discutidas anteriormente, seis formas de multitransmissão confiável são alcançadas, conforme mostrado na Figura 8-16 
(Hadzilacos e Toueg, 1993).
finalmente, o multi-fluxo confiável causalmente ordenado entregar mensagens de tal
Implementação de sincronização virtual
A seguir, consideramos uma possível implementação de uma multitransmissão virtualmente síncrona confiável. 
Um exemplo disso aparece no Ísis, um sistema distribuído tolerante a falhas que está em uso prático na indústria 
há vários anos. Vamos nos concentrar em alguns
SEÇÃO 8.4 COMUNICAÇÃO DE GRUPO CONFIÁVEL 353
Multitransmissão Ordem básica de mensagens Entrega no pedido total?
Multitransmissão confiável
Multitransmissão FIFO
Multitransmissão causal
Multitransmissão atômica
Multitransmissão atômica FIFO
Multistransmissão atômica causal
Nenhum
Entrega em pedido FIFO Entrega 
em ordem causal Nenhum
Entrega em pedido FIFO Entrega 
em ordem causal
Não
Não
Não
sim
sim
sim
Figura 8-16. Seis versões diferentes de multitransmissão confiável virtualmente síncrona.
das questões de implementação desta técnica, conforme descrito por Birman et al. (1991).
No Ísis, a multitransmissão confiável usa os recursos de comunicação ponto a ponto confiáveis disponíveis na rede 
subjacente, em particular o TCP. Multitransmissão de uma mensagem m
para um grupo de processos é implementado enviando de forma confiável m a cada membro do grupo. Consequentemente, 
embora toda transmissão seja garantida para acontecer, não há garantia de que todo mundo membros do grupo recebem m. Em 
particular, o remetente pode falhar antes de ter transmitido m para cada membro.
Além da comunicação ponto a ponto confiável, o Ísis também assume que as mensagens da mesma origem são 
recebidas por uma camada de comunicação na ordem em que foram enviadas por essa origem. Na prática, esse 
requisito é resolvido por meio de conexões TCP para comunicação ponto a ponto.
O principal problema a ser resolvido é garantir que todas as mensagens enviadas à vista de todos G são entregues a todos 
os processos não defeituosos presentes em G antes que ocorra a próxima mudança de associação ao grupo. A primeira questão 
a ser abordada é garantir que cada processo presente em G recebeu todas as mensagens enviadas para G. Observe que como o 
remetente de uma mensagem m para G pode ter falhado antes de completar seu multitransmissão, se houver processos em
G que eles nunca receberão m. Uma vez que o remetente congelou, esses processos precisarão obter m de outro lugar. Como 
detectar um processo que não recebeu uma mensagem é explicado a seguir.
A solução para este problema é permitir que cada processo incluído no G manter-se m para garantir que todos os 
membros de G recebi. Se diz que m isto é estábulo se todos os membros presentes em G eles o receberam. Apenas 
mensagens estáveis podem ser entregues. Para garantir sua estabilidade, é suficiente selecionar um processo 
arbitrário (operacional) em
G e pedir que você envie m a todos os outros processos.
Para ser mais específico, suponha que a visualização atual seja G Eu, mas você precisa instalar o
próxima vista G Eu 1 Sem perder a generalidade, podemos assumir que G Eu Y G Eu 1diferem
no máximo em um processo. Um processo P notifica a mudança de visão quando você recebe uma mensagem
mudança de visão. A mensagem pode vir do processo de que você deseja entrar ou sair do grupo,
ou de um processo que detectou a falha de um processo em G 1 que agora deve ser removido, conforme mostrado na Figura 
8-17 (a).
354 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Quando um processo P recebe a mensagem de mudança de visão para G Eu 1, primeiro envie uma cópia
de qualquer mensagem instável de G Eu que ainda tem cada processo incluído em G Eu 1 e mais tarde o marca como estável. 
Lembre-se de que o Ísis assume que a comunicação ponto a ponto é confiável.
para que as mensagens encaminhadas nunca sejam perdidas. A referida operação de referência garante
giz que todas as mensagens presentes em G Eu que foram recebidos por pelo menos um processo
são recebidos por todos os processos não defeituosos de G Eu. Observe que também teria sido suficiente selecionar um único 
coordenador para encaminhar mensagens instáveis.
mensagem
instável
Mensagem de descarga
11 1
2 5 2 5 2 5
Mudança de visão
4 6 4 6 4 6
0 3 0 3 0 3
7 7 7
(para) (b) (c)
Figura 8-17. ( a) O processo 4 avisa que o processo 7 congelou e envia uma mudança de visão. (b) O 
processo 6 envia todas as suas mensagens instáveis, seguidas por uma mensagem de liberação. (c) O 
processo 6 instala a nova visualização quando recebe uma mensagem de liberação de todos os outros.
Para indicar que P você não tem mais mensagens instáveis e está pronto para instalar G Eu 1 no
na medida em que os outros processos também podem fazer isso, multitransmite um mensagem de descarga para G Eu 1,
como mostrado na Figura 8-17 (b). Depois de que P recebeu uma mensagem de limpeza para informar-
sobre o mar G Eu 1 Começando com cada um dos outros processos, você pode instalar com segurança a nova visualização [mostrada na 
Figura 8-17 (c)].
Quando um processo Q receba uma mensagem m enviado G Eu, Y Q continue a acreditar que a vista
atual é G Eu, Entrega m sem levar em consideração quaisquer restrições adicionais na ordem das mensagens. Se você já tinha 
recebido m, ele considera a mensagem como uma duplicata e também a descarta.
Como o processo Q eventualmente, você receberá a mensagem de mudança de visualização para G Eu 1, também
irá encaminhar qualquer uma das suas mensagens instáveis primeiro e então encerrar as coisas
enviar uma mensagem de descarga para G Eu 1 Observe que devido à ordem de entrega das mensagens na camada de comunicação, uma 
mensagem de liberação é sempre recebida de um processo após o recebimento de uma mensagem
instável desse mesmo processo.
A principal falha do protocolo descrito até agora é que ele não pode lidar com falhas de processo enquanto uma 
nova mudança de visão está sendo anunciada. Em particular, assume que até
SEÇÃO 8.5 REALIZAÇÃO DISTRIBUÍDA 355
a nova visão G Eu 1 foi instalado por cada membro do grupo incluído em G Eu 1, nenhum procedimento
SW G Eu 1 irá falhar (o que leva à próxima vista G Eu 2). O problema é resolvido com o anúncio da mudança
bios de vista para qualquer G ik mesmo quando as alterações anteriores ainda não foram instaladas por todos os processos. Os 
detalhes são deixados como um exercício para o leitor.
8.5 REALIZAÇÃO DISTRIBUÍDA
O problema de multistransmissão atômica discutido na seção anterior é um exemplo de um problema ainda mais geral, 
conhecido como realização distribuída. O problema de realização distribuída envolve fazer com que uma operação seja 
executada por todos os membros de um grupo ou por nenhum. No caso de multitransmissão confiável, a operação é a 
entrega de uma mensagem. Com transações distribuídas, a operação pode ser a conclusão de uma transação em um 
único site envolvido na transação. Outros exemplos de realização distribuída e como ela pode ser resolvida são discutidos 
em Tanisch (2000).
A implementação distribuída geralmente é estabelecida por meio de um coordenador. Em um esquema simples, esse 
coordenador comunica a todos os demais processos envolvidos, chamados de participantes, se devem ou não realizar 
(localmente) a operação em questão. Este esquema se refere a um
protocolo de implementação monofásica, e tem a desvantagem óbvia de que, se um dos participantes não puder 
realizar a operação de fato, não haverá como comunicar isso ao coordenador. Por exemplo, no caso de transações 
distribuídas, não é possível implementar uma realização local porque violaria as restrições de controle de simultaneidade.
Na prática, são necessários esquemas mais complexos, dos quais o mais comum é o protocolo de 
implementação bifásica que estudaremos em detalhes a seguir. A principal falha desse protocolo é que ele não 
consegue lidar com a falha do coordenador de forma eficiente. Para tanto, foi desenvolvido um protocolo trifásico, 
que também apresentamos.
8.5.1 Realização bifásica
o protocolo bifásico (2PC, de Inglês protocolo de confirmação de duas fases) é devido a Gray (1978). Sem perder a 
generalidade, consideremos uma transação distribuída que envolve a participação de vários processos e onde cada 
processo é executado em uma máquina diferente. Assumindo que não ocorram falhas, o protocolo é composto das duas 
fases a seguir, cada fase compreendendo duas etapas [ver também Bernstein et al. (1987)]:
1. O coordenador envia uma mensagem VOTE_REQUEST para todos os participantes.
2. Quando um participante recebe uma mensagem VOTE_REQUEST, retorne a mensagem
VOTE_COMMIT ao coordenador para dizer-lhe que se prepare para fazer a sua parte na transação 
localmente, ou então envie uma mensagem VOTE_ABORT.
356 CAPÍTULO 8 TOLERÂNCIA AO ERRO
3. O coordenador reúne todos os votos dos participantes. Se todos os participantes votaram para concluir a 
transação, o coordenador também votará. Nesse caso, envie uma mensagem GLOBAL_COMMIT para 
todos os participantes. No entanto, se um participante votou para abortar a transação, o coordenador 
também decidirá abortar a transação e fazer o multitransmissão da mensagem. GLOBAL_ABORT.
4. Cada participante que votou a favor da apresentação aguarda a reação final do coordenador. Se um participante 
receber uma mensagem GLOBAL_COMMIT, em seguida, execute a transação localmente. Caso contrário, quando 
uma mensagem for recebida GLOBAL_ABORT, a transação também é abortada localmente.
A primeira fase é a fase de votação e consiste nas etapas 1 e 2. A segunda é a fase de decisão e consiste nas etapas 3 e 
4. Essas quatro etapas são mostradas como diagramas de estado finito na Figura 8-18. .
Pedido de votação
Vote para abortar
COMEÇAR
COMEÇAR
Executar
Solicitação de
voto
Abortar votação
Aborto global
ABORTAR
Pedido de votação
Vote para conclusão
ESPERAR
PRONTO
Vote para a realização 
Realização global
REALIZAÇÃO
Aborto global
ACR
Realização global
ACR
REALIZAÇÃOABORTAR
(para)
(b)
Figura 8-18. ( a) Máquina de estados finitos para o coordenador em 2PC, (b) Máquina de estados 
finitos para um participante.
Vários problemas surgem ao usar este protocolo 2PC básico em um sistema com falha. Em primeiro lugar, 
observe que tanto o coordenador quanto os participantes têm estados em que ficam pendurados à espera de 
mensagens recebidas. Consequentemente, o protocolo pode falhar facilmente quando um processo congela, já que 
outros processos podem esperar indefinidamente pela chegada de uma mensagem enviada por aquele processo. Por 
esse motivo, mecanismos de tempo limite são usados. Esses mecanismos são explicados nas páginas a seguir.
Quando você examina as máquinas de estado finito ilustradas na Figura 8-18, pode ver que há três estados nos quais 
um coordenador ou um participante fica esperando por uma mensagem que chega. Primeiro, um participante pode estar 
esperando em seu estado INICIAR para o coordenador enviar uma mensagem VOTE_REQUEST. Se não o receber após um 
determinado período de tempo, o participante irá simplesmente decidir abortar localmentea transação e, portanto, enviar uma 
mensagem VOTE_ABORT para o coordenador.
Além disso, o coordenador pode estar preso no estado ESPERAR, aguardando os votos de cada participante. Se nem 
todos os votos forem coletados após um determinado período de tempo, o
SEÇÃO 8.5 REALIZAÇÃO DISTRIBUÍDA 357
o coordenador também deve votar a favor do aborto, para posteriormente enviar uma mensagem GLOBAL_ ABORT para todos os 
participantes.
Por fim, um participante também pode ser bloqueado no estado PRONTO, aguardando o voto global enviado pelo 
coordenador. Se essa mensagem não for recebida dentro de um determinado tempo, o participante simplesmente não pode 
decidir abortar a transação. Em vez disso, você precisa descobrir qual mensagem o coordenador realmente enviou. A solução 
mais simples para esse problema é permitir que cada participante bloqueie até que o coordenador se recupere novamente.
A melhor solução é permitir que um participante P entre em contato com outro participante Q para ver se pode decidir 
a partir do estado atual de Q o que deveria ser feito. Por exemplo, suponha Q tinha alcançado o estado COMPROMETA-SE. 
Isso só é possível se o coordenador tiver enviado uma mensagem GLOBAL_COMMIT para Q pouco antes de congelar. 
Aparentemente, esta mensagem ainda não foi enviada para P. Por consequência, P agora você também pode decidir se 
apresentar localmente. Também se Q está no estado ABORT, P também pode abortar com segurança.
Suponha agora que Q ainda está no estado INICIAR. Esta situação pode ocorrer quando o coordenador envia uma 
mensagem VOTE_REQUEST a todos os participantes e esta mensagem chegou P ( que respondeu imediatamente com a 
mensagem VOTE_COMMIT), mas não atingiu Q.
Em outras palavras, o coordenador teria sido congelado durante a multitransmissão da mensagem VOTE_ REQUEST. Neste caso, é 
seguro abortar a transação: ambos P Como Q pode levar a uma transição para o estado ABORTAR.
A situação mais difícil ocorre quando Q também está no estado PRONTO, aguardando resposta do 
coordenador. Em particular, se todos os participantes estiverem no estado PRONTO, nenhuma decisão pode ser 
feita. O problema é que embora todos os participantes desejem realizar, ainda precisam do voto do coordenador 
para chegar à decisão final. Consequentemente, o protocolo trava até que o coordenador se recupere.
As várias alternativas estão resumidas na Figura 8-19.
Estado Q Ação de P
PERFORM
ABORTAR
COMEÇAR
PRONTO
Transição para PERFORM Transição 
para ABORT Transição para ABORT 
Contate outro participante
Figura 8-19. Ações realizadas por um participante P quando você está no estado PRONTO ( PRONTO) 
e entrou em contato com outro participante Q.
Para garantir que um processo possa realmente ser recuperado, ele precisa manter seu estado no armazenamento 
persistente. (Como os dados podem ser salvos de forma tolerante a falhas é discutido posteriormente neste capítulo.) Por 
exemplo, se um participante estava no estado INICIAR, após a recuperação, você pode decidir com segurança abortar 
localmente a transação e então
358 CAPÍTULO 8 TOLERÂNCIA AO ERRO
informar o coordenador. Além disso, quando você já tomou uma decisão, como congelar durante o COMPROMETE 
ou ABORTAR, É retornar a esse estado e transmitir sua decisão ao coordenador.
Os problemas surgem quando um participante congela enquanto está no estado
PRONTO. Nesse caso, quando ele se recuperar, você não poderá decidir por si mesmo o que fazer a seguir, ou seja, 
realizar ou abortar a transação. Consequentemente, ele é forçado a entrar em contato com outros participantes para saber o 
que fazer, de forma análoga à situação em que ele é retirado do serviço enquanto residia no estado PRONTO conforme já 
descrito.
O coordenador tem apenas dois status críticos para estar ciente. Quando você inicia o protocolo 2PC, deve 
indicar que você está entrando no estado ESPERAR para que eu possa transmitir a mensagem VOTE_REQUEST a 
todos os participantes após a recuperação. Além disso, se você tomou uma decisão na segunda fase, é suficiente 
se essa decisão foi registrada para que possa ser retransmitida quando recuperada.
Na Figura 8-20, apresentamos um plano geral das ações realizadas pelo coordenador. Este primeiro 
multi-transmite uma mensagem VOTE_REQUEST a todos os participantes para coletar seus votos; posteriormente 
registra que está entrando no estado ESPERAR, após o que aguarda a chegada dos votos dos participantes.
Ações realizadas pelo coordenador
escreva START_2PC no registro local;
multistream VOTE_REQUEST para todos os participantes; contanto que nem todos 
os votos sejam recebidos {
aguarde qualquer votação entrante; se 
chegarem fora do prazo {
escreva GLOBAL_ABORT no registro local;
multistream GLOBAL_ABORT para todos os participantes; sair;
}
registrar voto;
}
se todos os participantes enviaram VOTE_COMMIT e o coordenador votar em COMMIT {
escrever GLOBAL_COMMIT no registro local;
multicast GLOBAL_COMMIT para todos os participantes; } se não {
escreva GLOBAL_ABORT no registro local;
multistream GLOBAL_ABORT para todos os participantes;
}
Figura 8-20. Esboço das etapas seguidas pelo coordenador em um protocolo bifásico.
Se nem todos os votos tiverem sido coletados, mas nenhum outro voto for recebido dentro de um determinado intervalo de tempo 
prescrito com antecedência, o coordenador presume que um ou mais participantes falharam. Portanto, você precisará abortar a transação 
e transmitir uma mensagem por multitransmissão GLOBAL_ ABORT para os participantes (restantes).
SEÇÃO 8.5 REALIZAÇÃO DISTRIBUÍDA 359
Se nenhuma falha ocorrer, eventualmente o coordenador terá coletado todos os votos. Se todos os participantes, bem 
como o coordenador votarem pela realização, uma mensagem é gravada primeiro
GLOBAL_COMMIT e posteriormente é enviado para todos os processos. Caso contrário, o coordenador multistream transmite uma 
mensagem GLOBAL_ABORT ( depois de registrá-lo no registro local).
A Figura 8-21 (a) mostra as etapas seguidas por um participante. Primeiro, o processo espera que o coordenador 
peça para você votar. Observe que essa espera pode ser feita por um thread diferente em execução no espaço de 
endereço do processo. Se nenhuma mensagem chegar, a transação será simplesmente abortada. Aparentemente, o 
coordenador falhou.
Após receber um pedido de voto, o participante pode decidir votar pela conclusão da transição, para isso, ele 
primeiro registra sua decisão em um cartório local e, em seguida, informa o coordenador por meio de envio de 
mensagem VOTE_COMMIT. O participante deve então aguardar a decisão global. Partindo do pressuposto de que esta 
decisão (que novamente terá que vir do coordenador) chegue a tempo, fica simplesmente registrada no cartório local, 
após o que pode ser tomada.
No entanto, quando um participante é retirado de serviço enquanto se aguarda a decisão do coordenador, ele executa um 
protocolo de terminação multi-broadcast transmitindo primeiro uma mensagem
DECISION_REQUEST para os outros processos, após o qual ele trava à espera de uma resposta. Quando chega 
uma resposta (possivelmente do coordenador, que se presume que se recuperou ao longo do tempo), o participante 
escreve a decisão em seu registro local e trata-a de acordo.
Cada participante deve estar preparado para aceitar solicitações de uma decisão global dos outros participantes. Para 
tanto, suponha que cada participante inicie um thread diferente, executando simultaneamente com o thread principal do 
participante, conforme mostrado na Figura 8-21 (b). Este thread é bloqueado até que receba uma solicitação de decisão. Só 
pode ajudar outro processo se o seu parceiro participante já tiver chegado a uma decisão final. Em outras palavras, se uma 
mensagem foi escrita GLOBAL_COMMIT ou GLOBAL_ABORT No cartório local, é certo que o coordenador havia pelo menos 
encaminhado sua decisão para esse processo. Além disso, o tópico também pode decidir enviar uma mensagemGLOBAL_ABORT 
quando o seu parceiro participante ainda está no estado INICIAR, conforme discutido anteriormente. Em todos os outros casos, 
o thread de recebimento não pode ajudar e o participante solicitante não receberá uma resposta.
O que se observa é que pode ser possível que um participante tenha que se trancar até que o coordenador se 
recupere. Esta situação ocorre quando todos os participantes receberam e processaram a mensagem VOTE_REQUEST coordenador, 
enquanto, entretanto, o coordenador congela. Nesse caso, os participantes não podem decidir cooperativamente sobre 
a ação final a ser tomada. Por este motivo, o protocolo 2PC também é conhecido como realizando protocolo
bloqueio.
Existem várias soluções para evitar o travamento. Um, descrito por Babaoglu e Toueg (1993), é usar uma primitiva de 
multitransmissão por meio da qual um destinatário imediatamente faz o multicast de uma mensagem recebida para todos os 
outros processos. Este método pode ser mostrado para permitir que um participante chegue a uma decisão final, mesmo 
quando o coordenador ainda não se recuperou. Outra solução é o protocolo de realização trifásico, que é o assunto desta 
seção e que abordamos imediatamente.
360 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Ações realizadas pelo participante:
escrever INIT no registro local;
aguarde a mensagem VOTE_REQUEST enviada pelo coordenador; se chegar fora 
do prazo {
escreva VOTE_ABORT no registro local; sair;
}
se o participante votar em COMMIT {
escreva VOTE_COMMIT no registro local; enviar 
VOTE_COMMIT para o coordenador; aguardar DECISÃO 
enviada pelo coordenador; se chegar fora do prazo {
multistream DECISION_REQUEST para outros participantes; espere até 
receber a DECISÃO; / * permanecer bloqueado * / gravar DECISÃO no 
registro local;
}
sim DECISÃO
escrever GLOBAL_COMMIT no registro local; mas se 
DECISÃO GLOBAL_ABORT
escreva GLOBAL_ABORT no registro local;
GLOBAL_COMMIT
} se não }
escreva VOTE_ABORT no registro local; enviar 
VOTE_ABORT para o coordenador;
}
(para)
Ações para lidar com solicitações de decisão: / * executado por um thread diferente * /
contanto que seja verdade {
aguarde até que qualquer DECISION_REQUEST de entrada seja recebido; / * permanecer bloqueado * / ler o ESTADO 
registrado mais recentemente no registro local;
sim ESTADO GLOBAL_COMMIT
enviar GLOBAL_COMMIT para o participante solicitante; mas se 
ESTADO INIT ou STATE GLOBAL_ABORT
enviar GLOBAL_ABORT para o participante solicitante;
se não
saltar; / * participante permanece bloqueado * /
}
(b)
Figura 8-21. a) Etapas seguidas por um processo participante em 2PC. (b) Etapas para lidar com 
as solicitações recebidas para tomar uma decisão.
SEÇÃO 8.5 REALIZAÇÃO DISTRIBUÍDA 361
8.5.2 Implementação trifásica
Um problema com o protocolo de desempenho bifásico é que, quando o coordenador congela, os participantes podem não 
ser capazes de chegar a uma decisão final. Como resultado, os participantes podem precisar permanecer bloqueados até 
que o coordenador se recupere. Skeen (1981) desenvolveu uma variante do 2PC, chamada protocolo de implementação 
trifásico (3PC, de Inglês
protocolo de confirmação trifásico), que evita que processos sejam bloqueados na presença de congelamentos de prisão. 
Embora o 3PC seja amplamente referido na literatura, na prática não é frequentemente aplicado, pois raramente ocorrem 
condições em que o 2PC é bloqueado. O protocolo é estudado aqui porque dá uma ideia mais completa de como resolver 
problemas de tolerância a falhas em sistemas distribuídos.
Como o 2PC, o 3PC também é formulado em termos de um coordenador e vários participantes. Suas respectivas 
máquinas de estado finito são mostradas na Figura 8-22. A essência deste protocolo é que os estados do coordenador 
e de cada participante satisfaçam as duas seguintes condições:
1. Não há um único estado a partir do qual seja possível fazer a transição diretamente para um estado COMPROMETE 
ou um estado ABORTAR.
2. Não há estado em que não seja possível tirar uma conclusão final, e a partir do qual uma transição 
possa ser feita para um estado COMPROMETA-SE.
Pode-se mostrar que essas duas condições são necessárias e suficientes para um protocolo de desempenho não 
travar (Skeen e Stonebraker, 1983).
Votar por aplicativo
Vote para abortar
Votar por aplicativo
COMEÇAR
Votar por aplicativo
ESPERAR
COMEÇAR
Vote pela realização
PRONTO
Realização
Vote para abortar
Aborto global
ABORTAR
Vote pela realização
Prepare-se para realizar
PRÉ-REALIZAR
Pronto para atuar
Realização global
REALIZAÇÃO
Aborto global
ACR
Prepare-se para realizar
Pronto para atuar
PRÉ-REALIZAR
Realização global
ACR
REALIZAÇÃO
ABORTAR
(para) (b)
Figura 8-22. ( a) Máquina de estados finitos para o coordenador em 3PC. (b) Máquina de estados 
finitos para um participante.
O coordenador em 3PC primeiro envia uma mensagem VOTE_REQUEST a todos os participantes, após o que ele 
aguarda respostas. Se algum participante votar para abortar a transação, a decisão final também será abortada, então o 
coordenador envia uma mensagem GLOBAL_ABORT.
362 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Porém, quando a transação pode ser realizada, uma mensagem é enviada PREPARE_COMMIT.
Somente após a confirmação do recebimento de cada participante estará pronto para atuar, o coordenador enviará a 
mensagem final GLOBAL_COMMIT pelo qual a transação é efetivamente realizada.
Novamente, existem apenas algumas situações em que um processo trava enquanto espera a chegada das mensagens. 
Primeiro, se um participante estiver aguardando a solicitação de voto do coordenador enquanto estiver no estado INICIAR, eventualmente 
mudará para o estado ABORTAR, assumindo que o coordenador congelou. Esta situação é idêntica à implementada em 2PC. 
Da mesma forma, o coordenador pode estar no estado ESPERAR, aguardando os votos dos participantes. Em um tempo limite, 
o coordenador irá concluir que um participante foi congelado e, portanto, abortar a transação multistream transmitindo uma 
mensagem GLOBAL_ABORT.
Agora, suponha que o coordenador esteja bloqueado no estado PRECOMMIT. Em um downtime, você 
concluirá que um dos participantes foi congelado, mas sabe-se que esse participante votou pela conclusão da 
transação. Portanto, o coordenador pode instruir com segurança os participantes operacionais a multitransmitir 
uma mensagem. GLOBAL_COMMIT. Além disso, conta com um protocolo de recuperação para que o 
participante congelado acabe realizando sua parte da transação ao se recuperar.
Um participante P pode ser bloqueado no estado PRONTO ou no estado PRECOMMIT. Em um tempo fora de 
serviço, P ele só pode concluir que o coordenador falhou, então ele deve perguntar o que fazer a seguir. Como no 
protocolo 2PC, sim P entre em contato com qualquer outro participante do estado COMMIT ( ou ABORTAR), ele 
também deve ser passado para esse estado. Além disso, se todos os participantes estiverem no estado PRECOMMIT,
a transação pode ser realizada com segurança.
Novamente como em 2PC, se outro participante Q ainda está no estado INICIAR, a transação pode ser abortada com 
segurança. É importante apontar que Q pode estar no estado INICIAR apenas se nenhum outro participante estiver no estado 
PRECOMMIT. Um participante pode alcançar
PRECOMMIT somente se o coordenador tivesse alcançado o estado PRECOMMIT antes de congelar
e, portanto, recebeu um voto pelo desempenho de cada participante. Em outras palavras, nenhum participante pode 
residir no estado INICIAR enquanto outro participante está no estado PRECOMMIT.
Se cada um dos participantes com quem P pode ser contatado está no estado
PRONTO ( e juntos eles formam a maioria), a transação deve ser abortada. O ponto a ser observado é que outro 
participante pode ter congelado e irá se recuperar mais tarde. No entanto, nenhum
P nem qualquer outro participante operacional sabe qual será o estado do participante congelado quando ele se 
recuperar. Se oprocesso recuperar o estado INICIAR, então, decidir abortar a transação é a única decisão correta. No 
pior caso, o processo pode recuperar o estado PRECOMMIT, mas nada acontecerá se a transação for abortada.
Esta situação é a principal diferença com o 2PC, onde um participante congelado poderia recuperar o estado COMPROMETE 
enquanto todos os outros processos continuam no estado PRONTO. Nesse caso, os processos operacionais restantes não 
poderiam chegar a uma conclusão final e teriam que esperar até que o processo congelado se recuperasse. Com o 3PC, se 
algum processo operacional estiver no estado PRONTO, nenhum processo congelado irá recuperar para um estado diferente
SEÇÃO 8.6 RECUPERAÇÃO 363
de INIT, ABORT ou PRECOMMIT. Por isso, os processos de sobrevivência sempre chegam a uma decisão final.
Finalmente, se os processos que P pode alcançar estão no estado PRECOMMIT ( e formar a maioria), então a 
transação é segura. Novamente, pode ser mostrado que, neste caso, todos os outros processos estarão ou no estado PRONTO 
ou pelo menos eles vão recuperar o status PRONTO, PRECOMITE ou COMPROMETE eles tinham quando foram 
congelados.
Mais detalhes sobre 3PC podem ser encontrados em Bernstein et al. (1987) e em Chow e Johnson (1997).
8.6 RECUPERAÇÃO
Até agora, abordamos principalmente algoritmos que permitem tolerância a falhas. No entanto, uma vez ocorrida uma falha, 
é essencial que o processo em que ela ocorreu possa ser recuperado para um estado correto. A seguir, primeiro abordamos 
o que realmente significa recuperar para um estado correto e, em seguida, vemos quando e como o estado de um sistema 
distribuído pode ser registrado e recuperado, por meio de marcação de pontos de verificação e registro de mensagens.
8.6.1 Introdução
A recuperação de falhas é crítica para a tolerância a falhas. Lembre-se de que um erro é a parte de um sistema 
que pode levar à falha. A ideia geral sobre a recuperação de erros é substituir um estado ruim por um estado livre 
de erros. Basicamente, existem duas maneiras de se recuperar de erros.
No recuperação para trás, o principal é retornar o sistema de seu estado incorreto atual ao estado correto 
anteriormente. Para isso, será necessário registrar o estado do sistema de tempos em tempos e, quando algo 
der errado, restaurar o estado registrado. Cada vez (uma parte) do estado atual do sistema é registrado, diz-se 
que é marcar um
verifique o ponto.
Outra forma de recuperação de erro é o recuperação para a frente. Nesse caso, quando o sistema entra em um estado 
incorreto, em vez de retorná-lo a um estado de ponto de verificação anterior, é feita uma tentativa de trazê-lo para um novo 
estado bom a partir do qual ele pode continuar a funcionar. O principal problema com os mecanismos de recuperação de erro de 
encaminhamento é que você deve saber com antecedência quais erros podem ocorrer. Somente nesse caso é possível corrigir 
os erros e passar para um novo estado.
A distinção entre recuperação de erro anterior e posterior é facilmente explicada quando consideramos a 
implementação de comunicação confiável. O método comum de recuperação de um pacote perdido é permitir 
que o remetente retransmita o pacote. Com efeito, a retransmissão de pacotes estabelece que tentamos voltar a 
um estado anterior correto, ou seja, aquele em que o pacote enviado foi perdido. Comunicação confiável por 
meio de
364 CAPÍTULO 8 TOLERÂNCIA AO ERRO
A retransmissão de pacotes é, portanto, um exemplo da aplicação de técnicas de recuperação de erros 
reversos.
Um procedimento alternativo é usar um método conhecido como correção de apagamento. Neste procedimento, um 
pacote perdido é criado a partir de outro para entregar os pacotes com sucesso. Por exemplo, em um código de apagamento 
de bloco ( n, k), um conjunto de k pacotes originais é criptografado na forma de n pacotes criptografados, então o suficiente uma 
jogo de k pacotes criptografados para reconstruir o k pacotes originais. Valores típicos são k 
Dia 16 k 32, e k n 2 k
[ver, por exemplo, Rizzo (1997)]. Se ainda não houver pacotes suficientes entregues, o remetente deve continuar a 
transmitir pacotes até que um pacote perdido anteriormente possa ser construído. A correção de apagamento é um 
exemplo típico de método de recuperação de erro antecipado.
Em sistemas distribuídos, as técnicas de recuperação reversa de erros são, de longe, as mais amplamente 
aplicadas como mecanismo geral de recuperação de falhas. O principal benefício da recuperação reversa de erros é 
que ela é geralmente aplicável e independente de qualquer sistema ou processo específico. Em outras palavras, ele 
pode ser incorporado (na camada de middleware de) um sistema distribuído como um serviço de propósito geral.
No entanto, a recuperação retroativa de erros também apresenta alguns problemas (Singhal e Shivaratri, 
1994). Primeiro, restaurar um sistema ou processo a um estado anterior geralmente é uma operação relativamente 
cara em termos de desempenho. Como você verá nas seções subsequentes, muitas vezes é necessário realizar 
muito trabalho para recuperar, por exemplo, um congelamento de processo ou falha no site. Uma possível saída 
para esse problema é criar mecanismos muito baratos pelos quais os componentes simplesmente reiniciem. 
Voltaremos a este método mais tarde.
Em segundo lugar, uma vez que os mecanismos de recuperação de erro são independentes do aplicativo distribuído para 
o qual são realmente usados, nenhuma garantia pode ser dada de que, uma vez que a recuperação ocorra, a mesma falha ou 
falha semelhante não ocorrerá novamente. Se essas garantias forem necessárias, o tratamento de erros geralmente requer que 
o aplicativo entre no loop de recuperação. Em outras palavras, transparência de falha totalmente madura, em geral, não pode 
ser fornecida por mecanismos de recuperação de erro reverso.
Finalmente, embora a recuperação reversa de erros exija a marcação de um ponto de verificação, alguns 
estados simplesmente não podem voltar. Por exemplo, depois que uma pessoa (possivelmente 
mal-intencionada) pega os $ 1.000 que saíram repentinamente de um caixa eletrônico com defeito, há apenas 
uma pequena chance de que o dinheiro seja devolvido à máquina. Além disso, na maioria dos sistemas UNIX, a 
recuperação a um estado anterior após uma digitação intensa.
rm fr *
mas, no diretório com erros, pode deixar muitas pessoas pálidas. Alguns erros são simplesmente irreversíveis.
A marcação do ponto de verificação permite que você volte a um estado anterior. No entanto, costuma ser uma 
operação cara que pode penalizar gravemente o desempenho. Consequentemente, muitos sistemas distribuídos tolerantes a 
falhas combinam a marcação de pontos de controle com o
SEÇÃO 8.6 RECUPERAÇÃO 365
log de mensagens. Neste caso, depois que um ponto de verificação foi executado, um processo (chamado registro baseado no 
remetente) registre suas mensagens antes de enviá-las. Uma solução alternativa é fazer com que o processo de recebimento 
registre uma mensagem de entrada antes de entregá-la ao aplicativo que você está executando. Este esquema também é 
conhecido como Registro baseado em destinatário. Quando um processo de recebimento congela, ele precisa ser restaurado ao 
estado mais recentemente marcado com um ponto de verificação e, a partir daí, aconteceu denovo as mensagens que foram 
enviadas. Portanto, combinando pontos de verificação com o registro de mensagens, é possível recuperar um estado localizado 
além do ponto de verificação mais recente sem o custo de marcar os pontos de verificação.
Segue-se outra distinção importante entre marcar pontos de verificação e esquemas que, adicionalmente, usam 
registros. Em um sistema onde apenas a marcação de ponto de verificação é usada, os processos serão restaurados para 
um estado marcado com um ponto de verificação. A partir daí, seu comportamento pode ser diferente do que era antes de 
ocorrer a falha. Por exemplo, como ostempos de comunicação não são determinísticos, eles agora podem ser entregues 
em uma ordem diferente, o que, por sua vez, faz com que os destinatários reajam de maneira diferente. No entanto, se o 
log de mensagens ocorrer, ocorre uma verdadeira recapitulação dos eventos desde a última marcação do ponto de 
verificação. Essa recapitulação facilita a interação com o mundo exterior.
Por exemplo, considere o caso em que ocorreu uma falha porque um usuário forneceu a entrada errada. Se 
apenas a marcação do ponto de verificação for usada, o sistema terá que marcar um ponto de verificação antes de 
aceitar a entrada do usuário para recuperar exatamente o mesmo estado. Com o registro de mensagens, uma 
marcação de ponto de verificação antiga pode ser usada, após a qual um encerramento de eventos pode ocorrer até o 
ponto em que o usuário precisará fornecer entrada. Na prática, a combinação de marcar alguns pontos de verificação 
e registrar mensagens é mais eficiente do que marcar muitos pontos de verificação.
Armazenamento estável
Para recuperar a um estado anterior, é necessário que as informações necessárias para permitir a recuperação sejam 
armazenadas com segurança. Segurança neste contexto significa que a recuperação sobrevive a congelamentos de processos e 
falhas de site, mas talvez também a várias falhas de mídia de armazenamento. O armazenamento estável desempenha um papel 
muito importante quando se trata de recuperação em sistemas distribuídos. Aqui nós o analisamos brevemente.
O armazenamento vem em três categorias. Em primeiro lugar, existe a RAM comum que é apagada quando há 
queda de energia ou uma máquina congela. Em segundo lugar, temos o armazenamento em disco, que sobrevive a 
falhas de CPU, mas também pode ser perdido quando ocorrem falhas na cabeça do disco.
Finalmente, também há armazenamento estável, que é projetado para sobreviver a qualquer coisa, exceto 
calamidades extremas, como inundações ou terremotos. O armazenamento estável pode ser implementado com 
um par de discos comuns, conforme mostrado na Figura 8-23 (a). Cada bloco gravado no disco 2 é uma cópia exata 
do bloco correspondente incluído no disco 1. Quando um bloco é atualizado, o bloco no disco 1 é atualizado e 
verificado primeiro, então o mesmo é feito no bloco correspondente no disco 2 .
366 CAPÍTULO 8 TOLERÂNCIA AO ERRO
O setor tem
valores diferentes
aC aC
aC
para
h
d
e
para ¿
h
d
e
para
h
d
e
gf gf
gf
Soma de
Verifica
errado
aC aC aC
para
h
d
e
para
h
d
e
para
h
d
e
gf gf gf
(para) (b) (c)
Figura 8-23. ( a) Armazenamento estável. (b) Congelamento após a atualização do disco 1. (c) 
Local ruim.
Suponha que o sistema congele depois que o disco 1 é atualizado, mas antes que o disco 2 seja atualizado, 
conforme ilustrado na Figura 8-23 (b). Ao recuperar, o disco pode ser comparado bloco a bloco. Sempre que dois 
blocos correspondentes diferem, pode-se presumir que o disco 1 é o correto (porque o disco 1 é sempre atualizado 
antes do disco 2), então o novo bloco é copiado do disco 1 para o disco 2. Quando o processo de recuperação, 
ambos os discos serão novamente idênticos.
Outro problema potencial é a deterioração espontânea de um bloco. Em um bloco válido anteriormente, 
partículas de poeira ou desgaste geral podem causar um erro repentino de checksum, sem qualquer causa aparente 
ou aviso, conforme mostrado na Figura 8-23 (c). Quando um erro como esse é detectado, o bloco defeituoso pode 
ser regenerado a partir do bloco correspondente localizado no outro disco.
Como resultado dessa implementação, o armazenamento estável é adequado para aplicativos que exigem um alto 
grau de tolerância a falhas, como transações atômicas. Quando os dados são gravados no armazenamento estável e 
depois lidos para verificar se foram gravados corretamente, a probabilidade de que sejam perdidos posteriormente é 
extremamente pequena.
Nas seções a seguir, abordamos as marcações de pontos de verificação e o registro de mensagens em mais 
detalhes. Elnozahy et al. (2002) fornecem um estudo sobre marcação e registro de pontos de verificação em sistemas 
distribuídos. Vários detalhes algorítmicos podem ser encontrados em Chow e Johnson (1997).
8.6.2 Marcando pontos de controle
Em um sistema distribuído tolerante a falhas, a recuperação reversa de falhas exige que o sistema salve regularmente 
seu estado no armazenamento estável. Em particular, um estado global consistente deve ser registrado, também 
chamado instantâneo distribuído. Em um instantâneo
SEÇÃO 8.6 RECUPERAÇÃO 367
distribuído, se um processo P registrou o recebimento de uma mensagem, então também deve haver um processo Q que 
registrou o envio da referida mensagem. Afinal, a mensagem deve vir de algum lugar.
Estado inicial
Linha de recuperação
Check Point
P1
Falha
P2
Mensagem enviada
de P2 a P1
Clima
Coleção inconsistente
de pontos de controle
Figura 8-24. Linha de recuperação.
Em esquemas de recuperação de falha reversa, cada processo de vez em quando salva seu estado no 
armazenamento estável disponível localmente. Para recuperar após uma falha de processo ou sistema, você precisa 
criar um estado global consistente a partir desses estados locais. Em particular, é melhor recuperar para o instantâneo 
distribuído mais recente, também conhecido como linha de recuperação. Em outras palavras, uma linha de recuperação 
corresponde à coleção consistente mais recente de pontos de controle, conforme mostrado na Figura 8-24.
Marcação de checkpoint independente
Infelizmente, a natureza distribuída da marcação do ponto de verificação (onde cada processo simplesmente registra seu 
estado local de vez em quando de uma maneira descoordenada) pode dificultar a localização de uma linha de 
recuperação. A descoberta de uma linha de recuperação exige que cada processo volte ao estado salvo mais 
recentemente. Se esses estados locais juntos não formarem um instantâneo distribuído, mais retrocesso será necessário. 
Descreveremos uma maneira de encontrar uma linha de recuperação abaixo. Este processo de reversão em cascata 
pode levar ao que é conhecido como Efeito dominó, e é mostrado na Figura 8-25.
Estado inicial
Check Point
P1
m m
Falha
P2
Clima
Figura 8-25. Efeito dominó.
368 CAPÍTULO 8 TOLERÂNCIA AO ERRO
Quando um processo P 2 congela, ele tem que recuperar seu estado para o ponto de controle mais
salvo recentemente. Consequentemente, o processo P 1 também terá que ser empurrado para trás. Infelizmente, os dois estados 
locais salvos mais recentemente não formam um estado global que consiste em
tente: o estado salvo por P 2 indica o recebimento de uma mensagem m, mas nenhum outro processo pode ser identificado como 
seu remetente. Por tanto, P 2 tem que ser regredido a um estado anterior.
No entanto, o próximo estado ao qual P 2 está para trás também não pode ser usado como
parte de um instantâneo distribuído. Neste caso, P 1 terá registrado o recebimento da mensagem m ¿,
mas não há nenhum evento registrado de que esta mensagem está sendo enviada. Por consequência,
você precisa voltar também P 1 a um estado anterior. Neste exemplo, verifica-se que a linha de recuperação é na 
verdade o estado inicial do sistema.
Uma vez que os processos marcam pontos de controle locais independentes uns dos outros, este método também
também é conhecido como marcação de ponto de verificação independente. Uma solução alternativa
é para coordenar globalmente a marcação dos pontos de controle, como veremos a seguir, mas a coordenação 
requer sincronização global, o que pode apresentar problemas de desempenho. Outra desvantagem da marcação 
de ponto de verificação independente é que cada armazenamento local deve ser limpo periodicamente, por 
exemplo, executando um coletor de lixo distribuído especial. No entanto, a principal desvantagem está no cálculo 
da linha de recuperação.
Implementar a marcação de ponto de verificação independente requer que as dependências sejamregistradas 
para que os processos possam reverter em conjunto para um estado global
consistente. Para esse efeito, vamos PC Eu ( m) o ponto de controle m- o levado pelo processo P Eu.
Além disso, seja INT Eu ( m) o intervalo entre os pontos de verificação PC Eu ( m 1) e PC Eu ( m).
Quando o processo P Eu envie uma mensagem no intervalo INT Eu ( m), incorporar o par ( Eu estou) para o processo de 
recebimento. Quando o processo P j recebe uma mensagem no intervalo INT j ( n) junto com o par de índices ( Eu estou), então registre 
a dependência INT Eu ( m) → INT j ( n). Sempre que P j assumir o ponto de controle PC j ( n), além disso, grava essa dependência em seu 
armazenamento estável local, junto com o resto das informações de recuperação que fazem parte do PC j ( n).
Agora suponha que em um determinado momento o processo seja necessário P 1 de volta ao ponto de verificação PC Eu ( m 
1). Para garantir a consistência global, devemos garantir que todos
processos que receberam mensagens de P Eu enviado no intervalo INT Eu ( m) são revertidos para um estado de ponto de 
verificação antes de receber as mensagens. Em particular, o processo P j isto é
nosso exemplo terá que ser revertido para pelo menos o ponto de verificação PC j ( n 1). sim PC j
( n 1) não leva a um estado globalmente consistente, mais retrocesso pode ser necessário.
O cálculo da linha de recuperação requer uma análise das dependências do intervalo registradas por cada 
processo quando um ponto de controle é obtido. Sem entrar em mais detalhes, verifica-se que os cálculos são bastante 
complexos e não justificam a necessidade de marcação de checkpoint independente em comparação com a marcação 
de checkpoint coordenado. Além disso, como se constatou, muitas vezes não é a coordenação entre processos que é o 
fator de desempenho dominante, mas sim a sobrecarga de ter que salvar o estado em armazenamento local estável. 
Consequentemente, a marcação de ponto de controle coordenado, mais simples do que a marcação de ponto de 
controle independente, é frequentemente mais popular e provavelmente permanecerá assim mesmo quando os sistemas 
crescerem para tamanhos muito maiores (Elnozahy e Planck,
SEÇÃO 8.6 RECUPERAÇÃO 369
Marcação de checkpoint coordenado
Como o próprio nome sugere, no marcação de checkpoint coordenado todos os processos são sincronizados para 
gravar em conjunto seu estado em um armazenamento local estável. A principal vantagem da marcação de ponto de 
verificação coordenada é que o estado salvo é automática e globalmente consistente, evitando reversões que levam a 
um efeito dominó. O algoritmo de instantâneo distribuído que apresentamos no Capítulo 6 pode ser usado para 
coordenar a marcação de pontos de controle coordenados. Este algoritmo é um exemplo de coordenação de 
marcação de ponto de verificação sem bloqueio.
Uma solução mais simples é usar um protocolo de bloqueio bifásico. Um coordenador primeiro multi-transmite uma 
mensagem CHECKPOINT_REQUEST para todos os processos. Quando um processo recebe essa mensagem, ele apreende 
um ponto de verificação local, enfileira todas as mensagens subsequentes entregues a ele pelo aplicativo em execução e 
confirma ao coordenador que conquistou um ponto de verificação. Quando o coordenador recebe uma confirmação de todos 
os processos, ele multiplica uma mensagem CHECKPOINT_DONE para permitir que processos (bloqueados) continuem.
É fácil ver que esse método também leva a um estado globalmente consistente, porque nenhuma mensagem de 
entrada é registrada como parte de um ponto de verificação. A razão para isso é que qualquer mensagem que segue uma 
solicitação para capturar um ponto de verificação não é considerada parte do ponto de verificação local. Ao mesmo tempo, as 
mensagens de saída (conforme entregues ao processo de marcação do ponto de verificação pelo aplicativo em execução) 
são enfileiradas localmente até que a mensagem seja recebida. CHECKPOINT_DONE.
Uma melhoria nesse algoritmo é a multitransmissão de uma solicitação de ponto de verificação apenas para aqueles 
processos que dependem da recuperação do coordenador e ignoram os outros processos. Um processo depende do 
coordenador se ele recebeu uma mensagem que está direta ou indiretamente relacionada causalmente a uma mensagem 
que o coordenador enviou do último ponto de verificação. Isso leva à noção de instantâneo incremental.
Para obter uma captura instantânea incremental, o coordenador faz o multitransmissão de uma solicitação para marcar 
um ponto de verificação apenas para os processos para os quais ele enviou uma mensagem desde a última vez que fez um 
ponto de verificação. Quando um processo P recebe uma requisição como essa, encaminha para todos os processos para os 
quais enviou mensagem desde o último checkpoint, e assim por diante. Um processo envia a solicitação apenas uma vez. 
Quando todos os processos forem identificados, um segundo multistream é usado para ativar a marcação do ponto de 
verificação e permitir que os processos continuem de onde pararam.
8.6.3 Registro de mensagens
Considerando que a marcação de pontos de controle é uma operação onerosa, principalmente no que diz respeito às operações 
envolvidas na gravação de seu estado para um armazenamento estável, técnicas têm sido buscadas para reduzir o número de 
pontos de controle, mas ainda assim permitindo a recuperação. Em sistemas distribuídos, uma técnica importante é o registro 
de mensagens.
A ideia básica por trás do registro de mensagens é que se você pode repetir transmissão de mensagens, ainda 
é possível atingir um estado globalmente consistente, mas sem ter que
370 CAPÍTULO 8 TOLERÂNCIA AO ERRO
restaure-o do armazenamento estável. Em vez disso, um estado com marcação de ponto de verificação é considerado o 
ponto de partida e todas as mensagens enviadas desde então são simplesmente retransmitidas e tratadas de acordo.
Este método funciona bem sob o pressuposto do que é chamado de modelo determinístico fragmentado. Neste 
modelo, assume-se que a execução de cada processo ocorre como uma série de intervalos em que os eventos 
ocorrem. Esses eventos são iguais aos que estudamos no contexto do relacionamento Lamport denominado 
ocorrência anterior no Capítulo 6. Por exemplo, um evento pode ser a execução de uma instrução, o envio de uma 
mensagem e assim por diante. No modelo determinístico fragmentado, assumimos que cada intervalo começa com um 
evento não determinístico, como o recebimento de uma mensagem. Porém, a partir desse momento, a execução do 
processo é totalmente determinística. Um intervalo termina com o último evento antes de ocorrer um evento não 
determinístico.
Na verdade, um intervalo pode ser repetido com um resultado conhecido, ou seja, de forma totalmente determinística, 
desde que seja repetido a partir do mesmo evento não determinístico de antes. Consequentemente, se todos os eventos 
não determinísticos presentes naquele modelo forem registrados, torna-se possível repetir completamente toda a execução 
de um processo de forma determinística.
Considerando que os logs de mensagens são necessários para se recuperar de um congelamento de processo 
para que um estado globalmente consistente seja restaurado, torna-se importante saber precisamente quando as 
mensagens devem ser registradas. Seguindo o método descrito por Alvisi e Marzullo (1998), verifica-se que muitos 
esquemas de registro de mensagens existentes podem ser caracterizados com facilidade, se nos concentrarmos em 
como eles lidam com processos órfãos.
UMA processo órfão é um processo que sobrevive ao congelamento de outro processo, mas cujo estado é 
inconsistente com o processo congelado após sua recuperação. Como exemplo, considere a situação mostrada na 
Figura 8-26. O processo Q receber as mensagens
m 1 Y m 2 dos processos P Y R, respectivamente, e então enviar uma mensagem m 3 para R. Contudo-
vá, em contraste com todas as outras mensagens, a mensagem m 2 nãoestá registrado. Se o processo
Q é congelado e posteriormente recuperado, apenas as mensagens registradas necessárias para o
recuperação de Q são repetidos, em nosso exemplo, m 1 Como m 2 sua transmissão não foi gravada
A sessão não se repetirá, o que significa que a transmissão de m 3 também não pode ocorrer, Figura 8-26.
No entanto, a situação após a recuperação de Q é inconsistente com o que tinha
antes dessa recuperação. Em particular, R mantenha uma mensagem m 3) que foi enviado antes do congelamento. É claro 
que essas inconsistências devem ser evitadas.
Caracterização de esquemas de registro de mensagens
Para caracterizar os diferentes esquemas de registro de mensagens, segue-se o método descrito em Alvisi e Marzullo 
(1998). Cada mensagem é considerada m tem um cabeçalho contendo todas as informações necessárias para retransmitir m 
e manuseie-o adequadamente. Por exemplo, cada cabeçalho identificará o remetente e o destinatário, mas também um 
número sequencial para
SEÇÃO 8.6 RECUPERAÇÃO 371
Q congela e se recupera
P
m1 m1
m2 nunca se repete e nem 
é m3
m3
Q
m3
m2
m2
R
Mensagem não registrada
Mensagem registrada
Clima
Figura 8-26. A revisão incorreta das mensagens após a recuperação leva ao processo órfão.
reconhecê-lo como uma duplicata. Além disso, um número de entrega pode ser adicionado para decidir exatamente quando deve 
ser entregue ao aplicativo de recebimento.
Diz-se que uma mensagem é estábulo se não puder mais ser perdido, por exemplo, porque foi gravado no 
armazenamento estável. Portanto, as mensagens estáveis podem ser usadas para recuperação, repetindo sua transmissão.
Cada mensagem m leva a um conjunto DEP (m) processos que dependem da entrega de m.
Em particular, DEP (m) é composto por aqueles processos para os quais m Foi dado. Além disso, se outra mensagem m ¿ é 
causalmente dependente da entrega de m, Y m ¿ foi entregue a um processo Q, tão Q também estará contido em DEP (m). Vamos 
observar que m ¿ é causalmente dependente da entrega de m, se foi enviado pelo mesmo processo que entregou 
anteriormente m,
ou quem entregou outra mensagem que era causalmente dependente da entrega de m.
O conjunto CÓPIA (m) consiste naqueles processos que têm uma cópia de m, mas eles (ainda) não estão em seu 
armazenamento estável local. Quando um processo Q entregar a mensagem m, também se torna um membro de CÓPIA (m). Observe 
que CÓPIA (m) consiste naqueles processos que podem entregar uma cópia do m que pode ser usado para transmitir m. Se 
todos esses processos congelarem, a retransmissão de m certamente não é viável.
Usando essas notações, agora é fácil definir precisamente o que é um processo órfão. Suponha que em um sistema 
distribuído alguns processos acabaram de ser congelados. Estar Q um dos processos de sobrevivência. O processo Q é um 
processo órfão se existir uma mensagem m, de tal forma que Q está contido em DEP (m), enquanto, ao mesmo tempo, cada 
processo incluído no CÓPIA (m)
congelou. Em outras palavras, um processo órfão parece que depende de m, mas não há como repetir a 
transmissão de m.
Para evitar processos órfãos, deve-se garantir que, se cada processo incluído no
CÓPIA (m) congela, então nenhum processo de sobrevivência permanece em DEP (m). Ou seja, todos os processos 
incluídos em DEP (m) eles também devem ter sido congelados. Você pode tornar esta condição verdadeira se puder garantir 
que sempre que um processo se tornar um membro de
DEP (m), também se tornar um membro de CÓPIA (m). Ou seja, sempre que um processo torna-se dependente da entrega 
de m, manterá uma cópia de m.
Existem essencialmente dois métodos que podem ser seguidos. O primeiro, é representado por aqueles chamados protocolos 
de registro pessimistas. Esses protocolos cuidam disso por
372 CAPÍTULO 8 TOLERÂNCIA AO ERRO
cada mensagem não estável m, há no máximo um processo dependente de m. Em outras palavras, os protocolos de registro 
pessimista garantem que cada mensagem não estável n ser entregue a, no máximo, um processo. Vamos observar que m é 
entregue, por exemplo, ao processo P, P torna-se um membro de CÓPIA (m).
O pior que pode acontecer é que o processo P congelar sem m foi registrado. Com registro pessimista, não é 
permitido P não envie mensagem após a entrega m sem primeiro ter certeza de que m ele foi gravado no 
armazenamento estável. Consequentemente, nenhum outro processo ficará dependente da entrega de m para P sem 
possibilidade de retransmissão m. Desta forma, um processo órfão é sempre evitado.
Em contraste, em um protocolo de registro otimista, o próprio trabalho está feito
depois de que ocorre uma ulceração pelo frio. Em particular, suponha que para alguma mensagem m cada processo 
incluído em CÓPIA (m) congelou. Em um método otimista, qualquer processo órfão em DEP (m) é regredido a um estado 
em que não pertence mais DEP (m). Obviamente, os protocolos de registro otimistas não devem perder de vista as 
dependências, o que complica sua implementação.
Conforme observado em Elnozahy et al. (2002), o registro pessimista é muito mais simples do que os métodos 
otimistas, tornando-o a forma preferida de registro de mensagens no projeto prático de sistema distribuído.
8.6.4 Computação Orientada à Recuperação
Uma forma relacionada de lidar com a recuperação é, em essência, começar de novo. O principal princípio por trás 
dessa forma de esconder falhas é que pode ser muito mais barato otimizar para recuperação, ou seja, procurar 
sistemas que não falham por muito tempo. Este método também é conhecido como computação orientada para 
recuperação ( Candea et al., 2004a).
Existem diferentes tipos de computação orientada para recuperação. Um é simplesmente reinicializar (uma parte de 
um sistema), e tem sido explorado para reinicializar servidores de Internet (Candea et al., 2004b, 2006). Para reinicializar 
apenas parte do sistema, é crucial localizar corretamente a falha. Nesse ponto, reiniciar significa simplesmente excluir 
todas as instâncias dos componentes identificados, junto com os threads que operam neles, e (frequentemente) 
simplesmente reiniciar as solicitações associadas. Observe que a localização da falha em si pode ser um exercício não 
trivial (Steinder e Sethi, 2004).
Habilitar a reinicialização como uma técnica de recuperação prática requer que os componentes sejam 
altamente desacoplados, no sentido de que há poucas ou nenhuma dependência entre os vários componentes. Se 
houver dependências fortes, localizar e analisar a falha pode exigir uma reinicialização de todo o servidor até o ponto 
em que a aplicação de técnicas de recuperação tradicionais, como as estudadas aqui, possam ser mais eficientes.
Outro sabor da computação orientada para recuperação é a aplicação de marcação de pontos de verificação e 
técnicas de recuperação, mas continuando a funcionar em um ambiente alterado. A ideia básica neste caso é que muitas 
falhas podem simplesmente ser evitadas se os programas tiverem mais espaço no buffer, zerando a memória antes de 
alocá-la, mudando a ordem da memória.
SEÇÃO 8.7 RESUMO 373
entrega de mensagens (desde que não afete a semântica), etc. (Qin et al., 2005). A ideia fundamental é resolver as 
falhas de software (ao passo que muitas das técnicas examinadas até agora têm como objetivo resolver ou são 
baseadas em falhas de hardware). Como a execução do software é altamente determinística, alterar o ambiente de 
execução pode salvar o dia, mas é claro sem consertar nada.
8.7 RESUMO
A tolerância a falhas é uma questão importante no projeto de sistemas distribuídos. A tolerância a falhas é definida 
como a característica pela qual um sistema pode ocultar a ocorrência e reparo de falhas. Em outras palavras, um 
sistema é tolerante a falhas se puder continuar a operar na presença de falhas.
Existem vários tipos de falhas. Uma falha de congelamento ocorre quando um processo simplesmente para. Uma 
falha padrão ocorre quando um processo não responde àssolicitações de entrada. Quando um processo responde 
muito rapidamente ou muito tarde a uma solicitação, ele exibe uma falha de tempo. Responder a uma solicitação 
recebida, mas da maneira errada, é um exemplo de falha de resposta. As falhas mais difíceis de tratar, chamadas 
falhas arbitrárias ou bizantinas, são aquelas em que um processo apresenta qualquer tipo de falha.
A redundância é a técnica fundamental necessária para alcançar a tolerância a falhas. Quando aplicada a processos, 
a noção de grupos de processos torna-se importante. Um grupo de processos é formado por vários processos que 
cooperam estreitamente para fornecer um serviço. Em grupos de processos tolerantes a falhas, um ou mais processos 
podem falhar sem afetar a disponibilidade do serviço oferecido pelo grupo. Freqüentemente, é necessário que a 
comunicação dentro do grupo seja altamente confiável e respeite a atomicidade estrita e as propriedades de ordenação 
para obter tolerância a falhas.
A comunicação de grupo confiável, também chamada de multitransmissão confiável, ocorre de maneiras 
diferentes. Desde que os grupos sejam relativamente pequenos, a implementação da confiabilidade é viável. No entanto, 
quando grupos muito grandes precisam ser suportados, a escalabilidade da multitransmissão confiável torna-se 
problemática. O principal problema para alcançar escalabilidade é reduzir o número de mensagens de feedback pelas 
quais os receptores relatam a recepção (malsucedida) de uma mensagem de multi-difusão.
As coisas pioram quando você tem que fornecer atomicidade. Em protocolos de multitransmissão atômicos, é essencial 
que cada membro do grupo tenha a mesma visão de para quais membros uma mensagem de multitransmissão foi entregue. 
A multitransmissão atômica pode ser formulada com precisão com base em um modelo de execução síncrona virtual. Em 
essência, esse modelo apresenta limites entre quais membros do grupo não mudam e quais mensagens são transmitidas de 
forma confiável. Uma mensagem nunca pode cruzar uma fronteira.
As mudanças de membros do grupo são um exemplo em que cada processo deve concordar com a mesma 
lista de membros. Tal acordo pode ser alcançado por meio de protocolos de implementação, sendo a bifásica a 
mais aplicada. Em um protocolo de desempenho bifásico, um coordenador primeiro investiga se todos os 
processos concordam em realizar
374 CAPÍTULO 8 TOLERÂNCIA AO ERRO
a mesma operação (isto é, se todos concordarem em realizá-la), e em um segundo turno multi-transmite o resultado da 
referida pesquisa. Um protocolo de realização trifásico é usado para lidar com o congelamento do coordenador sem ter 
que travar todos os processos para chegar a um acordo até que o coordenador se recupere.
Em sistemas tolerantes a falhas, a recuperação é invariavelmente alcançada verificando o estado do 
sistema regularmente. A marcação do ponto de verificação é totalmente distribuída. Infelizmente, fazer um 
checkpoint é uma operação cara. Para melhorar o desempenho, muitos sistemas distribuídos combinam 
marcação de checkpoint com registro de mensagens. Ao registrar a comunicação entre os processos, é 
possível repetir a execução do sistema após o congelamento.
PROBLEMAS
1 Freqüentemente, sistemas confiáveis são necessários para fornecer um alto grau de segurança. Por quê?
O que torna o modelo de parada de falha, no caso de falhas de congelamento, tão difícil de implementar?
Considere um navegador da web que retorna uma página em cache desatualizada em vez de uma mais recente que foi 
atualizada no servidor. Isso é uma falha? Em caso afirmativo, que tipo de falha?
O modelo de redundância modular tripla descrito no texto pode lidar com as falhas bizantinas?
Quantos elementos com falha (dispositivos mais votação) a Figura 8-2 pode controlar? Forneça um exemplo do pior caso 
que pode ser disfarçado.
O TMR generaliza para cinco itens por grupo em vez de três? Em caso afirmativo, quais propriedades ele possui?
Para cada uma das seguintes aplicações, você acha que a semântica de pelo menos uma vez ou a semântica de no 
máximo uma vez é melhor? Analise isso.
(a) Ler e gravar arquivos de um servidor de arquivos. (b) Compile um 
programa.
(c) Realizar operações bancárias remotas.
Com RPC assíncrono, um cliente trava até que sua solicitação seja aceitaram pelo servidor. Até que ponto as falhas 
afetam a semântica do RPC assíncrono?
Dê um exemplo em que a comunicação em grupo não exija nenhuma ordem de mensagens.
2
3 -
Quatro.
5
6
7
8
9
SEÇÃO 8.7 RESUMO 375
10 Em multicast confiável, é sempre necessário que a camada de comunicação mantenha uma cópia de uma mensagem 
para fins de retransmissão?
Qual a importância da escalabilidade multitransmissão atômica?
No texto, sugerimos que a multitransmissão atômica pode salvar o dia quando se trata de atualizar um conjunto 
acordado de processos. Em que medida é possível garantir que cada atualização seja realmente realizada?
A sincronização virtual é análoga à consistência fraca em armazenamentos de dados distribuídos, com alterações de exibição 
de grupo atuando como pontos de sincronização. Nesse contexto, qual seria o análogo de consistência forte?
Quais são os pedidos de entrega permitidos para a combinação de pedido FIFO e multitransmissão em pedido 
completo na Figura 8-15?
Adapte o protocolo para instalar a seguinte vista G Eu 1 no caso de sincronização virtual para que possa tolerar falhas de 
processo.
No protocolo de implementação bifásico, por que a trava nunca pode ser totalmente removida, mesmo quando os 
participantes elegem um novo coordenador?
Em nossa explicação sobre a conclusão trifásica, parece que a condução de uma transação é baseada na votação por 
maioria. Isto é certo?
Em um modelo de execução determinístico fragmentado, é suficiente apenas registrar mensagens ou outros eventos também 
precisam ser registrados?
Explique como o log write-ahead pode ser usado em transações distribuídas para se recuperar de falhas.
Um servidor sem estado precisa fazer checkpoints?
O log de mensagens baseado no receptor é geralmente considerado melhor do que o log baseado no remetente. Por 
quê?
onze.
12
13
14
quinze.
16
17
18
19
vinte.
vinte e um.
9
SEGURANÇA
O último princípio de sistemas distribuídos que é discutido é o da segurança. A segurança não é de forma alguma o ponto 
menos importante. No entanto, pode-se argumentar que é uma das mais difíceis, uma vez que a segurança deve estar 
presente em todo o sistema. Uma única falha de projeto no que diz respeito à segurança pode tornar todas as medidas de 
segurança inúteis. Neste capítulo, prestamos atenção especial aos vários mecanismos geralmente construídos em 
sistemas distribuídos para oferecer suporte à segurança.
Primeiro, apresentamos as questões básicas de segurança. Incorporar vários mecanismos de segurança em um 
sistema realmente não faz sentido, a menos que você saiba como eles devem ser usados e contra o quê. Isso implica 
conhecimento da política de segurança a ser aplicada. A noção de uma política de segurança, junto com alguns problemas 
de design para os mecanismos que ajudam a aplicá-la, é tratada primeiro. A criptografia necessária também é abordada 
brevemente.
A segurança em sistemas distribuídos geralmente é dividida em duas partes. Uma parte tem a ver com a 
comunicação entre usuários e processos, que possivelmente residem em máquinas diferentes. O principal mecanismo 
para garantir uma comunicação segura é um canal seguro. Canais seguros e, mais especificamente, a integridade e 
confidencialidade da mensagem de autenticação, são abordados em outra seção.
A outra parte do tópico de segurança trata da autorização, que garante que um processo obtenha apenas os 
direitos de acesso aos recursos de um sistema distribuído para o qual está autorizado. A autorização é abordada 
em uma seção separada que trata do controle de acesso. Além dos mecanismos de acesso tradicionais, também é 
dada atençãoao controle de acesso que tem a ver com códigos móveis, como agentes.
377
378 CAPÍTULO 9 SEGURANÇA
Canais seguros e controle de acesso requerem mecanismos de distribuição de chaves criptográficas, mas também 
mecanismos para adicionar ou remover usuários de um sistema. Esses problemas são resolvidos pelo que é conhecido 
como gerenciamento de segurança. Em uma seção separada, discutimos tópicos relacionados a chaves criptográficas, 
gerenciamento de grupo seguro e concessão de certificados que verificam se o proprietário está autorizado a acessar 
recursos específicos.
9.1 INTRODUÇÃO À SEGURANÇA
Começamos a descrição da segurança em sistemas distribuídos com uma revisão de alguns tópicos gerais de 
segurança. Primeiro, você precisa definir o que é um sistema seguro. o política segurança de mecanismos segurança 
e um sistema de área ampla Globus é estudado para o qual uma política de segurança foi formulada explicitamente. 
Em segundo lugar, alguns problemas gerais de design sobre sistemas seguros são considerados. Finalmente, alguns 
algoritmos criptográficos são analisados, os quais desempenham um papel essencial no projeto de protocolos de 
segurança.
9.1.1 Ameaças, políticas e mecanismos de segurança
Em um sistema de computador, a segurança está fortemente relacionada à noção de confiabilidade. Informalmente, 
um sistema de computador confiável é aquele em que acreditamos que fornecerá seus serviços (Laprie, 1995). 
Conforme mencionado no Capítulo 7, confiabilidade inclui disponibilidade, consistência, segurança e 
sustentabilidade. No entanto, se um sistema de computador é confiável, a confidencialidade e a integridade 
também devem ser levadas em consideração. Confidencialidade refere-se à propriedade de um sistema de 
computador pelo qual suas informações são disponibilizadas apenas para pessoas autorizadas. o
integridade é a característica de que as modificações dos ativos de um sistema só podem ser feitas de forma 
autorizada. Ou seja, em um sistema de computador seguro, as modificações inadequadas devem ser detectáveis 
e recuperáveis. Os principais ativos de qualquer sistema de computador são seu hardware, seus programas e seus 
dados.
Outra maneira de olhar para a segurança em sistemas de computador é como uma tentativa de proteger os serviços e 
dados que ela oferece contra ameaças à segurança. Existem quatro tipos de ameaças à segurança a serem considerados 
(Pfleeger, 2003):
1. Interceptação
2. Interrupção
3. Modificação
4. Fabricação
O conceito de interceptação refere-se à situação em que uma pessoa não autorizada conseguiu acessar serviços ou 
dados. Um exemplo típico de interceptação é aquele em que a comunicação
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 379
entre duas pessoas é ouvido por outra pessoa. A interceptação também ocorre quando os dados são copiados 
ilegalmente, por exemplo, após violar o diretório privado de uma pessoa contido em um sistema de arquivos.
Um exemplo de interrupção é quando um arquivo é corrompido ou perdido. De forma mais geral, a interrupção se 
refere à situação em que os serviços ou dados não estão mais disponíveis, tornam-se inúteis ou destruídos e assim por 
diante. Nesse caso, neutralizar ataques por meio dos quais alguém tenta de forma maliciosa impedir que outras pessoas 
acessem um serviço é uma ameaça à segurança classificada como uma interrupção.
As modificações envolvem a alteração não autorizada ou manipulação de um serviço de tal forma que ele não mais 
adere às suas especificações originais. Os exemplos de modificações incluem a interceptação e subsequente alteração dos 
dados transmitidos, adulteração das entradas do banco de dados e alteração de um programa para que ele registre 
secretamente as atividades de seu usuário.
Fabricação refere-se à situação em que são gerados dados ou atividades adicionais que normalmente não existiriam. 
Por exemplo, um invasor pode tentar adicionar uma entrada a um banco de dados ou arquivo de senha. Além disso, às vezes 
é possível violar um sistema, reabastecendo mensagens enviadas anteriormente. Você verá esses exemplos mais adiante 
neste capítulo.
É importante observar que a interrupção, modificação e fabricação podem ser vistas como uma forma de 
falsificação de dados.
A simples afirmação de que um sistema deve ser capaz de se proteger contra ameaças potenciais à segurança 
não é uma maneira de realmente construir um sistema seguro. A primeira coisa a fazer é descrever os requisitos de 
segurança, ou seja, estabelecer uma política de segurança. UMA política de segurança descreve com precisão 
quais ações são permitidas às entidades de um sistema e quais são proibidas. Entidades incluem usuários, serviços, 
dados, máquinas, etc. Uma vez que uma política de segurança é delineada, é possível focar no
mecanismo de segurança pelo qual pode ser aplicado. Os mecanismos de segurança importantes são:
1. Criptografia
2. Autenticação
3. Autorização
4. Auditoria
A criptografia é crítica para a segurança de um computador. A criptografia transforma os dados em algo que um invasor não 
consegue entender. Em outras palavras, a criptografia permite implementar a confidencialidade dos dados. Além disso, permite 
verificar se os dados foram modificados. Ele também oferece suporte a verificações de integridade.
A autenticação é usada para verificar a identidade pretendida de um usuário, cliente, servidor, host ou outra 
entidade. No caso de clientes, a premissa básica é que antes que um servidor comece a realizar qualquer trabalho em 
nome de um cliente, o serviço deve aprender a identidade
380 CAPÍTULO 9 SEGURANÇA
cliente (a menos que o serviço esteja disponível para todos). Normalmente, os usuários são autenticados por meio 
de senhas, embora haja muitas outras maneiras de fazer isso.
Após a autenticação de um cliente, é necessário verificar se ele está autorizado a executar a ação solicitada. Um 
exemplo típico é acessar registros de um banco de dados médico. Dependendo de quem está acessando o banco de 
dados, eles podem ter permissão para ler os registros, modificar determinados campos em um registro ou adicionar ou 
excluir um registro.
Ferramentas de auditoria são usadas para rastrear o que e como os clientes acessaram. Embora a auditoria 
não proteja realmente contra ameaças de segurança, seus logs podem ser extremamente úteis para analisar uma 
violação de segurança e tomar medidas subsequentes contra intrusos. Por esse motivo, em geral, os invasores 
têm o cuidado de não deixar evidências que possam expor sua identidade ao longo do tempo. Nesse sentido, o 
log de acesso transforma um ataque em um negócio arriscado.
Exemplo: arquitetura de segurança Globus
A noção de política de segurança e o papel que os mecanismos de segurança desempenham em sistemas distribuídos na 
aplicação de tais políticas são geralmente mais bem compreendidos examinando-se um exemplo concreto. Considere a política 
de segurança definida para o sistema de área ampla Globus (Chervenak et al., 2000). Globus é um sistema que suporta 
cálculos distribuídos em grande escala nos quais muitos hosts, arquivos e outros recursos são usados ao mesmo tempo para 
realizar um cálculo. Esses ambientes também são conhecidos como malhas computacionais (Foster e Kesselman, 2003). 
Nessas malhas, os recursos geralmente estão localizados em diferentes domínios administrativos que podem estar localizados 
em diferentes partes do mundo.
Como os usuários e recursos são muitos e amplamente distribuídos em diferentes domínios 
administrativos, a segurança é essencial. Para planejar e usar os mecanismos de segurança de maneira 
adequada, é necessário entender exatamente o que precisa ser protegido e quais são as premissas em relação 
à segurança. Para simplificar, a política de segurança do Globus impõe as oito afirmações a seguir, que são 
explicadas a seguir (Foster et al., 1998):
1. O ambiente é composto de vários domínios administrativos.
2. As operações locais(ou seja, as operações executadas apenas em um único domínio) estão sujeitas a 
uma política de segurança de domínio local.
3. As operações globais (ou seja, as operações que envolvem vários domínios) requerem que o iniciador seja 
conhecido em cada um dos domínios onde a operação é executada.
4. As operações entre entidades em diferentes domínios requerem autenticação mútua.
5. A autenticação global substitui o local.
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 381
6. O controle de acesso aos recursos está sujeito apenas à segurança local.
7. Os usuários podem delegar direitos aos processos.
8. Um grupo de processos localizado no mesmo domínio pode compartilhar credenciais.
Globus assume que o ambiente é composto de vários domínios administrativos, onde cada domínio tem sua própria 
política de segurança local. Presume-se que as políticas locais não podem ser alteradas apenas porque o domínio 
participa do Globus, nem pode a política global do Globus substituir as decisões de segurança locais. 
Consequentemente, a segurança na Globus será limitada a operações que afetam vários domínios.
Algo relacionado a esta questão é que Globus assume que operações consideradas totalmente locais em relação a 
um domínio estão sujeitas apenas à política de segurança do domínio. Em outras palavras, se uma operação for iniciada 
e executada dentro de um único domínio, todos os problemas de segurança serão tratados apenas por medidas de 
segurança locais. Globus não vai impor medidas adicionais.
A política de segurança Globus estipula que os pedidos de operação podem ser iniciados global ou localmente. 
O iniciador, seja um usuário ou um processo agindo em nome de um usuário, deve ser conhecido localmente dentro 
de cada domínio onde essa operação é realizada. Por exemplo, um usuário pode ter um nome global mapeado para 
nomes locais em um domínio específico. Como exatamente a correlação ocorre é deixada para cada domínio.
Uma importante estipulação de política é que as operações entre entidades localizadas em domínios 
diferentes requerem autenticação mútua. Isso significa, por exemplo, que se o usuário de um domínio usa um 
serviço de outro domínio, sua identidade terá que ser verificada. Igualmente importante é que o usuário tenha 
certeza de que está usando o serviço que deveria usar. Voltaremos à autenticação mais extensivamente 
posteriormente neste capítulo.
Os dois tópicos de segurança anteriores são combinados no seguinte requisito de segurança. Se a identidade 
de um usuário foi verificada e se o usuário também é conhecido localmente em um domínio, ele pode atuar como 
autenticado para esse domínio local. Isso significa que o Globus requer que suas medidas de autenticação em todo 
o sistema sejam suficientes para considerar que um usuário já foi autenticado para um domínio remoto (onde esse 
usuário é conhecido) ao acessar os recursos desse domínio. Nenhuma autenticação adicional será exigida pelo 
domínio local.
Uma vez que o usuário (ou o processo agindo em nome de um usuário) tenha sido autenticado, ainda é 
necessário verificar os direitos de acesso exatos com respeito aos recursos. Por exemplo, um usuário que deseja 
modificar um arquivo deve primeiro ser autenticado, após o que pode ser verificado se ele realmente tem ou não 
permissão para modificar o arquivo. A política de segurança Globus estabelece que tais decisões de controle de 
acesso sejam inteiramente locais dentro do domínio onde o recurso acessado está localizado.
Para explicar a sétima afirmação, vamos considerar um agente móvel Globus que executa uma tarefa iniciando várias 
operações em domínios diferentes, uma após a outra. Esse agente pode levar muito tempo para concluir sua tarefa. Para não 
ter que se comunicar com o usuário em nome de quem
382 CAPÍTULO 9 SEGURANÇA
agente está agindo, Globus requer que os processos possam ser delegados a um subconjunto de direitos do 
usuário. Consequentemente, com a autenticação de um agente e a posterior verificação dos seus direitos, Globus 
deve ser capaz de permitir que um agente inicie uma operação sem ter de contactar o seu titular.
Como estipulação final de sua política, a Globus exige que grupos de processos que são executados em um único 
domínio e agem em nome do mesmo usuário possam compartilhar um único conjunto de credenciais. Como será explicado 
a seguir, a autenticação requer credenciais. Essa estipulação abre a porta para soluções de autenticação escalonáveis, 
pois não exige que cada processo execute seu próprio conjunto exclusivo de credenciais.
A política de segurança da Globus permite que seus designers se concentrem no desenvolvimento de uma solução de 
segurança abrangente. Supondo que cada domínio aplique sua própria política de segurança, Globus se concentra apenas 
nas ameaças à segurança que envolvem vários domínios. Em particular, a política de segurança indica que questões 
importantes de design são a representação de um usuário em um domínio remoto e a alocação de recursos de um domínio 
remoto para um usuário ou seu representante. Consequentemente, o que Globus requer principalmente são mecanismos de 
autenticação de domínio cruzado e fazer um usuário ser reconhecido em domínios remotos.
Para tanto, são apresentados dois tipos de representantes. UMA proxy do usuário é um processo que tem permissão 
para agir em nome de um usuário por um período limitado de tempo. Os recursos são representados por proxies de recursos. 
UMA proxy de recursos É um processo executado dentro de um domínio específico usado para transformar operações 
globais em um recurso em operações locais que estejam em conformidade com a política de segurança do domínio 
específico. Por exemplo, um proxy de usuário normalmente se comunica com um proxy de recurso quando o acesso a seus 
recursos é necessário.
A arquitetura de segurança Globus, em essência, é composta de entidades como usuários, proxies de usuários, 
proxies de recursos e processos gerais. Essas entidades estão em domínios e interagem umas com as outras. Em 
particular, a arquitetura de segurança define quatro protocolos diferentes, conforme ilustrado na Figura 9-1 [ver também 
Foster et al. (1998)].
O primeiro protocolo descreve com precisão como um usuário pode criar um proxy e delegar direitos a ele. Em particular, 
para permitir que o proxy do usuário atue em nome de seu usuário, o usuário concede ao proxy um conjunto apropriado de 
credenciais.
O segundo protocolo especifica como um proxy de usuário pode solicitar a alocação de um recurso localizado em 
um domínio remoto. Em essência, o protocolo informa a um proxy de recursos para criar um processo no domínio 
remoto após a autenticação mútua. Esse processo representa o usuário (exatamente como o proxy do usuário 
representava), embora opere no mesmo domínio do recurso solicitado. O processo tem permissão para acessar o 
recurso de acordo com as decisões de controle de acesso local relativas a esse domínio.
Um processo criado em um domínio remoto pode iniciar cálculos adicionais em outros domínios. Conseqüentemente, um 
protocolo é necessário para alocar recursos em um domínio remoto, conforme solicitado por um processo diferente de um 
proxy de usuário. No sistema Globus, este tipo de alocação é feito através da intermediação do proxy do usuário, permitindo 
que um processo faça com que o seu proxy do usuário associado solicite a alocação de recursos, essencialmente seguindo o 
segundo protocolo.
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 383
Protocolo 3:
Atribuição de um recurso por um processo 
localizado em um domínio remoto
Domínio
O proxy cria
um processo
Domínio
Processo
Proxy de recursos
Processo
Proxy de recursos
Política e
mecanismos de
segurança local
Correlação
global para local
de IDs
Política e
mecanismos de
segurança local
Processo Processo
Correlação
global para local
de IDs
Protocolo 4:
Torne o usuário 
conhecido no domínio 
remoto
O usuário deve ser 
conhecido no domínioO processo cria
um processo filho
Protocolo 2:
Atribuição de um recurso pelo usuário 
localizado em um domínio remoto
Proxy
do utilizador
Protocolo 1:
Criação de um
proxy do usuário
Domínio
Do utilizador
Figura 9-1. Arquitetura de segurança Globus.
O quarto e último protocolo da arquitetura de segurança Globus é a maneira pela qual um usuário pode se tornar 
conhecido em um domínio. Assumindo que um usuário possui uma conta em um domínio, o que deve ser estabelecido é que 
as credenciais implementadas em todo o sistema, à medida que aparecem no proxy do usuário, são automaticamente 
convertidas em credenciais reconhecidas pelo domínio específico. O protocolo decreta como a correlação entre as 
credenciais globais e locais pode ser registrada pelo usuário em uma tabela de mapeamento local com relação ao domínio 
específico.
Detalhes específicos de cada protocolo são descritos em Foster et al. (1998). A questão importante neste caso é que 
a arquitetura de segurança Globus reflete sua política de segurança conforme estabelecido anteriormente. Os 
mecanismos usados para implementar essa arquitetura, particularmente os protocolos mencionados acima, são comuns 
a muitos sistemas distribuídos e são discutidos extensivamente neste capítulo. A principal dificuldade em projetar sistemas 
distribuídos seguros não está nos mecanismos de segurança, mas em decidir como eles devem ser tratados.
384 CAPÍTULO 9 SEGURANÇA
ser usado para impor uma política de segurança. Na próxima seção, veremos algumas dessas decisões de 
design.
9.1.2 Temas de design
Um sistema distribuído, ou qualquer sistema de computador, deve fornecer serviços de segurança por meio dos quais uma 
ampla gama de políticas de segurança pode ser implementada. Existem vários problemas de design importantes que 
devem ser levados em consideração ao implementar serviços de segurança de propósito geral. Nas páginas a seguir, 
discutiremos três desses temas: abordagem para controle, organização em camadas dos mecanismos de segurança e 
simplicidade [ver também Gollmann (2006)].
Abordagem de controle
Ao considerar a proteção de um aplicativo (possivelmente distribuído), existem basicamente três métodos 
diferentes que podem ser seguidos, conforme mostrado na Figura 9-2. O primeiro método é focar diretamente na 
proteção dos dados associados ao aplicativo. Significa diretamente que, independentemente das várias 
operações que podem ser realizadas em um item de dados, o principal interesse é garantir sua integridade. Em 
geral, esse tipo de proteção ocorre em sistemas de banco de dados nos quais várias restrições de integridade 
podem ser formuladas, as quais são verificadas automaticamente cada vez que um item de dados é modificado 
[ver, por exemplo, Doorn e Rivero (2002)] .
O segundo método é focar na proteção, especificando exatamente quais operações podem ser chamadas e por 
quem, quando certos dados ou recursos devem ser acessados. Nesse caso, a abordagem de controle está fortemente 
relacionada aos mecanismos de controle de acesso, que são discutidos extensivamente mais adiante neste capítulo. Por 
exemplo, em um sistema baseado em objeto, você pode decidir especificar - para cada método - o que é disponibilizado 
aos clientes e quais clientes têm permissão para invocá-lo. Como alternativa, os métodos de controle de acesso podem 
ser aplicados a toda a interface oferecida por um objeto ou a todo o objeto. Este método, portanto, permite várias 
granularidades de controle de acesso.
Um terceiro método é direcionar os usuários diretamente, tomando medidas pelas quais apenas pessoas 
específicas tenham acesso ao aplicativo, independentemente das operações que desejam realizar. Por exemplo, em 
um banco, um banco de dados pode ser protegido negando o acesso a qualquer pessoa, exceto à alta administração 
e àqueles especificamente autorizados a acessá-lo. Como outro exemplo, em muitas universidades, determinados 
dados e aplicativos só podem ser usados por professores e funcionários, enquanto o acesso não é permitido aos 
alunos. Na realidade, o controle está focado em definir o papéis que os usuários têm, e assim que a função de um 
usuário for verificada, eles têm ou não têm acesso a um recurso. Como parte do projeto de um sistema seguro, é 
necessário definir as funções que as pessoas podem ter e fornecer mecanismos para oferecer suporte ao controle de 
acesso baseado em funções. Mais adiante neste capítulo, retornaremos ao tópico dos papéis.
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 385
Os dados são protegidos contra 
operações erradas ou inválidas
Os dados são protegidos contra 
invocações não autorizadas
Estado
Objeto
Invocação Método
(para) (b)
Os dados são protegidos 
verificando a função do 
invocador
(c)
Figura 9-2. Três métodos de proteção contra ameaças à segurança: (a) Proteção contra 
operações inválidas. (b) Proteção contra invocações não autorizadas. (c) Proteção contra 
usuários não autorizados.
Organização em camadas de mecanismos de segurança
Uma questão importante ao projetar sistemas seguros é decidir em que nível os mecanismos de segurança devem ser 
colocados. Nesse contexto, um nível está relacionado à organização lógica de um sistema em várias camadas. Por exemplo, as 
redes de computadores são frequentemente organizadas em camadas seguindo um modelo de referência, como visto no 
Capítulo 4. O Capítulo 1 apresentou a organização de sistemas distribuídos compostos de camadas distintas para aplicativos, 
middleware e serviços de sistema. sistema operacional e o kernel (kernel) do sistema operacional. A combinação da 
organização em camadas de redes de computadores e sistemas distribuídos leva aproximadamente ao que é mostrado na 
Figura 9-3.
Em essência, a Figura 9-3 separa os serviços de uso geral dos serviços de comunicação. Essa separação é 
importante para entender a organização em camadas de segurança em sistemas distribuídos e, em particular, a noção 
de confiança. A diferença entre confiança e segurança é importante. Um sistema é seguro ou não (se várias medidas 
probabilísticas forem levadas em consideração), mas se um cliente considera um sistema seguro é uma questão de 
confiança (Bispo,
2003). A segurança é técnica; a confiança é emocional. A camada na qual os mecanismos de segurança são colocados 
depende da confiança que um cliente tem na segurança dos serviços em uma determinada camada.
386 CAPÍTULO 9 SEGURANÇA
Inscrição
Middleware
Serviços de sistema operacional
Núcleo 
Transporte
TÃO 
Internet
Link de dados
Hardware Físico
Inscrição
Middleware
Serviços de sistema operacional
Transporte
Internet
Link de dados
Fisica
Protocolos
alto nível
Núcleo
TÃO
Hardware
Protocolos
baixo nivel
Internet
Figura 9-3. Organização lógica de um sistema multicamadas.
Como exemplo, vamos considerar uma organização localizada em diferentes sites conectados por um serviço de 
comunicação, como Switched Multi-megabit Data Service (SMDS). Uma rede SMDS pode ser considerada como uma 
rede central ( espinha dorsal) que conecta várias redes locais localizadas em localizações geográficas possivelmente 
dispersas, conforme mostrado na Figura 9-4.
Dispositivo de criptografia
SMDS
Figura 9-4. Vários sites conectados por um serviço de entroncamento de área ampla.
A segurança pode ser fornecida colocando dispositivos de criptografia em cada roteador SMDS, como também mostrado 
na Figura 9-4. Esses dispositivos criptografam e descriptografam automaticamente os pacotes enviados entre sites, embora 
não forneçam comunicação segura entre servidores no mesmo site. Se no local PARA Alice manda mensagem para Bob no 
site B e você está preocupado com a interceptação de sua mensagem, deve pelo menos confiar que a criptografia do tráfego 
entre os sites está funcionando corretamente. Isso significa, por exemplo, que você deve confiar que os administradores de 
ambos os sites tomaram as medidas adequadas contra a manipulação não autorizadados dispositivos.
Agora, suponha que Alice não confie na segurança do tráfego entre sites. Você pode então decidir tomar suas 
próprias medidas usando um serviço de segurança de nível de transporte, como SSL. SSL significa Secure Sockets 
Layer, e pode ser usado para enviar mensagens com segurança por meio de uma conexão TCP. Mais tarde no 
Capítulo 12, discutiremos os detalhes
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 387
de um SSL quando introduzimos sistemas baseados na web. O ponto importante a se notar neste caso é que o SSL permite que 
Alice estabeleça uma conexão segura com Bob. Todas as mensagens no nível de transporte serão criptografadas - e no nível 
SMDS também, mas isso não preocupa Alicia. Nesse caso, você terá que contar com SSL. Em outras palavras, você acha que 
SSL é seguro.
Em sistemas distribuídos, os dispositivos de segurança geralmente são colocados na camada de middleware. Se 
Alice não confiar em SSL, ela pode querer usar um serviço RPC seguro. Novamente, você terá que confiar que esse 
serviço RPC cumpre o que promete, como nenhum vazamento de informações ou autenticação adequada de clientes e 
servidores.
Os serviços de segurança colocados na camada de middleware podem ser confiáveis apenas se os serviços dos 
quais eles dependem forem realmente seguros. Por exemplo, se um serviço RPC seguro for implementado em parte 
por meio de SSL, a confiança no serviço RPC depende de quanta confiança existe no SSL. Se o SSL não for confiável, 
a segurança do serviço RPC não será confiável.
Distribuição de mecanismos de segurança
Dependências entre serviços em termos de confiança levam à noção de um Trusted Computing Base (TCB). Um 
TCB é o conjunto de todos os mecanismos de segurança implementados em um sistema de computador (distribuído) 
que são necessários para fazer cumprir uma política de segurança e, portanto, deve ser confiável. Quanto menor o 
TCB, melhor. Se um sistema distribuído for construído como middleware em um sistema operacional de rede 
existente, sua segurança dependerá da segurança dos sistemas operacionais locais subjacentes. Em outras palavras, 
em um sistema distribuído, o TCB pode incluir os sistemas operacionais locais em vários hosts.
Vamos considerar um servidor de arquivos em um sistema distribuído. Esse servidor pode precisar contar com os vários 
mecanismos de proteção oferecidos por seu sistema operacional local. Esses mecanismos incluem não apenas aqueles que 
protegem os arquivos contra o acesso por processos diferentes do servidor de arquivos, mas também os mecanismos que 
protegem o servidor contra tentativas maliciosas de contorná-lo.
Os sistemas distribuídos baseados em middleware, portanto, requerem confiança nos sistemas operacionais locais 
existentes dos quais dependem. Se essa confiança não existir, pode ser necessário incorporar algumas das 
funcionalidades dos sistemas operacionais locais no próprio sistema distribuído. Vamos considerar um sistema 
operacional micro-core, no qual a maioria de seus serviços funcionam como processos normais do usuário. Nesse caso, o 
sistema de arquivos, por exemplo, pode ser totalmente substituído por outro adequado às necessidades específicas de 
um sistema distribuído, incluindo suas diversas medidas de segurança.
Compatível com este método é separar os serviços de segurança de outros tipos de serviços, distribuindo-os em várias 
máquinas de acordo com o grau de segurança exigido. Por exemplo, para um sistema de arquivos distribuído seguro, pode ser 
possível isolar o servidor dos clientes colocando-o em uma máquina com um sistema operacional confiável, possivelmente 
controlando um sistema de arquivos dedicado e seguro. Os clientes e seus aplicativos são colocados em máquinas não 
confiáveis.
Essa separação reduz efetivamente o TCB a um número relativamente pequeno de máquinas e componentes 
de software. Com a subsequente proteção das referidas máquinas contra
388 CAPÍTULO 9 SEGURANÇA
ataques de segurança externos, a confiança geral do sistema distribuído pode ser aumentada. No
o método Interfaces reduzidas para componentes de sistema seguros (RISSC) acesso é impedido
de clientes e suas aplicações a serviços críticos, conforme descrito em Neumann (1995). No método RISSC, qualquer 
servidor de segurança crítica é colocado em outra máquina isolada dos sistemas do usuário final com interfaces de rede 
de baixa segurança, conforme mostrado na Figura 9-5. Os clientes e seus aplicativos são executados em máquinas 
diferentes e podem acessar o servidor seguro apenas por meio dessas interfaces de rede.
Sem acesso direto
de outras máquinas
Servidores executando serviços seguros
Dispositivo
controle de acesso
Servidor inseguro
clientes
Figura 9-5. Princípio do método RISSC aplicado a sistemas distribuídos seguros.
Simplicidade
Outra questão importante de design relacionada à decisão em qual camada colocar os mecanismos de segurança 
é a simplicidade. Projetar um sistema de computador seguro é geralmente considerado uma tarefa difícil. 
Portanto, se o projetista de um sistema usar alguns mecanismos simples, fáceis de entender e confiáveis para 
trabalhar, tanto melhor.
Infelizmente, mecanismos simples nem sempre são suficientes para implementar políticas de segurança. 
Vamos reconsiderar a situação em que Alice deseja enviar uma mensagem para Bob. A criptografia em nível de 
link é um mecanismo simples e fácil de entender que protege contra a interceptação do tráfego de mensagens 
entre sites. No entanto, muito mais é necessário se Alice quiser ter certeza de que apenas Bob receberá suas 
mensagens. Nesse caso, os serviços de autenticação em nível de usuário são necessários e Alice pode 
precisar saber como os serviços funcionam para confiar neles. A autenticação no nível do usuário pode, 
portanto, exigir pelo menos alguma noção sobre as chaves criptográficas e algum conhecimento de 
mecanismos como certificados,
Em outros casos, o aplicativo em si é inerentemente complexo e a introdução de segurança só piora as coisas. Um 
exemplo de domínio de aplicativo que envolve protocolos de segurança (como será visto mais adiante neste capítulo) é o de 
sistemas de pagamento digital. A complexidade dos protocolos de pagamento digital geralmente se origina da necessidade 
de várias pessoas se comunicarem para fazer um pagamento. Nestes casos, é importante que os mecanismos subjacentes 
utilizem
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 389
As ferramentas para implementar os protocolos são relativamente simples e fáceis de entender. A simplicidade ajudará 
a aumentar a confiança que os usuários finais depositarão no aplicativo e, mais importante, convencerá os designers de 
que o sistema não tem brechas de segurança.
9.1.3 Criptografia
O uso de técnicas criptográficas é essencial para segurança em sistemas distribuídos. A ideia básica de aplicar essas técnicas 
é simples. Vamos considerar um remetente S você quer transmitir uma mensagem m para um destinatário R. Para proteger a 
mensagem contra ameaças de segurança, o remetente primeiro figura para transformá-lo em uma mensagem ininteligível m ¿ e 
depois enviar m ¿
para R. R, por sua vez, deve decifrar a mensagem recebida para devolvê-la à sua forma original m.
A criptografia e a descriptografia são realizadas com métodos criptográficos parametrizados por chave, conforme mostrado 
na Figura 9-6. A forma original da mensagem enviada é chamada texto comum
( texto simples), mostrado como P na Figura 9-6; a forma criptografada é conhecida como texto cifrado
( texto cifrado), ilustrado como C.
O intruso passivo
apenas ouça C
O intruso ativo pode 
modificar mensagens
O intruso ativo pode
inserir mensagens
Texto comum, P
Método de
criptografia
Texto criptografado
C = E K ( P)
Método de
criptografia
Texto comum
Chave
criptografia, E K
Chave
criptografia, D K
Remetente
Destinatário
Figura 9-6. Intrusos e bisbilhoteiros na comunicação.
Para descrever os vários protocolos de segurançausados ao construir serviços de segurança para 
sistemas distribuídos, é útil ter uma notação que relacione texto simples, texto cifrado e chaves. Seguindo as 
convenções de notação comum, usaremos
C E K ( P) para denotar que o texto cifrado C é obtido criptografando o texto simples P usando a chave K. Da mesma forma, P 
D K ( C) é usado para expressar a descriptografia do texto cifrado C por
meio da chave K para obter o texto comum P.
Vamos voltar ao exemplo mostrado na Figura 9-6, onde observamos que ao transferir uma mensagem como texto 
cifrado C, Existem três ataques que devem ser protegidos e para os quais a criptografia ajuda. Em primeiro lugar, um intruso 
pode interceptar a mensagem sem o remetente
390 CAPÍTULO 9 SEGURANÇA
Ou o destinatário perceberá que alguém está bisbilhotando. Obviamente, se a mensagem transmitida foi criptografada 
de forma que não seja fácil descriptografar sem a chave adequada, a interceptação é inútil; o intruso verá apenas dados 
ininteligíveis. (A propósito, apenas transmitir uma mensagem às vezes pode ser suficiente para um intruso tirar 
conclusões. Por exemplo, se durante uma crise global a quantidade de tráfego para a Casa Branca cair repentinamente, 
enquanto a quantidade o tráfego para uma determinada montanha no Colorado aumenta na mesma proporção, sabendo 
que essa informação pode ser útil.)
O segundo tipo de ataque a ser considerado é a modificação da mensagem. Modificar o texto comum é fácil; o do 
texto que foi criptografado adequadamente é muito mais difícil porque o intruso terá primeiro de descriptografá-lo antes 
de modificá-lo. Além disso, você também terá que criptografá-lo novamente de forma adequada, caso contrário, o 
destinatário pode perceber que a mensagem foi adulterada.
O terceiro tipo de ataque é quando um intruso insere mensagens criptografadas no sistema de comunicação 
com o objetivo de R acho que essas mensagens foram enviadas por S.
Novamente, como você verá mais adiante neste capítulo, a criptografia pode proteger contra esses ataques. Observe que 
se um invasor é capaz de modificar as mensagens, ele também é capaz de inseri-las.
Há uma distinção fundamental entre os diferentes sistemas criptográficos, que se baseia no fato de as chaves de 
criptografia e descriptografia serem iguais ou não. Em um cifra simétrica a mesma chave é usada para criptografar e 
descriptografar uma mensagem. Em outros termos,
P D K ( E K ( P))
As cifras simétricas também são conhecidas como chave secreta ou sistemas de chave compartilhada, porque o 
remetente e o destinatário precisam compartilhar a mesma chave e, para garantir que a proteção funcione, essa chave 
compartilhada deve ser mantida em segredo; a ninguém
mais você tem permissão para ver. Nós vamos usar K A, B para denotar uma chave compartilhada por PARA Y B.
Em um sistema de criptografia assimétrica, as chaves de criptografia e descriptografia são diferentes, mas
juntos, eles formam um par único. Em outras palavras, há uma chave diferente K E para criptografar e outro para descriptografar, K D, de modo que
P D K ( E K ( P))
D E
Em um sistema de criptografia assimétrica, uma das chaves é mantida privada; o outro é tornado público. Por este motivo, as 
cifras assimétricas também são conhecidas como sistemas de chave pública.
A partir daqui, vamos usar a notação K PARA para denotar uma chave pública pertencente a PARA, Y K PARA
como sua chave privada correspondente.
Em antecipação às explicações detalhadas sobre os protocolos de segurança que apresentaremos mais tarde, quais das 
chaves de criptografia e descriptografia que são realmente tornadas públicas dependem de como as chaves são usadas. Por 
exemplo, se Alice deseja enviar uma mensagem confidencial para Bob, ela deve usar a chave pública de Bob para criptografar a 
mensagem. Como Bob é o único que conhece a chave de descriptografia privada, ele também é a única pessoa que pode 
descriptografá-la.
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 391
Por outro lado, suponha que Bob queira ter certeza de que a mensagem que acabou de receber é realmente de Alice. 
Nesse caso, Alicia pode manter sua chave de criptografia privada para criptografar as mensagens que ela envia. Se Bob for 
capaz de descriptografar uma mensagem com a chave pública de Alice (o texto simples da mensagem contém informações 
significativas o suficiente para Bob), ele saberá que foi Alice quem enviou a mensagem porque a chave de descriptografia está 
unicamente vinculada à chave. criptografia. Voltaremos a esses algoritmos em detalhes posteriormente.
Uma aplicação final da criptografia em sistemas distribuídos é o uso de funções hash. Uma função hash H considere uma 
mensagem m de comprimento arbitrário como entrada e produz uma string de bits h saída de comprimento fixo:
h H (m)
Um hash h é um pouco comparável aos bits extras anexados a uma mensagem em sistemas de comunicação 
para permitir a detecção de erros, como a verificação de redundância cíclica ( CRC, por suas siglas em inglês).
As funções hash usadas em sistemas criptográficos possuem várias propriedades essenciais. Em primeiro lugar, 
eles são funções unilaterais, ou seja, computacionalmente, não é viável encontrar a entrada m que corresponde a uma 
saída conhecida h. Além disso, calcule h a partir de m é facil. Em segundo lugar, as funções unilaterais têm a 
propriedade de resistência fraca à colisão, isso significa que, dado uma entrada m e sua saída associada h 
H (m), compu-
opcionalmente, não é possível localizar uma entrada diferente m ¿ ≠ m de modo que H (m) H (m ?). Por
Por último, as funções de hash criptográficas também têm a propriedade de forte resistência à colisão, Isso significa que quando 
apenas H é conhecido, computacionalmente não é viável encontrar dois valores de entrada diferentes m Y m ¿, assim que H (m) 
H (m ?).
A função de criptografia E e as chaves usadas devem ter propriedades semelhantes. Além disso, para qualquer função de 
criptografia E, não deve ser computacionalmente viável encontrar a chave K
quando o texto comum é fornecido P e texto cifrado associado C E K ( P). Da mesma forma, analógico
à resistência à colisão, quando você tem um texto comum P e uma chave K, deve ser eficaz-
mente impossível encontrar outra chave K ¿ de modo que E K ( P) E K ( P).
A arte e a ciência de desenvolver algoritmos para sistemas criptográficos têm uma longa e fascinante
história (Kahn, 1967), e construir sistemas seguros é muitas vezes surpreendentemente difícil ou mesmo impossível 
(Schneier, 2000). Está além do escopo deste livro estudar em detalhes qualquer algoritmo. No entanto, para se ter uma 
ideia da criptografia em sistemas de computador, três algoritmos representativos serão brevemente discutidos a seguir. 
Informações detalhadas sobre esses e outros algoritmos criptográficos podem ser encontradas em Ferguson e 
Schneier (2003), Menezes et al. (1996) e Schneier (1996).
Antes de entrar nos detalhes dos vários protocolos, um resumo da notação e abreviações usadas nas 
seguintes expressões matemáticas é apresentado na Figura 9-7.
Criptossistemas simétricos: DES
Um excelente exemplo de algoritmo criptográfico é o Padrão de criptografia de dados (DES), que é usado para 
implementar criptosistemas simétricos. DES foi projetado para operar com blocos
392 CAPÍTULO 9 SEGURANÇA
Notação Descrição
K A, B Chave secreta compartilhada por PARA Y B
Chave pública de PARA
Chave privada de PARA
K PARA
K PARA
Figura 9-7. Notação usada neste capítulo.
Dados de 64 bits. Um bloco é transformado em um bloco de saída criptografado (64 bits) em 16 rodadas, onde cada 
rodada usa uma chave de criptografia diferente de 48 bits. Cada uma dessas 16 chaves é derivada de uma chave mestra 
de 56 bits, conforme mostrado na Figura 9-8 (a). Antes de um bloco de entrada começar suas 16 rodadas de cifra, ele 
primeiro passa por uma permutação inicial, da qual o inverso é subsequentemente aplicado à saída da cifra que leva ao 
bloco de saídafinal.
+ = ImJ / -JZm 8 /
Permutação inicial
K 1
Rodada 1
eu eu 1 R eu 1
K 16
eu eu 1 f (R eu 1, K Eu)
Rodada 16
Permutação final
+ = ImJ / - 8 / m8 /
eu Eu R Eu
(para)
Figura 9-8. ( a) Princípio do algoritmo DES. (b) Plano geral para uma rodada de criptografia.
(b)
C
h
a
v
e
 
d
e
 
5
6
 
b
i
t
s
1
6
 
c
h
a
v
e
s
 
s
ã
o
 
g
e
r
a
d
a
s
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 393
Cada rodada de criptografia Eu pega o bloco de 64 bits produzido pela rodada anterior Eu
entrada, conforme mostrado na Figura 9-8 (b). Os 64 bits são divididos em uma parte esquerda eu Eu 1 e uma
Parte certa R Eu 1, cada parte consiste em 32 bits. A parte direita é usada para a parte esquerda na próxima rodada, ou seja, eu
Eu
Trabalho duro é feito na função de mangler F. Esta função usa um bloco de 32 bits R Eu 1
como entrada, junto com uma senha K Eu 48 bits, e produz um bloco de 32 bits ao qual a função XOR é aplicada com eu Eu 
1 para produzir R Eu. ( XOR é uma abreviatura para a operação exclusiva ou.) A função mangler primeiro se expande R Eu 1 a 
um bloco de 48 bits e aplica a função
XOR com K Eu. O resultado é dividido em oito seções de seis bits cada. Cada seção alimenta um caixa S diferente, 
que é uma operação que substitui cada uma das 64 entradas
possíveis saídas de seis bits em uma das 16 possíveis saídas de 4 bits. As oito seções de saída de quatro bits cada são 
então combinadas em um valor de 32 bits e comutadas de volta.
A chave K Eu 48 bits para a rodada Eu é derivado da chave mestra de 56 bits da seguinte maneira. Primeiro, a chave 
mestra é permutada e dividida em metades de 28 bits. Para cada rodada, cada
metade é primeiro girada um ou dois bits para a esquerda, após o que 24 bits são extraídos. Junto com os 24 bits da outra metade 
girada, uma chave de 48 bits é construída. Os detalhes de uma rodada de criptografia são mostrados na Figura 9-9.
1 gosto do seu
R Eu 1
Chave de 56 bits
Permutação inicial
String de 28 bits String de 28 bits
Usado para
proxima rodada
Rotação para a esquerda Rotação para a direita
Extrair 24 bits Extrair 24 bits
Chave de 48 bits
Figura 9-9. Detalhes da geração de chaves para cada rodada no DES.
O princípio do DES é bastante simples, mas o algoritmo é difícil de romper com os métodos analíticos. Usar um ataque 
de força bruta de simplesmente procurar uma chave que fará o trabalho realizado tornou-se fácil, como foi demonstrado em 
várias ocasiões. No entanto, aplicando DES três vezes em um modo especial criptografar-descriptografar-criptografar com 
chaves diferentes, prossiga
394 CAPÍTULO 9 SEGURANÇA
também conhecido como DES triplo, é muito mais seguro e freqüentemente é o usado [ver também Barker 
(2004)].
É difícil atacar o DES pela análise porque a lógica do design subjacente nunca foi explicada publicamente. Por 
exemplo, sabe-se que, ao tomar S-boxes diferentes das usadas atualmente no padrão, o algoritmo se torna 
substancialmente mais fácil de violar (ver Pfleeger, 2003, para uma breve discussão sobre DES). Uma justificativa 
para o design e uso de S-box foi publicada somente depois que novos modelos de ataque foram criados na década 
de 1990. DES provou ser bastante resistente a esses ataques e seus designers revelaram que os modelos 
recém-concebidos já eram familiares para eles. quando desenvolveram DES em 1974 (Coppersmith, 1994).
DES tem sido usado como uma técnica de criptografia padrão há anos, mas atualmente está em processo 
de substituição pelos blocos de algoritmo de Rijndael de 128 bits. Existem também variantes com chaves e 
blocos de dados maiores. O algoritmo foi projetado para ser rápido o suficiente para ser implementado em 
cartões inteligentes, que é uma área de aplicação cada vez mais importante para criptografia.
Criptossistemas de chave pública: RSA
O segundo exemplo de um algoritmo criptográfico é amplamente utilizado em sistemas de chave pública: RSA, nomeado em 
homenagem a seus inventores Rivest, Shamir e Adleman (1978). A segurança do RSA decorre do fato de que não existem 
métodos conhecidos para calcular de forma eficiente o fatores principais de grande número. É possível mostrar que cada 
inteiro pode ser escrito como o produto de números primos. Por exemplo, 2100 pode ser escrito como
2100 2 2 3 5 5 7
isso torna 2, 3, 5 e 7 os fatores primos de 2100. No RSA, as chaves privadas e públicas são construídas com números 
primos muito grandes (compostos de centenas de dígitos decimais). Conforme observado, violar o RSA é equivalente a 
encontrar esses números primos. Até agora, foi demonstrado que isso não é computacionalmente viável, apesar do fato 
de que os matemáticos tentam resolver o problema há séculos.
A geração das chaves privada e pública requer quatro etapas:
1. Escolha dois números primos muito grandes, p Y q.
2. Calcule n p o que Y z ( p - 1) ( o que 1).
3. Escolha um número d que é relativamente primo de z.
4. Calcule o número e de modo que e d 1 mod z.
Um dos números, por exemplo d, pode ser usado mais tarde para decifrar, enquanto e ele é usado para 
criptografar. Apenas um desses dois é tornado público, dependendo da finalidade do algoritmo.
SEÇÃO 9.1 INTRODUÇÃO À SEGURANÇA 395
Considere o caso em que Alice deseja manter as mensagens que envia a Bob confidenciais. Ou seja, você deseja ter 
certeza de que ninguém, exceto Bob, intercepta e lê suas mensagens. RSA considera cada mensagem m é uma sequência de 
bits. Cada mensagem é primeiro dividida em blocos
de comprimento fixo, onde cada bloco m Eu, interpretado como um número binário, deve estar no intervalo 0 
m Eu n.
Para criptografar a mensagem m, remetente calcula para cada bloco m Eu o valor c Eu m e
Eu ( mod n),
que é então enviado ao destinatário. A descriptografia do lado do destinatário ocorre por meio do cálculo
m Eu c d
Eu ( mod n). Observe que para implementar a criptografia requer ambos e Como n, enquanto
após a descriptografia requer conhecer os valores de d Y n.
Quando o RSA é comparado a criptossistemas simétricos como o DES, o RSA tem a desvantagem de ser 
computacionalmente mais complexo. Portanto, a criptografia de mensagens com RSA é aproximadamente 100-1000 vezes 
mais lenta que o DES, dependendo da técnica de implementação usada. Consequentemente, muitos sistemas criptográficos 
usam RSA para trocar apenas chaves compartilhadas de maneira segura, mas não para criptografar dados "normais". 
Exemplos de combinação dessas duas técnicas serão vistos nas seções subsequentes.
Funções hash: MD5
Como um exemplo final de um algoritmo criptográfico amplamente usado, daremos uma olhada no MD5 (Rivest, 1992). MD5 
é uma função hash útil para calcular um resumo da mensagem Comprimento fixo de 128 bits obtido de uma string de 
entrada binária de comprimento arbitrário. A string de entrada é primeiro preenchida com um comprimento total de 448 bits 
(módulo 512), após o qual o comprimento da string de bits original é preenchido com um inteiro de 64 bits. A entrada é 
convertida em uma série de blocos de 512 bits.
A estrutura do algoritmo é mostrada na Figura 9-10. Começando com algum valor constante de 128 bits, o algoritmo 
continua k fases, onde k é o número de blocos de 512 bits que compõem a mensagem preenchida. Durante cada fase, 
um resumo de 128 bits é calculado a partir de um bloco de dados de 512 bits retirado da mensagem preenchida e do 
resumo de 128 bits calculado na fase anterior.
Constante de 128 bits Mensagem preenchida (múltiplo de 512 bits)
Resumo
512 bits
Resumo
512 bits
Mensagem de resumo
Figura 9-10. Estrutura de uma função MD5.
396 CAPÍTULO 9 SEGURANÇA
No MD5, uma fase consiste em quatro rodadas de cálculos, onde cada rodada usa uma das seguintes quatro 
funções:
F (x, y, z)
G (x, y, z)
H (x, y, z)
I (x, y, z)
( x AND y) OR ((NÃO x) AND z)
( x AND z) OR ((y AND (NOT z)) x XOR y 
XOR z
y XOR (x OR (NÃO z))
Cada uma dessas funções opera em variáveis de 32 bits x, y, Y z. Para ilustrar como essas funções são usadas, vamosconsiderar um bloco de 512 bits b da mensagem embutida que está sendo pro-
cessou durante a fase k. O bloco b é dividido em blocos filhos de 32 bits (ou sub-blocos) b 0,
b 1, …, b quinze. Durante a primeira rodada, a função F para alterar quatro variáveis (denotadas como p, q, r, Y sim, respectivamente) 
em 16 iterações, conforme mostrado na Figura 9-11. Essas variáveis
rasteje em cada uma das rodadas seguintes, e uma vez que uma fase é concluída, eles passam para
a próxima fase. Há um total de 64 constantes predefinidas C Eu. A notação x <<< n é usado para indicar um rotação à 
esquerda: os pedaços de x eles se movem n posições à esquerda, onde o bit
deslocado da esquerda é colocado na posição localizada mais à direita.
Iterações 1 a 8 Iterações 9 a 16
p ← ( p
s ← ( s
r ← ( r
o que ← ( o que
p ← ( p
s ← ( s
r ← ( r
o que ← ( o que
F (q, r, s)
F (p, q, r)
F (s, p, q)
F (r, s, p)
F (q, r, s)
F (p, q, r)
F (s, p, q)
F (r, s, p)
b 0
b 1
b 2
b 3
b 4
b 5
b 6
b 7
C 1) <<< 7
C 2) <<< 12
C 3) <<< 17
C 4) <<< 22
C 5) <<< 7
C 6) <<< 12
C 7) <<< 17
C 8) <<< 22
p ← ( p
s ← ( s
r ← ( r
o que ← ( o que
p ← ( p
s ← ( s
r ← ( r
o que ← ( o que
F (q, r, s)
F (p, q, r)
F (s, p, q)
F (r, s, p)
F (q, r, s)
F (p, q, r)
F (s, p, q)
F (r, s, p)
b 8
b 9
C 9) <<< 7
C 10) <<< 12
C 11) <<< 17
C 12) <<< 22
C 13) <<< 7
C 14) <<< 12
C 15) <<< 17
C 16) <<< 22
b 10
b onze
b 12
b 13
b 14
b quinze
Figura 9-11. Todas as 16 iterações presentes durante a primeira rodada em uma fase MD5.
Da mesma forma, a segunda rodada usa a função G, em tanto que H e Eu eles são usados na terceira e quarta 
rodadas, respectivamente. Cada etapa, portanto, consiste em 64 iterações, após as quais a próxima fase começa, mas agora 
com os valores que p, q, r, Y s tem nesse ponto.
9.2 CANAIS SEGUROS
Nos capítulos anteriores, o modelo cliente-servidor foi usado frequentemente como uma maneira conveniente de 
organizar um sistema distribuído. Neste modelo, os servidores podem possivelmente ser distribuídos ou replicados, 
embora também atuem como clientes em relação aos demais
SEÇÃO 9.2 CANAIS SEGUROS 397
servidores. Ao considerar a segurança em sistemas distribuídos, mais uma vez é muito útil pensar em termos de clientes e 
servidores. Em particular, a implementação de um sistema distribuído seguro basicamente se resume a dois temas 
predominantes. A primeira é como tornar segura a comunicação entre clientes e servidores. A comunicação segura requer 
autenticação das partes em comunicação. Em muitos casos, também é necessário garantir a integridade e possivelmente 
a confidencialidade de uma mensagem. Como parte desse problema, você também deve considerar a proteção da 
comunicação dentro de um grupo de servidores.
O segundo problema é a autenticação; depois que um servidor aceita a solicitação de um cliente, como você 
pode saber se esse cliente está autorizado a fazer a solicitação? A autorização tem a ver com o problema de 
controlar o acesso aos recursos, que é discutido detalhadamente na próxima seção. Esta seção se concentra na 
proteção da comunicação em um sistema distribuído.
A questão de proteger a comunicação entre clientes e servidores pode ser considerada dependendo do 
estabelecimento de um canal seguro entre as partes comunicantes (Voydock e Kent, 1983). Um canal seguro 
protege remetentes e destinatários contra interceptação, modificação e fabricação de mensagens. Não protege 
necessariamente contra interrupções também. A proteção das mensagens contra interceptação é feita 
garantindo a confidencialidade: o canal seguro garante que suas mensagens não sejam vistas por intrusos. A 
proteção contra modificação e fabricação é feita por meio de autenticação mútua e protocolos de integridade de 
mensagem. Nas páginas a seguir, vários protocolos que podem ser usados para implementar a autenticação 
por meio de criptosistemas simétricos e de chave pública são discutidos primeiro. Uma descrição detalhada da 
razão por trás da autenticação é encontrada em Lampson et al. (1992).
9.2.1 Autenticação
Antes de entrar em detalhes sobre vários protocolos de autenticação, é importante notar que a autenticação e a 
integridade da mensagem não podem ser realizadas sem a outra. Considere, por exemplo, um sistema distribuído que 
oferece suporte à autenticação de duas partes na comunicação, mas não fornece mecanismos para garantir a integridade 
da mensagem. Em um sistema como esse, Bob pode saber com certeza que Alice é o remetente de uma mensagem. m. No 
entanto, se Bob não pode ter certeza de que m não foi modificado durante a transmissão, de que adianta saber que Alice 
enviou (a versão original de) m?
Além disso, suponha que apenas a integridade da mensagem seja suportada, mas que nenhum mecanismo de 
autenticação exista. Quando Bob recebe uma mensagem informando que ele ganhou $ 1.000.000 na loteria, quão feliz ele 
poderia ficar se não pudesse verificar se a mensagem foi enviada pelo organizador da loteria?
Portanto, autenticação e integridade da mensagem devem andar de mãos dadas. Em muitos protocolos, a 
combinação funciona aproximadamente da seguinte maneira. Novamente, suponha que Alice e Bob desejam se 
comunicar e que Alice tome a iniciativa de estabelecer um canal. Alice envia uma mensagem para Bob ou para um 
terceiro de confiança que o ajudará a estabelecer
398 CAPÍTULO 9 SEGURANÇA
o canal. Depois que o canal é estabelecido, Alice sabe que está falando com Bob e Bob sabe com certeza que 
ele está falando com Alice, para que possam trocar mensagens.
Para garantir a integridade subsequente das mensagens de dados trocadas uma vez autenticadas, é prática 
comum usar criptografia de chave secreta por meio de chaves de sessão. UMA
chave de sessão é uma chave compartilhada (secreta) que é usada para criptografar mensagens para integridade e 
possivelmente confidencialidade. Essa chave geralmente é usada apenas enquanto o canal existir. Quando é fechado, sua 
chave de sessão associada é descartada (ou na verdade, com certeza é destruída). Em seguida, voltamos às chaves de sessão.
Autenticação baseada em uma chave secreta compartilhada
Vamos primeiro dar uma olhada em um protocolo de autenticação baseado em uma chave secreta que Alice e Bob já 
compartilham. Como eles realmente conseguem obter com segurança uma chave compartilhada é discutido posteriormente 
neste capítulo. Na descrição do protocolo, Alice e Bob
eles são abreviados PARA Y B, respectivamente, e sua chave compartilhada é indicada como K A, B. O protocolo adota um método 
comum pelo qual uma parte desafia a outra a responder corretamente apenas
se a outra parte conhece a chave secreta compartilhada. Essas soluções também são conhecidas como
protocolos de desafio-resposta.
No caso de autenticação baseada em uma chave secreta compartilhada, o protocolo continua conforme mostrado na 
Figura 9-12. Primeiro, Alice envia sua identidade para Bob (mensagem 1), o que indica que ela deseja estabelecer um canal 
de comunicação entre os dois. Bob depois envia um
desafio R B para Alice, mostrado como mensagem 2. Esse desafio pode assumir a forma de um número aleatório.
tório. Alice é obrigada a criptografar o desafio com a chave secreta K A, B compartilhado com Bob e devolvido criptografado para 
Bob. Esta resposta é mostrada como mensagem 3 na Figura 9-12 que contém
K A, B ( R B).
1
PARA
2 R B
3 K A, B ( R B)
4 R PARA
5 K A, B ( R PARA)
Figura 9-12. Autenticação baseada em uma chave secreta compartilhada.
Quando Bob recebe a resposta K A, B ( R B) para o seu desafio R B, você pode descriptografar a mensagem reutilizando a chave 
compartilhada para ver se ela contém R B. Se sim, então você sabe que Alice está do outro lado, então quem mais poderia ter 
descoberto R B com K A, B? Em outras palavras, Bob já verificou
A
l
i
c
i
a
P
r
u
m
o
SEÇÃO 9.2 CANAIS SEGUROS 399
que ele está falando com Alicia. No entanto, observe que Alice ainda não verificouse ela é Bob
quem está do outro lado do canal. Então, envie um desafio R PARA ( mensagem 4), à qual Bob responde de volta
Sando K A, B ( R PARA), mostrado como mensagem 5. Quando Alice o descriptografar com K A, B e ver o dele R PARA, ele percebe que está 
falando com Bob.
Um dos problemas de segurança mais difíceis ao projetar protocolos é que eles realmente funcionam. Para ilustrar a facilidade 
com que as coisas podem se complicar, vamos considerar uma “otimização” de protocolo de autenticação em que o número de 
mensagens foi reduzido de cinco para três, conforme mostrado na Figura 9-13. A ideia básica é que, se Alice finalmente quiser 
desafiar Bob, ela precisará enviar-lhe um desafio junto com sua identidade quando estabelecer o canal. Além disso, Bob responde ao 
desafio, junto com seu próprio desafio, em uma única mensagem.
1
A, R PARA
2
R B, K A, B ( R PARA)
3 K A, B ( R B)
Figura 9-13. Autenticação baseada em uma chave secreta compartilhada, mas usando três 
mensagens em vez de cinco.
Infelizmente, este protocolo não funciona mais. Ele pode ser facilmente derrotado pelo que é conhecido como um ataque 
de reflexão. Para explicar como esse ataque funciona, considere um intruso chamado Chuck, que é indicado como C nos 
protocolos. O objetivo de Chuck é estabelecer um canal com Bob para que Bob pense que ele está falando com Alice. Chuck 
pode fazer isso se responder corretamente ao desafio enviado por Bob, por exemplo, retornando a versão criptografada de
um número que Bob enviou. Sem conhecimento de K A, B, apenas Bob pode fazer a descriptografia, e Chuck está 
tentando enganar Bob para fazê-lo.
O ataque é ilustrado na Figura 9-14. Chuck envia uma mensagem contendo a identidade de Ali.
Inc PARA, junto com um desafio R C. Bob retorna o desafio R B e responda K A, B ( R C) em uma única mensagem. Nesse ponto, Chuck teria 
que verificar se ele conhece a chave secreta retornando K A, B ( R B) para Bob.
Infelizmente, não tem K A, B. Portanto, ele tenta configurar um segundo canal para que Bob faça a descriptografia 
para ele.
Consequentemente, Chuck envia PARA Y R B em uma única mensagem como antes, mas agora você sugere que deseja um 
segundo canal. Isso é mostrado como Mensagem 3 na Figura 9-14. Bob, por não dar
conta que ele próprio havia usado R B antes como um desafio, responda K A, B ( R B) e mande outro desafio
R B 2, exibida como mensagem 4. Nesse ponto, Chuck já tinha K A, B ( R B) e acaba começando
A
l
i
c
i
a
P
r
u
m
o
400 CAPÍTULO 9 SEGURANÇA
1 A, R C
Primeira sessão
2
R B, K A, B ( R C)
3 A, R B
Segunda sessão
4
R B2, K A, B ( R B)
5
K A, B ( R B)
Primeira sessão
Figura 9-14. O ataque de reflexão.
a primeira sessão ao retornar a mensagem 5 contendo a resposta K A, B ( R B), que foi originalmente solicitado com o desafio 
enviado na mensagem 2.
Conforme explicado em Kaufman et al. (2003), um dos erros cometidos durante a adaptação do protocolo 
original foi que na nova versão do protocolo as duas partes estavam usando o mesmo desafio em duas 
execuções diferentes do protocolo. Um design melhor é sempre usar desafios diferentes para o iniciador e o 
respondente. Por exemplo, se Alice sempre usa um número ímpar e Bob um número par, Bob teria percebido 
que
algo estranho estava acontecendo quando ele recebeu o R B na mensagem 3 na Figura 9-14. (Infelizmente, esta solução 
está sujeita a outros ataques, nomeadamente um conhecido como "homem
no meio do ataque ”, o que é explicado em Ferguson e Schneier, 2003.) Em geral, permitir que as duas partes que estão 
estabelecendo um canal façam várias coisas de forma idêntica não é uma boa ideia.
Outro princípio que é violado no protocolo adaptado é que Bob divulgou informações valiosas em
a forma da resposta K A, B ( R C) não tenho certeza para quem ele estava dando. Este princípio não foi violado no 
protocolo original, onde Alice deve primeiro provar sua identidade, após
qual Bob queria passar suas informações criptografadas.
Existem outros princípios que os desenvolvedores de protocolo criptográfico aprenderam gradualmente ao longo dos 
anos e alguns serão introduzidos quando outros protocolos forem discutidos posteriormente. Uma lição importante é que 
projetar protocolos de segurança que façam o que deveriam fazer é geralmente muito mais difícil do que parece. Da 
mesma forma, o menor ajuste a um protocolo existente para melhorar seu desempenho pode facilmente afetar sua 
precisão, como já foi demonstrado. Mais teoria sobre os princípios do projeto de protocolo é encontrada em Abadi e 
Needham (1996).
Autenticação usando um centro de distribuição de chaves
Um dos problemas de usar uma chave secreta compartilhada para autenticação é sua escalabilidade. Se um 
sistema distribuído contém N servidores, e cada servidor requer
M
a
n
d
r
i
l
P
r
u
m
o
SEÇÃO 9.2 CANAIS SEGUROS 401
compartilhe uma chave secreta com outras pessoas N
negar N (N 1) / 2 chaves, e cada servidor deve lidar com N
ce para problemas. Uma alternativa é usar um método centralizado por meio de um centro de distribuição de chaves 
(KDC, por suas siglas em inglês). Este KDC compartilha uma chave secreta com cada um dos servidores, mas nenhum 
dos pares também precisa ter uma chave secreta compartilhada. Em outras palavras, usar um KDC requer que você 
lide com N chaves em vez de N (N 
1) / 2, o que é claramente uma melhoria.
Se Alice deseja estabelecer um canal seguro com Bob, ela pode fazer isso com a ajuda de um KDC confiável. A idéia 
geral é que o KDC forneça uma chave para Alice e Bob que eles possam usar para se comunicarem, e isso é mostrado na 
Figura 9-15.
1 servidores, o sistema como um todo precisa de ma-
1 chaves. Com N ótimo, isso leva
1
A, B
2 2
K A, KDC ( K A, B) K B, KDC ( K A, B)
Figura 9-15. O princípio de uso de um KDC.
Alicia primeiro envia uma mensagem ao KDC, informando que deseja falar com Bob. The KDC
retorna a mensagem contendo uma chave secreta compartilhada K A, B que Alicia pode usar. A mensagem é criptografada com a chave 
secreta K A, KDC que Alicia compartilha com o KDC. Além disso, o KDC também
enviar K A, B para Bob, mas agora criptografado com a chave secreta K B, KDC que ele compartilha com Bob.
A principal desvantagem deste método é que Alice pode desejar estabelecer um
canal seguro com Bob mesmo antes de Bob receber a chave compartilhada do KDC. Além disso, o KDC é necessário 
para colocar Bob no circuito, passando-lhe a chave. Esses problemas podem
ser evitado se o KDC retornar K B, KDC ( K A, B) Alicia e permite que ela se conecte com Bob. Isso leva
ao protocolo mostrado na Figura 9-16. A mensagem K B, KDC ( K A, B) também conhecido como bilhete.
É trabalho de Alice passar este tíquete para Bob. Observe que Bob ainda é o único que pode
fazer uso razoável do tíquete, pois é o único além do KDC que sabe decifrar as informações que contém
O protocolo mostrado na Figura 9-16 é na verdade uma variante de um exemplo bem conhecido de um protocolo de 
autenticação que usa um KDC, chamado Protocolo de autenticação Needham-Schroeder em homenagem a seus 
inventores (Needham e Schroeder, 1978). Uma variante diferente do protocolo é usada no sistema Kerberos, que 
descreveremos mais tarde. O protocolo Needham-Schroeder, mostrado na Figura 9-17, é um protocolo de resposta de 
desafio multidirecional que funciona da seguinte maneira.
A
l
i
c
i
a
K
D
C
,
 
g
e
r
a
 
K
 
A
,
 
B
P
r
u
m
o
402 CAPÍTULO 9 SEGURANÇA
1
A, B
2 K A, KDC ( K A, B), K B, KDC ( K A, B)
3
A, K B, KDC ( K A, B)
Figura 9-16. Uso de um tíquete e permissão para Alice se conectar com Bob.
1
R A1, A, B
2
K A, KDC ( R A1, B, K A, B, K B, KDC ( A, K A, B))
3
K A, B ( R A2), K B, KDC ( A, K A, B)
4
K A, B ( R A2 1, R B)
5 K A, B ( R B 1)
Figura 9-17. Protocolo de autenticação Needham-Schroeder.
Quando Alice deseja estabelecer um canal seguro com Bob, ela envia uma solicitação ao KDC confirmando
tem um desafio R PARA, junto com sua identidade PARA e,claro, de Bob. O KDC responde concedendo-
dê a ele a passagem K B, KDC ( K A, B) junto com a chave secreta K A, B que você pode compartilhar mais tarde com Bob.
O desafio R PARA 1 que Alice envia ao KDC junto com sua resposta para estabelecer um canal com Bob também é conhecido 
como um nonce. UMA nonce é um número aleatório usado apenas uma vez, como
como um número escolhido de um conjunto muito grande. O objetivo principal de um nonce é relacionar exclusivamente duas 
mensagens, neste caso a mensagem 1 e a mensagem 2. Em particular, com
R PARA 1 Incluída novamente na mensagem 2, Alice saberá com certeza que a mensagem 2 é enviada em resposta à mensagem 1, e que 
não é, por exemplo, o encaminhamento de uma mensagem mais antiga.
Para entender este problema, suponha que não foram usados nonces e Chuck roubou
uma das chaves antigas de Bob, por exemplo K velha
B, KDC. Além disso, Chuck interceptou uma resposta
velha ( A, K A, B)) que o KDC havia retornado em resposta a um pedido
Alicia conversou anteriormente com Bob. Enquanto isso, Bob terá que negociar uma nova chave
velha K A, KDC ( B, K A, B, K B, KDC
A
l
i
c
i
a
A
l
i
c
i
a
K
D
C
K
D
C
P
r
u
m
o
P
r
u
m
o
SEÇÃO 9.2 CANAIS SEGUROS 403
segredo compartilhado com o KDC. No entanto, Chuck espera pacientemente até que Alice novamente solicite o 
estabelecimento de um canal seguro com Bob. Nesse ponto, ela envia a resposta antiga e faz Alice pensar que ela está 
falando com Bob, porque ela pode decifrar o tíquete e mostrar que
conheça a chave secreta compartilhada K A, B. Isso é claramente inaceitável e será necessário tomar medidas contra isso.
Se um nonce for incluído, tal ataque será impossível porque o encaminhamento de uma mensagem antiga será descoberto 
imediatamente. Em particular, o nonce incluído na mensagem de resposta não corresponderá ao nonce da solicitação original.
A mensagem 2 também contém B, A identidade de Bob. Incluindo B, o KDC protege Alice contra o próximo ataque. 
Vamos supor B foi deixado de fora da mensagem 2. Nesse caso, Chuck poderia modificar a mensagem 1 substituindo a 
identidade de Bob por sua própria identidade, ou seja, C. O KDC então pensaria que Alice deseja estabelecer um canal 
seguro com Chuck e responde apropriadamente. Assim que Alice deseja entrar em contato com Bob, Chuck intercepta 
a mensagem e faz Alice acreditar que está falando com Bob. Ao copiar a identidade da outra parte da mensagem 1 
para a mensagem 2, Alice detectará imediatamente que sua solicitação foi modificada.
Depois que o KDC passa o tíquete para Alice, o canal seguro entre Alice e Bob pode ser este-
estabelecido. Alice envia a mensagem 3, que contém o tíquete para Bob e um desafio. R PARA 2 criptografia com chave compartilhada K
A, B que o KDC acabou de gerar. Bob então decifra o tíquete para descobrir
a chave compartilhada e retorna uma resposta R PARA 2 1 junto com o desafio R B para Alicia.
O seguinte comentário é imposto em relação à mensagem 4. Em geral, retornando
1 e não só R PARA 2, Bob não apenas mostra que conhece a chave secreta compartilhada, mas também que 
realmente superou o desafio. Novamente, isso vincula a mensagem 4 à 3
da mesma forma que R PARA mensagem vinculada 2 a 1. O protocolo é, portanto, mais seguro contra encaminhamento.
Porém, neste caso especial, bastaria retornar K A, B ( R PARA 2, R B), pela
razão simples pela qual essa mensagem nunca foi usada no protocolo antes. K A, B ( R PARA 2, R B) já mostrou que Bob foi 
capaz de decifrar o desafio enviado na mensagem 3. Mensagem 4 como
O que a Figura 9-17 mostra é devido a razões históricas.
Conforme apresentado aqui, o protocolo Needham-Schroeder ainda tem o ponto fraco de
E se Chuck conseguisse uma chave velha K A, B, Eu poderia encaminhar a mensagem 3 e fazer com que Bob estabelecesse um 
canal. Bob então acreditará que está falando com Alice quando, na realidade,
Chuck está do outro lado. Nesse caso, a mensagem 3 deve estar relacionada à mensagem 1, ou seja, tornar a chave 
dependente da solicitação inicial de Alice para estabelecer um canal com Bob. A solução é mostrada na Figura 9-18.
O truque é incorporar um nonce à solicitação enviada por Alice ao KDC. No entanto, o nonce precisa vir de 
Bob; Isso faz com que Bob se sinta confiante de que quem deseja estabelecer um canal seguro com ele obteve 
as informações apropriadas do KDC. Por consi-
Em seguida, Alice primeiro pede a Bob para enviar-lhe um nonce R B 1 criptografado com a chave compartilhada entre Bob e o KDC. 
Alice incorpora este nonce em sua solicitação ao KDC, que então o descriptografa e
coloca o resultado no ticket gerado. Dessa forma, Bob saberá com certeza que a chave de sessão está vinculada à 
solicitação original de Alice para falar com ele.
R PARA 2
404 CAPÍTULO 9 SEGURANÇA
1
PARA
2 K B, KDC ( R B1)
3
R A1, A, B, K B, KDC ( R B1)
4
K A, KDC ( R A1, B, K A, B, K B, KDC ( A, K A, B, R B1))
5
K A, B, ( R A2), K B, KDC ( A, K A, B, R B1)
6
K A, B ( R A2 1, R B2)
7
K A, B ( R B2 1)
Figura 9-18. Proteção contra reutilização mal-intencionada de uma chave de sessão gerada 
anteriormente no protocolo Needham-Schroeder.
1
K B ( A, R PARA)
2
K PARA( R PARA, R B, K A, B)
3 K A, B ( R B)
Figura 9-19. Autenticação mútua em um criptosistema de chave pública.
Autenticação com criptografia de chave pública
Aqui, cobrimos a autenticação com um criptosistema de chave pública que não requer um KDC. Novamente, 
consideramos a situação em que Alice deseja estabelecer um canal seguro com Bob e os dois têm a chave 
pública um do outro. Um protocolo de autenticação típico baseado em criptografia de chave pública é mostrado 
na Figura 9-19, que é explicado abaixo.
Alice começa enviando um desafio R PARA Bob criptografou com sua chave pública K B. A tarefa de Bob é decifrar a 
mensagem e devolver o desafio para Alicia. Já que Bob é a única pessoa que pode
Após a mensagem (usando a chave privada associada à chave pública que Alice usou), Alice saberá que está falando com 
Bob. Vamos observar como é importante para Alice ter certeza de que está usando a chave pública de Bob e não alguém 
que está tentando se passar por Bob. Como essas salvaguardas podem ser implementadas é discutido posteriormente 
neste capítulo.
Quando Bob recebe a solicitação de Alice para configurar um canal, ele recebe o desafio de descriptografia de volta.
junto com seu próprio desafio R B para autenticar Alicia. Além disso, gere uma chave de sessão K A, B o que
A
l
i
c
i
a
A
l
i
c
i
a
P
r
u
m
o
K
D
C
P
r
u
m
o
SEÇÃO 9.2 CANAIS SEGUROS 405
pode ser usado para estabelecer mais comunicações. A resposta de Bob ao desafio de Alicia, seu
próprio desafio, e a chave de sessão é incluída em uma mensagem criptografada com a chave pública K PARA pertencente a Alice e 
mostrado como mensagem 2 na Figura 9-19. Só Alice será capaz de decifrar
esta mensagem com a chave pública privada K PARA associado com K PARA.
Alice finalmente retorna sua resposta ao desafio de Bob usando a chave de sessão K A, B gerado por Bob. Desta forma, Alice 
mostra que ela poderia descriptografar a mensagem criptografada 2 e que, por
Então, sim, é com Alice que Bob está realmente falando.
9.2.2 Integridade e confidencialidade da mensagem
Além da autenticação, um canal seguro também deve oferecer garantias quanto à integridade e confidencialidade da 
mensagem. Integridade da mensagem significa que as mensagens são protegidas contra modificações sub-reptícias; a 
confidencialidade garante que as mensagens não possam ser interceptadas e lidas por bisbilhoteiros. A confidencialidade 
é fácil de estabelecer simplesmente criptografando uma mensagem antes de enviá-la. A criptografia pode ocorrer por uma 
chave secreta compartilhada com o destinatário ou, alternativamente, pela chave pública do destinatário. No entanto, 
proteger uma mensagem contra modificações é um pouco mais complicado, como você verá a seguir.
Assinaturas digitais
A integridade de uma mensagem geralmentevai além da transferência por meio de um canal seguro. Considere a 
situação em que Bob acabou de vender para Alice um disco de colecionador por $ 500. A operação foi realizada via 
e-mail. No final, Alice envia uma mensagem a Bob para confirmar que ela comprará o álbum por $ 500. Além da 
autenticação, há pelo menos duas questões a serem consideradas em relação à integridade da mensagem.
1. Alice precisa ter certeza de que Bob não mudará maliciosamente os $ 500 mencionados em sua 
mensagem para um valor mais alto e, então, não dirá que prometeu mais de $ 500.
2. Bob precisa ter certeza de que Alice não pode se retratar de ter enviado a mensagem, por exemplo, porque 
ela mudou de ideia.
Esses dois problemas podem ser resolvidos se Alicia assinar digitalmente a mensagem, de modo que sua assinatura seja 
unicamente vinculada ao conteúdo. A associação única entre uma mensagem e sua assinatura evita que modificações na 
mensagem passem despercebidas. Além disso, se a assinatura de Alicia puder ser verificada como genuína, ela não poderá 
dizer que não assinou a mensagem.
Existem várias maneiras de colocar assinaturas digitais. Um muito popular é usar um sistema de criptografia de chave pública como 
o RSA, conforme mostrado na Figura 9-20. Quando Alicia escreve uma mensagem
m para Bob, ele o criptografa com sua chave privado K PARA e envia para Bob. Se você também deseja manter
406 CAPÍTULO 9 SEGURANÇA
segredo do conteúdo da mensagem, você pode usar a chave pública de Bob e enviar K B ( m, K PARA( m)), que combina m e a 
versão assinada por Alicia.
Computador de Alice
Computador de Bob
m
Chave
privado
de alicia
Chave
público
de Bob
Chave
privado
de Bob
Chave
público
de alicia
m m
K PARA K B
K PARA
K B
K PARA( m)
K (m, K PARA( m))
K PARA( m)
B
Figura 9-20. Assinatura digital de uma mensagem usando criptografia de chave pública.
Quando Bob recebe a mensagem, ele a descriptografa com a chave pública de Alice. Se você pode ter certeza de 
que a chave pública é realmente de Alice, descriptografando a versão assinada de m e comparação bem sucedida com m eles 
só podem significar que veio de Alice. Alice está protegida contra quaisquer modificações maliciosas de Bob porque Bob 
sempre terá que verificar se a versão modificada de m Também foi assinado por Alicia. Ou seja, em essência, a mensagem 
descriptografada nunca conta como um cheque. Bob também está interessado em manter a versão assinada do m para se 
proteger contra uma rejeição de Alicia.
Existem vários problemas associados a este esquema, embora o protocolo em si esteja correto. Em primeiro lugar, a 
validade da assinatura de Alicia dura apenas enquanto sua chave privada permanecer secreta. Se Alice quiser desfazer o 
negócio mesmo depois de enviar sua confirmação a Bob, ela pode alegar que sua chave privada foi roubada antes de enviar 
a mensagem.
Outro problema ocorre quando Alice decide alterar sua chave privada. Fazer isso não é uma má ideia, já que mudar 
as chaves de vez em quando geralmente evita invasões. No entanto, quando Alicia muda sua senha, a mensagem 
enviada a Bob torna-se inútil. O que é necessário nesses casos é uma autoridade central que saiba quando as chaves são 
alteradas, além de usar carimbos de data / hora ao assinar mensagens.
Outro problema com esse esquema é que Alice criptografa toda a mensagem com sua chave privada. Essa criptografia costuma 
ser cara, dependendo dos requisitos de processamento (ou mesmo matematicamente inviável, uma vez que se presume que a 
mensagem interpretada como um número binário é limitada por um máximo predefinido) e é realmente desnecessária. Lembre-se de 
que uma assinatura deve ser associada exclusivamente a uma única mensagem específica. Um esquema mais barato, e talvez mais 
elegante, é usar um resumo da mensagem.
Como já explicado, um resumo da mensagem é uma string de bits de comprimento fixo h calculado a partir de uma mensagem m 
de comprimento arbitrário por meio de uma função hash H criptográfico. sim
m muda para m ¿, seu hash H (m ¿) será diferente de h H (m) de modo que uma modificação é
fácil de detectar.
SEÇÃO 9.2 CANAIS SEGUROS 407
Para assinar digitalmente uma mensagem, Alice pode primeiro calcular um resumo da mensagem e então 
descriptografá-lo com sua chave privada, conforme mostrado na Figura 9-21. O resumo criptografado é enviado a Bob junto 
com a mensagem. Observe que a mensagem é enviada como texto simples; todos podem ler. Se a confidencialidade for 
exigida, a mensagem também deve ser criptografada com a chave pública de Bob.
Computador de Alice
m
Computador de Bob
m
m
Função
cerquilha,
H
Chave
público de
Alicia
K PARA
Função
cerquilha,
H
Chave
privado
de alicia
K PARA
Comparar
OK
H (m)
K PARA( H (m))
H (m)
Figura 9-21. Assinatura digital de uma mensagem usando um resumo da mensagem.
Quando Bob recebe a mensagem e seu resumo criptografado, ele simplesmente precisa descriptografar o resumo com a 
chave pública de Alice e calculá-lo separadamente. Se o resumo calculado a partir da mensagem recebida e o resumo 
descriptografado corresponderem, Bob pode ter certeza de que foi Alice quem o assinou.
Chaves de sessão
Durante o estabelecimento de um canal seguro, após a fase de autenticação ser concluída, as pessoas que se 
comunicam usam, para confidencialidade, uma chave de sessão compartilhada única. A chave de sessão é descartada 
com segurança quando o canal não está mais em uso. Uma alternativa seria usar as mesmas chaves de 
confidencialidade usadas para estabelecer o canal seguro. No entanto, vários benefícios importantes derivam do uso 
de chaves de sessão (Kaufman et al., 2003).
Primeiro, quando uma chave é usada com frequência, é mais fácil revelá-la. De certa forma, as chaves 
criptográficas "se deterioram" exatamente como as chaves comuns. A ideia básica é que se um invasor consegue 
interceptar uma grande quantidade de dados criptografados com a mesma chave, torna-se possível implementar ataques 
para determinar certas características das chaves utilizadas e possivelmente revelar o texto simples ou a própria chave. É 
por isso que é muito mais seguro usar as chaves de autenticação o mínimo possível. Além disso, essas chaves são 
frequentemente trocadas usando algum mecanismo fora de banda demorado, como correio normal ou telefone. Essa 
forma de troca de chaves deve ser reduzida ao mínimo.
408 CAPÍTULO 9 SEGURANÇA
Outro motivo importante para gerar uma chave exclusiva para cada canal seguro é garantir a proteção contra ataques 
de encaminhamento, como já aconteceu em várias ocasiões. Com o uso de uma chave exclusiva cada vez que um canal 
seguro é estabelecido, as pessoas que se comunicam são protegidas contra pelo menos uma nova execução de sessão 
completa. Para proteger contra o encaminhamento de mensagens individuais de uma sessão anterior, geralmente são 
necessárias medidas adicionais, como a inclusão de carimbos de data / hora ou números sequenciais como parte do 
conteúdo da mensagem.
Suponha que a integridade e a confidencialidade da mensagem foram alcançadas com a mesma chave usada 
quando a sessão foi estabelecida. Nesse caso, enquanto a chave estiver comprometida, um invasor pode descriptografar 
mensagens transferidas durante uma conversa anterior, obviamente isso é indesejável. Em vez disso, é muito mais seguro 
usar chaves para cada sessão, pois se a chave for comprometida, no pior caso, apenas uma sessão será afetada. As 
mensagens enviadas durante outras sessões permanecerão confidenciais.
Relacionado a este último ponto está o fato de que Alice pode querer trocar alguns dados confidenciais com Bob, 
mas ela não confia nele o suficiente para fornecer suas informações na forma de dados criptografados com chaves de 
longa duração. Você pode reservar essas chaves para mensagens altamente confidenciais que troca com pessoas em 
quem realmente confia. Nesses casos, usar uma chave de sessão relativamente barata para secomunicar com Bob é 
suficiente.
Em geral, as chaves de autenticação são frequentemente configuradas de forma que são muito caras para 
substituir. Portanto, combinar essas chaves de longa duração com chaves de sessão muito mais baratas e 
temporárias costuma ser uma boa alternativa para implementar canais seguros para troca de dados.
9.2.3 Comunicação segura do grupo
Até agora, o foco tem sido estabelecer um canal de comunicação seguro entre duas partes. Em sistemas distribuídos, 
entretanto, geralmente é necessário permitir a comunicação segura entre mais de duas partes. Um exemplo típico é o 
de um servidor replicado em que todas as comunicações entre as réplicas precisam ser protegidas contra modificação, 
fabricação e interceptação, como no caso de canais seguros de duas partes. Nesta seção, examinaremos mais de 
perto a comunicação segura do grupo.
Comunicação confidencial de um grupo
Primeiro, consideramos o problema de proteger a comunicação entre um grupo de N
usuários contra espionagem. Para garantir a confidencialidade, um esquema simples é que todos os membros do grupo 
compartilhem uma chave secreta, que é usada para criptografar e descriptografar todas as mensagens transmitidas entre os 
membros do grupo. Como neste esquema todos os membros compartilham a chave secreta, é necessário confiar que eles a 
manterão em segredo. Esse único pré-requisito torna o uso de uma única chave secreta compartilhada para comunicação de 
grupo confidencial mais vulnerável a ataques em comparação com canais seguros de duas partes.
SEÇÃO 9.2 CANAIS SEGUROS 409
Uma solução alternativa é usar uma chave secreta compartilhada diferente entre cada par de membros do 
grupo. Assim que um membro começa a vazar informações, os outros membros podem simplesmente parar de 
enviar-lhes mensagens, mas continuar a usar as chaves secretas que usaram para se comunicarem. No entanto, 
em vez de manter uma chave, agora você precisa manter N (N 
1) / 2 chaves, que podem ser um problema difícil
por si mesmo.
Usar um criptosistema de chave pública pode tornar as coisas melhores. Neste caso, cada membro tem seu 
próprio par ( chave pública, chave privada), em que a chave pública pode ser usada por todos os membros para enviar 
mensagens confidenciais. Neste caso, um total de N pares de chaves. Se um membro não for confiável, ele será 
simplesmente removido do grupo sem ter que comprometer as outras chaves.
Servidores replicados seguros
Agora, vamos considerar um problema completamente diferente: um cliente emite uma solicitação para um grupo de 
servidores replicados. Eles podem ter sido replicados por motivos de tolerância a falhas ou desempenho, mas, em qualquer 
caso, o cliente espera que a resposta seja confiável. Em outras palavras, apesar do fato de que o grupo de servidores está 
sujeito a falhas bizantinas, conforme visto no capítulo anterior, um cliente espera que a resposta retornada não tenha sido 
submetida a um ataque de segurança. Esse ataque pode ocorrer se um ou mais servidores foram corrompidos por um 
invasor.
Uma solução para proteger o cliente contra esses ataques é coletar as respostas de todos os servidores e 
autenticar cada um. Se houver uma certa maioria entre as respostas dos servidores não corrompidos (ou seja, 
autenticados), o cliente pode ter certeza de que a resposta também está correta. Infelizmente, este método revela a 
replicação dos servidores, portanto, a transparência da replicação é violada.
Reiter e outros (1994) propõem uma solução para implementar um servidor replicado seguro no qual a 
transparência da replicação seja mantida. A vantagem do seu esquema é que, como os clientes não sabem das 
réplicas existentes, é muito mais fácil adicionar ou remover réplicas com segurança. Voltaremos ao gerenciamento 
seguro do grupo mais tarde, quando o gerenciamento de chaves for discutido.
A essência dos servidores replicados transparentes reside no que é chamado compartimento de um segredo. Quando 
vários usuários (ou processos) compartilham um segredo, nenhum deles sabe o segredo completo. Em vez disso, o 
segredo pode ser revelado apenas se todos os usuários se reunirem. Esses esquemas podem ser extremamente úteis. 
Considere, por exemplo, o lançamento de um míssil nuclear. Essa ação geralmente requer autorização de pelo menos 
duas pessoas. Cada uma dessas pessoas mantém uma chave privada que deve ser usada em combinação com a 
outra para lançar um projétil. Usar uma única chave não.
No caso de servidores replicados e seguros, o que se busca é uma solução pela qual, no máximo, k dos N 
servidores são capazes de produzir uma resposta incorreta, e destes k servidores, no máximo c 
k foram realmente corrompidos por um intruso.
Observe que este requisito torna o serviço tolerante de k falhas, como visto
410 CAPÍTULO 9 SEGURANÇA
no capítulo anterior. A diferença é que um serviço corrompido agora é classificado como defeituoso.
Agora, vamos considerar a situação em que os servidores são replicados ativamente. Em outras palavras, uma 
solicitação é enviada ao mesmo tempo para todos os servidores que é posteriormente tratada por cada servidor. Cada 
servidor produz uma resposta que retorna ao cliente. Para um grupo de servidores replicados com segurança, cada 
servidor deve acompanhar
sua resposta com uma assinatura digital. sim r Eu é a resposta do servidor S Eu, estar md (r Eu) o resumo da mensagem calculado 
pelo servidor S Eu. Este resumo é assinado com a chave privada K Eu do
servidor S Eu.
Suponha que você queira proteger o cliente contra, no máximo, c servidores corrompidos. No
Em outras palavras, o grupo de servidores deve ser capaz de tolerar corrupção por, no máximo,
c servidores e ainda ser capaz de produzir uma resposta na qual o cliente pode confiar. Se as assinaturas dos 
servidores individuais pudessem ser combinadas de forma a exigir c 1
assinaturas para construir uma assinatura válido para a resposta, isso resolveria o problema. Ou seja, os servidores replicados têm 
permissão para gerar uma assinatura válida secreta com a propriedade que c
Os servidores corrompidos por si só não são suficientes para produzir essa assinatura.
Como exemplo, considere um grupo de cinco servidores replicados que devem ser capazes de tolerar dois 
servidores corrompidos e ainda produzir uma resposta em qual
o cliente pode confiar. Cada servidor S Eu manda sua resposta r Eu para o cliente, junto com sua assinatura
sig (S Eu, r Eu) K Eu ( md (r Eu)). Consequentemente, o cliente terá finalmente recebido cinco triplos r Eu,
md (r Eu), sig (S Eu, r Eu) do qual você deve derivar a resposta correta. Essa situação é mostrada na Figura 9-22.
O cliente também calcula cada resumo md (r Eu). sim r Eu está errado, então normalmente eu
detectar cálculo K Eu ( K Eu ( md (r Eu))). No entanto, esse método não pode mais ser aplicado porque nenhum servidor 
individual é confiável. Em vez disso, o cliente usa uma função de deslocamento.
criptografia especial publicamente conhecida, D, que requer um conjunto V { sig (S, r), sig (S ¿, r ¿),
sig (S ¿, r ¿¿)} de três assinaturas como entrada e produz um único resumo como saída:
d saída D (V) D (sig (S, r), sig (S ¿, r ¿), sig (S ¿, r ¿¿))
Para saber mais detalhes sobre D, ver Reiter (1994). Existem 5! / (3! 2!) De três assinaturas que o cliente pode usar como 
entrada para D. Se uma dessas combinações
produzir um resumo correto md (r Eu) por alguma resposta r Eu, então o cliente pode considerar r Eu
tão correto. Em particular, você pode ter certeza de que pelo menos três servidores honestos
produziu a resposta.
Para melhorar a transparência da replicação, Reiter e Birman tornaram possível que cada serviço
dor S Eu transmita uma mensagem contendo sua resposta r Eu para os outros servidores, junto com a assinatura associada sig (S Eu, r Eu). Quando 
um servidor recebeu pelo menos c 1 tal mensagem, incluindo
sua própria mensagem, ele tenta calcular uma assinatura válida para uma das respostas.Se isso funcionar bem para, por exemplo, a 
resposta r e o conjunto V de c 1 assinatura, servidor envia r Y V como um
apenas mensagem para o cliente. Ele pode mais tarde verificar a exatidão de r confrontando sua assinatura, isto é, se md (r) 
D (V).
10 combinações possíveis
SEÇÃO 9.2 CANAIS SEGUROS 411
Grupo de servidores
Servidor
S1
Computador cliente
r1
r2
r3
r4
r5
r
Função
cerquilha
H
md (r) H (r)
Servidor
S2
Servidor
S3
sig (S1, r1)
sig (S2, r2)
sig (S3, r3)
sig (S4, r4)
sig (S5, r5)
Função de
decodificado,
D (V)
d
SIM
d md (r)? r está bem
Servidor
S4
NÃO
Conjunto de
três assinaturas V
Selecione outra combinação (r, V)
Servidor
S5
Figura 9-22. Compartilhamento de uma assinatura secreta em um grupo de servidores replicados.
O que acaba de ser descrito também é conhecido como esquema de limiar (m, n) com, neste exemplo, m 
c 1 e n N, o número de servidores. Em um esquema de limite ( m, n), uma
a mensagem é dividida em n partes, conhecidas como tons desde qualquer
m sombras para reconstruir a mensagem original, mas com m 1 ou menos mensagens não podem.
Existem várias maneiras de construir esquemas de limite ( m, n). Os detalhes foram publicados em Schneier (1996).
9.2.4 Exemplo: Kerberos
Agora deve estar claro que incorporar segurança em sistemas distribuídos não é trivial. Os problemas são causados 
pelo fato de que todo o sistema deve ser seguro; se alguma parte não estiver, todo o sistema pode ser comprometido. 
Para ajudar a construir sistemas distribuídos capazes de impor uma miríade de políticas de segurança, vários 
sistemas de suporte foram desenvolvidos que podem ser usados como base para implementação de 
desenvolvimento posterior. Um sistema importante frequentemente usado é o Kerberos ( Steiner et al., 1988; e Kohl e 
Neuman, 1994).
O Kerberos foi desenvolvido no MIT e é baseado no protocolo de autenticação NeedhamSchroeder descrito 
acima. Existem atualmente duas versões diferentes em uso, versão 4 (V4) e versão 5 (V5). Ambos são 
conceitualmente semelhantes, embora o V5 seja muito mais flexível e
r
1
,
 
s
i
g
 
(
S
1
,
 
r
1
)
r
2
,
 
s
i
g
 
(
S
2
,
 
r
2
)
r3
, s
ig
 (S
3
, r3
)
r
4
,
 
s
i
g
 
(
S
4
,
 
r
4
)
r
5
,
 
s
i
g
 
(
S
5
,
 
r
5
)
412 CAPÍTULO 9 SEGURANÇA
escalável. Uma descrição detalhada do V5 pode ser encontrada em Neuman et al. (2005), enquanto Garman (2003) 
descreve informações práticas sobre a execução do Kerberos.
O Kerberos pode ser visto como um sistema de segurança que ajuda os clientes a estabelecer um canal seguro com 
qualquer servidor que faça parte de um sistema distribuído. A segurança é baseada em chaves secretas compartilhadas. 
Existem dois componentes diferentes. o COMO ( Servidor de autenticação; servidor de autenticação) é responsável por 
lidar com uma solicitação de login do usuário. O AS autentica um usuário e fornece uma chave que pode ser usada para 
estabelecer canais seguros com os servidores. O estabelecimento de canais seguros é gerenciado por um TGS ( Serviço de 
concessão de ingressos; serviço de bilheteria). O TGS entrega mensagens especiais, conhecidas como ingressos, que 
são usados para convencer um servidor de que um cliente é realmente quem ele diz ser. Aqui estão alguns exemplos 
concretos de ingressos.
Vamos dar uma olhada em como Alice faz logon em um sistema distribuído usando Kerberos e como ela 
pode estabelecer um canal seguro com o servidor de Bob. Para fazer login no sistema, Alice pode usar 
qualquer estação de trabalho disponível. A estação
O trabalhador envia seu nome em texto simples para o AS, que retorna uma chave de sessão K A, TGS e uma passagem que Alicia deve 
entregar ao TGS.
O tíquete retornado pelo AS contém a identidade de Alice, junto com uma chave secreta gerada que Alice 
e o TGS podem usar para se comunicarem. O ingresso em si será entregue à TGS por Alicia. Portanto, é 
importante que ninguém mais, exceto o TGS
pode ler. É por esta razão que o tíquete é criptografado com a chave secreta K AS, TGS compartilhada entre o AS e o TGS.
Esta parte do procedimento de login é mostrada como mensagens 1, 2 e 3 na Figura 9-23. A mensagem 1 
não é realmente uma mensagem, mas é para Alice inserir seu nome de login em uma estação de trabalho. A 
mensagem 2 contém esse nome e é enviada
para o AS. A mensagem 3 contém a chave de sessão K A, TGS e o ingresso K AS, TGS ( A, K A, TGS). Para garantir a privacidade, a mensagem 
3 é criptografada com a chave secreta K A, AS compartilhado entre Alicia e AS.
1 início de
sessão
2 PARA
3
4 senha
5 CONTRA-
PLACA
K A, AS ( K A, TGS, K AS, TGS ( A, K A, TGS))
6
K AS, TGS, ( A, K A, TGS), B, K A, TGS ( t)
7
K A, TGS, ( B, K A, B), K B, TGS ( A, K A, B)
Figura 9-23. Autenticação Kerberos.
Quando a estação de trabalho recebe a resposta do AS, ela pede a Alice sua senha (exibida como mensagem 
4), que ela usa para gerar posteriormente a chave compartilhada K A, AS.
A
l
i
c
i
a
E
s
t
a
ç
ã
o
 
d
e
 
T
r
a
b
a
l
h
o
 
d
e
 
A
l
i
c
e
T
G
S
Á
S
SEÇÃO 9.3 CONTROLE DE ACESSO 413
(É relativamente simples pegar uma senha de string, aplicar um hash criptográfico e, em seguida, pegar os 
primeiros 56 bits como a chave secreta.) Observe que este método não só tem a vantagem de que a senha de 
Alice nunca será enviada como texto simples pela rede, mas também que a estação de trabalho nem mesmo 
precisa salvá-la temporariamente. Ade-
mais, assim que a chave compartilhada for gerada K A, AS, a estação de trabalho encontra a chave de sessão K A, TGS, e 
você pode esquecer a senha de Alice e usar apenas a chave secreta
compartilhado K A, AS.
Depois que esta parte da autenticação for feita, Alice pode considerar que
entrou no sistema através da estação de trabalho atual. O tíquete recebido do AS é armazenado temporariamente 
(geralmente de 8 a 24 horas) e será usado para acessar serviços remotos. Claro, se Alice deixar sua estação de 
trabalho, ela terá que destruir todos os tíquetes armazenados em cache. Se você quiser falar com Bob, peça ao 
TGS para gerar uma chave de sessão para Bob, mostrada como mensagem 6 na Figura 9-23. O fato de Alicia ter 
o
bilhete K AS, TGS ( A, K A, TGS) Isso mostra que ela é Alice. O TGS responde com uma chave de sessão K A, B,
novamente encapsulado em um tíquete que Alice terá que passar mais tarde para Bob.
A mensagem 6 também contém um carimbo de data / hora, t, criptografado com a chave secreta compartilhada entre Alice e o 
TGS. O carimbo de data / hora é usado para evitar que Chuck encaminhe a mensagem 6 de forma maliciosa e tente estabelecer um 
canal com Bob. O TGS verificará o carimbo de data / hora antes de devolver um tíquete para Alice. Se for diferente em mais de alguns 
minutos da hora atual, a solicitação de um tíquete será rejeitada.
Este esquema estabelece o que é conhecido como logon único. Desde que Alice não mude de estação 
de trabalho, não há necessidade de ela se autenticar em qualquer outro servidor que faça parte do sistema 
distribuído. Esse recurso é importante ao lidar com muitos serviços diferentes espalhados por várias máquinas. 
Em princípio, os servidores delegaram um pouco a autenticação do cliente ao AS e ao TGS e aceitarão 
solicitações de qualquer cliente que tenha um tíquete válido. Claro, serviços como login remoto exigirão que o 
usuário associado tenha uma conta, mas isso é independente da autenticação Kerberos.
Estabelecer um canal seguro com Bob agora é fácil e é mostrado na Figura 9-24. Primeiro, Alice envia uma 
mensagem para Bob contendo o tíquete obtido do TGS junto com um carimbo de data / hora criptografado. Quando Bob 
decifra o tíquete, ele percebe que Alice está falando com ele
porque apenas o TGS poderia ter estruturado o tíquete. Encontre também a chave secreta K A, B que permite verificar o 
carimbo de data / hora. Nesse ponto, Bob sabe que está falando com Alice e não
com outra pessoa que encaminhoumaliciosamente a mensagem 1. Ao responder com K A, B ( t 1), Bob
Mostre a Alice que ele é Bob.
9.3 CONTROLE DE ACESSO
No modelo cliente-servidor, até agora utilizado, uma vez que um cliente e um servidor estabelecem um canal seguro, o 
cliente pode emitir pedidos que devem ser executados pelo servidor. As solicitações envolvem a execução de 
operações em recursos controlados pelo servidor. UMA
414 CAPÍTULO 9 SEGURANÇA
1
K B, TGS ( A, K A, B), K A, B ( t)
2
K A, B ( t 1)
Figura 9-24. Estabelecendo um canal seguro no Kerberos.
A situação geral é a de um servidor de objetos que possui vários objetos sob seu controle. Uma solicitação de um cliente 
geralmente envolve a chamada de um método em um objeto específico. Essa solicitação pode ser feita apenas se o cliente 
tiver direitos de acesso o suficiente para obter a referida invocação.
Formalmente, a verificação dos direitos de acesso é conhecida como controle de acesso, enquanto que autorização 
refere-se à concessão de direitos de acesso. Os dois termos estão fortemente relacionados entre si e são 
freqüentemente usados de forma intercambiável. Existem muitas formas de controle de acesso. Primeiro, abordamos 
algumas das questões gerais, dando atenção especial aos diferentes modelos de gerenciamento de controle de acesso. 
Uma forma importante de controlar o acesso aos recursos é construir um firewall que proteja os aplicativos ou até 
mesmo uma rede inteira. Firewalls são estudados separadamente. Com o advento do código de mobilidade, o controle 
de acesso não poderia mais ser feito apenas com métodos tradicionais. Em vez disso, novas técnicas tiveram que ser 
inventadas, que também são apresentadas nesta seção.
9.3.1 Problemas gerais de controle de acesso
Para entender as várias questões envolvidas no controle de acesso, o modelo simples mostrado na Figura 9-25 é geralmente 
adotado. Este modelo consiste em assuntos que emitem um pedido de acesso a um objeto. Um objeto é algo muito 
semelhante aos objetos que foram analisados até agora. Você pode pensar em objetos como encapsulando seu próprio 
estado e implementando operações nesse estado. As operações de um objeto que os sujeitos podem solicitar que sejam 
realizadas estão disponíveis por meio de interfaces. Os assuntos podem ser melhor considerados como processos que agem 
em nome dos usuários, embora também possam ser objetos que precisam dos serviços de outros objetos para fazer seu 
próprio trabalho.
Sujeito
Monitor
referência
Objeto
Pedido para
Operação
Petição
autorizado
Figura 9-25. Modelo geral de controle de acesso a objetos.
A
l
i
c
i
a
P
r
u
m
o
SEÇÃO 9.3 CONTROLE DE ACESSO 415
Controlar o acesso a um objeto trata de protegê-lo contra invocações feitas por sujeitos que não têm permissão 
para ter nenhum método específico (ou mesmo nenhum) dos métodos executados. Além disso, a proteção pode incluir 
tópicos de gerenciamento de objetos, como criação, renomeação ou exclusão de objetos. A proteção é freqüentemente 
aplicada por meio de um programa chamado monitor de referência. Um monitor de referência registra qual sujeito 
pode fazer o quê e decide se um sujeito tem permissão para realizar uma operação específica. Este monitor é 
chamado (por exemplo, pelo sistema operacional confiável subjacente) sempre que um objeto é chamado. Portanto, é 
extremamente importante que o próprio monitor de referência seja à prova de invasões: um invasor não deve ser 
capaz de interferir nele.
Matriz de controle de acesso
Um método comum usado para modelar os direitos de acesso dos sujeitos com relação aos objetos é construir um matriz 
de controle de acesso. Nessa matriz, cada sujeito é representado por uma linha e cada objeto por uma coluna. Se a 
matriz é denotada por M, então uma entrada M [s, o)]
indica precisamente quais operações o sujeito pode solicitar s a ser realizado no objeto ou.
Em outras palavras, enquanto um assunto s solicitação de invocação de método m do objeto ou, o monitor de referência deve 
verificar se m aparece em M [s, o)]. sim m não aparece em M [s, o)], a invocação falha.
Considerando que um sistema pode facilmente precisar suportar milhares de usuários e milhões de objetos precisam 
de proteção, implementar uma matriz de controle de acesso como uma matriz verdadeira não é a maneira correta de 
proceder. Muitas entradas no array estarão vazias: em geral, um único sujeito terá acesso a relativamente poucos objetos. 
Consequentemente, outras formas mais eficientes são seguidas para implementar uma matriz de controle de acesso.
Um método amplamente aplicado é fazer com que cada objeto mantenha uma lista de direitos de acesso dos 
sujeitos que desejam acessá-lo. Em essência, isso significa que a matriz é colunar em todos os objetos e as 
entradas vazias são removidas. Este tipo de implementação leva ao que é chamado ACL ( Lista de controle de 
acesso; lista de controle de acesso).
Supõe-se que cada objeto tenha sua própria ACL associada.
Outro método é distribuir a matriz em linhas, dando a cada sujeito uma lista de capacidades
você tem para cada objeto. Em outras palavras, uma capacidade corresponde a uma entrada na matriz de controle de 
acesso. Não ter capacidade para um objeto específico significa que o sujeito não tem direitos de acesso para esse objeto.
Uma capacidade pode ser comparada a um bilhete: seu titular recebe certos direitos associados ao bilhete. Também 
está claro que um bilhete deve ser protegido contra modificações por sua transportadora. Um método particularmente 
adequado em sistemas distribuídos, e que tem sido amplamente aplicado no Amoeba (Tanenbaum et al., 1990), é proteger 
(uma lista de) capacidades com uma assinatura. Voltaremos a esses e outros assuntos posteriormente, quando 
discutirmos o gerenciamento de segurança.
A diferença entre como as ACLs são usadas e os recursos para proteger o acesso a um objeto é mostrada na Figura 
9-26. Usando ACLs, quando um cliente envia uma solicitação a um servidor, o monitor de referência do servidor verifica 
se conhece o cliente e se o cliente tem permissão para realizar a operação solicitada, conforme ilustrado na Figura 9-26 
(a).
416 CAPÍTULO 9 SEGURANÇA
Cliente
Criar solicitação de acesso r como 
assunto s
Servidor
ACL
Objeto
(Sr)
Se (s aparecer na ACL) se (r 
aparecer na ACL [s] permitir 
acesso
(para)
Cliente
Crie a solicitação de acesso r para 
o objeto o. Capacidade de passe C
Servidor
Objeto
(o, r) C
Se (r aparecer em C) 
permitir acesso
(b)
Figura 9-26. Comparação entre ACL e recursos para proteger objetos. (a) Com uma ACL. (b) 
Com capacidades.
No entanto, quando você usa recursos, um cliente simplesmente envia sua solicitação (solicitação) ao servidor. 
Ele não se importa se conhece o cliente; capacidade declara o suficiente. Portanto, o servidor só precisa verificar se a 
capacidade é válida e se a operação solicitada aparece na capacidade. Esse método de proteção de objetos por meio 
de recursos é mostrado na Figura 9-26 (b).
Domínios de proteção
ACLs e recursos ajudam a implementar com eficiência uma matriz de controle de acesso, ignorando todas as entradas 
vazias. No entanto, uma ACL ou lista de recursos pode se tornar grande o suficiente se nenhuma medida adicional for 
tomada.
Uma maneira geral de reduzir ACLs é usar domínios de proteção. Formalmente, um domínio de proteção é um 
conjunto de pares ( objeto, direitos de acesso). Para um determinado objeto, cada par especifica exatamente quais 
operações podem ser realizadas (Saltzer e Schroeder, 1975). As solicitações para realizar uma operação são sempre 
emitidas dentro de um domínio. Portanto, sempre que um sujeito solicita a execução de uma operação em um objeto, o 
monitor de referência primeiro procura o domínio de proteção associado a essa solicitação. Então, dado o domínio, o 
monitor de referência pode verificar se a solicitação tem permissão para ser feita. Existem diferentes usos para domínios 
de proteção.