Armazenamento Estável através da
Replicação Remota de Dados
Tatiana Simas Stanchi
[email protected]
Francisco Vilar Brasileiro
[email protected]
Coordenação de Pós-graduação em Informática
Departamento de Sistemas e Computação
Universidade Federal da Paraíba
Av. Aprígio Veloso s/n, Bodocongó
58109-970, Campina Grande, Paraíba
ABSTRACT
Stable storage of data is an important requirement for many applications. Traditional file systems use
synchronous write operations to guarantee the stability of data stored. However, due to the slow speed of
disk accesses, writing data synchronously decreases the performance of applications. Other systems are
based on the use of special hardware devices that prevent data stored in volatile memory from being lost
after a crash. This paper presents a new stable storage technique that substitutes synchronous write
operations by remote replication of data that are modified in the cache of the file system. To assure the
stability of the information, the technique includes a forward recovery mechanism, which allows it to
collect enough remote information to restore the file system to a consistent state after a crash. Since the
transfer of data through a high speed network is considerably faster than writing the same quantity of data
to disk, the main advantage of the proposed technique is the guarantee of stability, even in the presence of
both software and hardware faults, without the need of any special hardware devices, and with a
performance that is potentially better than that of those solutions based on synchronous write operations.
Keywords: stable storage; replicated processing; file system.
RESUMO
Armazenamento estável é um requisito importante para muitas aplicações. Os sistemas de arquivo
tradicionais realizam a gravação síncrona em disco, como uma forma de garantir a estabilidade dos dados
armazenados. Contudo, a gravação síncrona provoca uma degradação no desempenho das aplicações, em
decorrência da lentidão dos acessos a disco. Outros sistemas baseiam-se na utilização de hardware
especial para garantir a não-volatilidade dos dados armazenados em memória principal. Este artigo
apresenta uma nova técnica de armazenamento estável, que substitui a gravação síncrona pela replicação
remota de dados alterados na cache do sistema de arquivo. Para assegurar a estabilidade das informações,
a técnica proposta inclui um mecanismo de recuperação para frente, capaz de restaurar o sistema de
arquivo para um estado consistente, após um crash. Como a transmissão de dados, através de uma rede de
alta velocidade, é bem mais veloz do que a gravação da mesma quantidade de dados em disco, o principal
benefício oferecido é a garantia de estabilidade dos dados, mesmo na presença de falhas do software e do
hardware, com um desempenho potencialmente superior ao de soluções baseadas na gravação síncrona
em disco, e sem a necessidade de qualquer hardware especial.
Palavras-chaves: armazenamento estável; processamento replicado; sistema de arquivo.
1. INTRODUÇÃO
A evolução tecnológica exerce uma forte influência nas pesquisas de sistemas computacionais. À medida que a
tecnologia avança, as características dos componentes de hardware mudam, exigindo que os algoritmos utilizados para
gerenciar os sistemas sejam reexaminados e que novas técnicas sejam desenvolvidas. As influências tecnológicas são
particularmente evidentes nos projetos de sistema de arquivo. O projeto de um sistema de arquivo depende da tecnologia
de processador, de memória principal, de disco e, mais recentemente, da tecnologia de rede. Nas duas últimas décadas,
as tecnologias de processador, memórias principal e rede melhoraram por várias ordens de grandeza, tanto em
desempenho, quanto em capacidade. Por outro lado, a tecnologia de disco não acompanhou esse desenvolvimento, no
que tange ao desempenho, em decorrência das limitações impostas pela natureza mecânica dos discos magnéticos. A
evolução desigual dos componentes de hardware desafia os sistemas de arquivo a compensarem a lentidão dos discos,
permitindo que o desempenho cresça com a tecnologia de processador, de memória e de rede. O aumento do
desempenho dos sistemas de arquivo deve superar o dos discos, sob pena de as aplicações serem incapazes de utilizar o
rápido aumento da velocidade de processadores e dos demais componentes de hardware, para oferecer um melhor
desempenho aos seus usuários.
Tradicionalmente, os sistemas de arquivo adotam técnicas de otimização de desempenho baseadas na utilização de
caching na memória principal. Porém, essas técnicas reduzem a confiabilidade do sistema, em decorrência da
volatilidade da memória. Algumas aplicações necessitam de armazenamento estável de dados, ou seja, não admitem a
perda de informações, mesmo nos casos em que ocorram falhas no sistema. Nesse caso, as técnicas de otimização
baseadas apenas em memória principal não podem ser utilizadas, porque um crash no sistema apaga todo o conteúdo da
memória volátil.
Uma solução bastante simples, para crashes provocados pela interrupção do fornecimento de energia, é a utilização de
um UPS (Uninterruptible Power Supply) [1]. Entretanto, o contínuo aumento da complexidade dos sistemas
operacionais atuais é um fator que tende a aumentar o número de falhas de concepção residuais presentes nesses
sistemas, e conseqüentemente a possibilidade de crash do sistema operacional. Além disso, em alguns casos, uma
máquina que sofreu um crash não se recupera automaticamente, precisando passar por um processo de manutenção offline antes de entrar novamente em operação. O uso de um UPS não resolve nenhum desses problemas.
Dada a grande confiabilidade dos discos, os sistemas de arquivo tradicionais oferecem a gravação síncrona, como uma
forma de prover armazenamento estável: a aplicação solicita ao sistema que inicie imediatamente a gravação, em disco,
dos dados de uma requisição de escrita e espera pela finalização da operação de saída. Portanto, os sistemas de arquivo
tradicionais obrigam as aplicações a pagarem um alto custo pelo armazenamento estável de dados. Outros sistemas (por
exemplo, [3, 17]) baseiam-se na utilização de hardware especial para garantir a não-volatilidade dos dados armazenados
em memória principal.
Neste artigo propomos uma nova técnica de armazenamento estável, baseada na replicação remota dos dados alterados.
A idéia fundamental da técnica é garantir a estabilidade de dados, minimizando ao máximo a necessidade de realizar
gravações síncronas em disco, e sem recorrer a qualquer hardware especial. Baseando-se no fato de que um acesso à
memória principal (na ordem de nanossegundos) é muito mais rápido do que um acesso a disco (na ordem de
milissegundos) e de que a latência decorrente de um acesso através de uma rede de alta velocidade é menor do que a
latência introduzida pelo acesso a um bloco em um disco local [7, 10, 12, 16], a técnica substitui a gravação síncrona de
dados pela replicação remota dos dados e metadados alterados na cache do sistema de arquivo. Dessa forma, o preço a
ser pago para se ter uma diminuição da latência das operações de armazenamento estável é apenas um, potencialmente
pequeno, aumento no consumo de banda passante na rede de comunicação. Adicionalmente, um mecanismo de
recuperação para frente é utilizado para garantir a consistência e estabilidade dos dados armazenados em um sistema de
arquivo, caso a máquina que hospeda o sistema de arquivo1 sofra um crash.
Para facilitar o entendimento da proposta, esta será apresentada dentro do contexto de um sistema de arquivo específico.
Devido a sua popularidade, escolhemos o sistema de arquivo do UNIX [11, 13] para tal fim. Embora a apresentação
enfoque um sistema em particular, a replicação remota de informações da cache de sistemas de arquivo, como uma
alternativa à gravação síncrona de dados, também pode ser aplicada a outros sistemas de arquivo. Assim, a técnica de
armazenamento estável proposta tem um sentido genérico.
O restante do artigo está organizado da seguinte forma. Na próxima seção analisamos os trabalhos relacionados, que
visam a melhoria do desempenho e da confiabilidade dos sistemas de arquivo. Essa seção evidencia o diferencial da
1
No restante desse documento essa máquina será denominada de hospedeira.
2
técnica de armazenamento estável proposta. Na Seção 3 o Salius2 - Serviço de Armazenamento Estável com
Recuperação para Frente Baseado na Replicação Remota de Dados é apresentado. Este serviço é acrescido ao sistema de
arquivo UNIX para prover armazenamento estável através da replicação remota de dados. Essa seção apresenta o
funcionamento geral do Salius e descreve seus principais componentes: a Interface, o Servidor de Arquivos
Complementar e sua interação com o Serviço de Replicação de Dados, além do Procedimento de Recuperação. A Seção
4 apresenta o projeto de um Serviço de Replicação de Dados, descrevendo o modelo de replicação e os protocolos de
replicação e recuperação utilizados. Esta seção discute também a corretude dos protocolos propostos. Finalmente, a
Seção 5 traz as nossas conclusões.
2. TRABALHOS RELACIONADOS
O contexto atual dos sistemas de arquivo exige soluções para que os requisitos de desempenho e confiabilidade sejam
atendidos satisfatoriamente. Muitos trabalhos foram desenvolvidos nesse sentido.
Os sistemas de arquivo baseados em log – Log File System (LFS), centralizados, como o Sprite LFS [14] e o BDS LFS
[15], ou distribuídos, como o Zebra [9] e o xFS [2], conseguem otimizar o desempenho através da utilização mais
eficiente dos discos, durante pequenas operações de escrita: os dados e metadados alterados são agrupados em buffers,
na memória principal, sendo posteriormente gravados no disco, de forma seqüencial, através de uma operação de saída
única e contínua, minimizando, assim, a quantidade de acessos a disco e de posicionamentos da cabeça de leitura e
gravação. Porém, essa estratégia diminui a confiabilidade do sistema, pois a ocorrência de um crash pode provocar a
perda de dados. Um mecanismo de recuperação para frente leva o sistema a um estado consistente, considerando apenas
o conteúdo já gravado no log, antes da falha. O sistema não consegue recuperar os dados que estavam na cache no
momento imediatamente anterior ao crash. Portanto, um LFS não consegue prover armazenamento estável de dados.
Outros trabalhos sugerem métodos para tornar a memória principal capaz de armazenar dados, de forma persistente. Por
exemplo, a adição de memória não-volátil nas caches de servidores e de clientes [3], diminui tanto o tráfego de rede
cliente-servidor, quanto o tráfego para disco, decorrentes de operações de escrita, melhorando o desempenho.
Adicionalmente, os dados gravados em memória não-volátil sobrevivem a crashes do sistema. Entretanto, se o fluxo de
dados das operações de escrita torna-se maior que a capacidade da memória não-volátil, o sistema passa a transferir
dados para o disco. Para garantir a estabilidade desses dados, a gravação em disco precisa ser realizada de forma
síncrona, como nos sistemas de arquivo convencionais.
O sistema eNVy [17] faz uso de memória Flash RAM, para prover armazenamento em memória não-volátil, adotando
uma variedade de técnicas para superar as deficiências apresentadas pela tecnologia Flash. Por exemplo, como a
programação da memória Flash RAM é uma operação lenta, durante a atualização de uma página de memória, o eNVy
cria uma nova versão da página num outro tipo de memória (SRAM, com bateria), simulando para o processador que os
dados sobrepõem o conteúdo antigo. À proporção que a SRAM vai atingindo um nível de preenchimento
preestabelecido, suas páginas vão sendo gravadas na memória Flash. Se não existir espaço livre na memória Flash, uma
operação de limpeza é realizada, transferindo dados para o disco. Por isso, O sistema eNVy foi projetado para aplicações
com base de dados de pequeno e médio portes. O desempenho do sistema eNVy está atrelado à taxa de transações por
minuto e à quantidade de dados armazenada pela aplicação. Assim, o eNVy não pode ser utilizado de forma genérica.
Somente algumas aplicações, com o comportamento previsível, podem beneficiar-se desse sistema.
O Rio File Cache [4] consegue tornar a memória RAM capaz de sobreviver a crashes de sistema operacional. Para isso,
ele adota duas linhas de ação: impede que a memória seja sobregravada acidentalmente pelo sistema, durante um crash,
e provê o sistema de um mecanismo de recuperação do tipo “warm reboot”. Esse sistema, entretanto, além necessitar de
uma fonte confiável para alimentação da memória RAM (um UPS, por exemplo), requer também que a memória do
sistema e a cache do processador sejam capazes de preservar seus respectivos conteúdos, após um reinício normal do
sistema.
O sistema de arquivo Harp [10] é um dos primeiros sistemas que provê estabilidade através da substituição de operações
de gravação síncronas no disco por operações de comunicação via a rede. Entretanto, diferentemente da técnica proposta
neste artigo, o Harp requer um UPS para manter o sistema executando por um pequeno período de tempo após uma falha
no fornecimento de energia.
Em resumo, a maioria dos trabalhos recentes, que visam aumentar a confiabilidade do armazenamento de dados,
depende da utilização de hardware especial. Além disso, nenhuma solução que se baseie em recuperar informação em
2
Salius, é o nome dado, em latim, aos doze sacerdotes de Marte, encarregados da guarda dos escudos sagrados que
protegiam a estabilidade da Roma Antiga.
3
memória RAM após um crash pode tolerar falhas do próprio hardware3. O Salius, pelo contrário, resiste a falhas do
software e do hardware, além de utilizar apenas a tecnologia atualmente disponível na maioria dos sistemas
computacionais e a redundância já presente no sistema.
3. O SALIUS
A idéia fundamental do Salius é garantir a estabilidade de dados, minimizando ao máximo a necessidade de realizar
gravações síncronas em disco. A estabilidade dos dados é garantida, porque todas as estruturas de dados, mantidas pelo
sistema de arquivo na memória principal da hospedeira, são copiadas para as memórias principais de outras máquinas
disponíveis. O sistema de arquivo do UNIX mantém em memória a buffer cache, os nós-i e o superbloco [11]; qualquer
alteração nessas estruturas é replicada pelo Salius. Essa replicação deve garantir a sobrevivência de, pelo menos, uma
cópia dos dados alterados, após a ocorrência de crashes na hospedeira e em outras máquinas usadas para replicar os
dados. Dessa forma, o conteúdo replicado pode ser recuperado, a partir de uma outra máquina que não falhou, e gravado
no sistema de arquivo em disco.
O Salius é constituído de quatro componentes básicos:
Interface: é um conjunto de primitivas, incorporadas à interface do sistema de arquivo e utilizadas pelos programas de
usuário para requisitar operações ao Salius;
Serviço de Replicação de Dados (SRD): é um serviço que provê a replicação confiável de dados, ou seja, garante o
armazenamento de cópias das alterações realizadas num sistema de arquivo. Adicionalmente, esse serviço fornece as
informações necessárias para restabelecer, após um crash da hospedeira, o sistema de arquivo a um estado consistente,
preservando os dados estáveis;
Servidor de Arquivos Complementar (SAC): é a implementação das operações invocadas através de primitivas do
Salius. O SAC realiza operações sobre arquivos, requisitadas pelos clientes, e interage com o SRD, solicitando a
replicação dos dados alterados;
Procedimento de Recuperação (PR): é um aplicativo que restabelece a consistência do sistema de arquivo, após um
crash da hospedeira. O PR interage com o SRD para recuperar as informações replicadas, necessárias para restaurar a
consistência do sistema de arquivo, mantendo as informações estáveis.
3.3. A Interface
Existem duas abordagens possíveis para incorporar um serviço de armazenamento estável a um sistema de arquivo: i)
substituindo todas as primitivas originais pelas primitivas do serviço; ou ii) adicionando novas primitivas à interface do
sistema. Na primeira abordagem, o armazenamento estável passa a ser a única forma possível de manipular dados. O
serviço é totalmente transparente ao usuário: ao invocar uma primitiva do sistema de arquivo, o usuário grava dados de
forma estável, automaticamente. Na segunda alternativa, a transparência cede lugar à flexibilidade, pois o usuário opta
entre utilizar o serviço, ou continuar usando as primitivas tradicionais.
O Salius prioriza a flexibilidade, porque muitas aplicações não necessitam pagar os custos do armazenamento estável.
Além disso, uma mesma aplicação pode requerer a estabilidade de apenas parte dos dados manipulados. Por exemplo,
uma aplicação pode desejar gravar seus arquivos de log e de auditoria, de forma estável, mas pode prescindir da
estabilidade para os demais arquivos. Oferecendo suas primitivas como uma alternativa adicional, para a manipulação de
arquivos, o serviço propicia ao usuário o benefício de decidir sobre a conveniência de utilizar, ou não, o armazenamento
estável.
Uma segunda decisão refere-se à granularidade atribuída à unidade de armazenamento estável. O Salius assume que a
necessidade de armazenamento estável aplica-se, em geral, a um arquivo inteiro e não a uma fração de arquivo. Por
conseguinte, o usuário opta pela utilização do serviço no momento em que abre ou cria um arquivo, indicando
explicitamente que o arquivo deve ser manipulado através de primitivas do Salius.
As principais primitivas oferecidas são:
open
A primitiva open é utilizada para abrir um arquivo existente, ou criar e abrir um novo arquivo. Através dela, o usuário
pode optar pela utilização do Salius.
3
O procedimento de manutenção necessário para recuperar ou substituir o componente defeituoso (memória,
processador, controladoras, etc.) normalmente precisa se realizado off-line, e portanto, não há como salvaguardar a
informação armazenada na memória RAM.
4
Sintaxe: fd = open(pathname, flags, mode); onde fd é um descritor de arquivo, que é retornado para a aplicação;
pathname é o nome do arquivo; flags é uma combinação de bits, com diretrizes importantes, resumidas na Tabela 1; e
mode contém as permissões de acesso associadas ao arquivo; esse parâmetro só é obrigatório para a criação de um
arquivo.
O_RDONLY
O_WRONLY
O_RDWR
O_APPEND
O_CREAT
O_STABLE
O_EXCL
O_TRUNC
O_SYNC
O_NDELAY
O arquivo é aberto apenas para leitura.
O arquivo é aberto apenas para escrita.
O arquivo é aberto para leitura e escrita.
Todas as escritas irão adicionar dados ao final do arquivo.
Se o arquivo existir, não tem efeito algum. Caso contrário, o arquivo é criado e o parâmetro
mode deve ser especificado.
Todas as alterações do arquivo serão realizadas pelo Salius.
O arquivo é aberto em modo exclusivo.
Se o arquivo existir, seu tamanho é truncado para zero.
Indica a gravação síncrona de todas as alterações do arquivo.
Se uma operação de leitura, ou escrita, não puder ser realizada, retorna, imediatamente, com
erro, sem entrar em uma condição de bloqueio.
Tabela 1: Flags da operação open no Salius.
A sintaxe do open do UNIX foi ligeiramente alterada, adicionando a opção O_STABLE no parâmetro flags. Quando o
O_STABLE é informado, todas as operações de escrita subseqüentes realizam o armazenamento estável, usando a
replicação do Salius. O_STABLE também afeta o comportamento da primitiva open quando é associado aos flags
O_CREAT ou O_TRUNC: o open só retorna para a aplicação, quando as alterações realizadas estiverem estáveis.
s_creat
A primitiva s_creat é a versão estável do creat original do UNIX, utilizada para criar um arquivo regular, ou rescrever
sobre um existente.
Sintaxe: fd = s_creat(pathname, mode); onde fd é um descritor de arquivo, que retorna para a aplicação; pathname é o
nome do arquivo; e mode contém as permissões de acesso associadas ao arquivo.
A primitiva cria um novo arquivo, com o nome indicado em pathname, e armazena as permissões de acesso, informadas
em mode, no nó-i associado. Se o arquivo existe, s_creat trunca o seu tamanho para zero. Após ser criado, com sucesso,
o arquivo é aberto exclusivamente para escrita, com a opção O_STABLE, ou seja, indicando que deve ser alterado de
forma estável. A primitiva só retorna, após realizar a estabilização dos dados alterados: o superbloco, o nó-i do arquivo e
do diretório pai e a entrada do arquivo no diretório pai. Por sua vez, os dados estão estáveis quando ocorre uma das
seguintes situações: i) as modificações realizadas no sistema de arquivos estão armazenadas na memória principal e
existem cópias dos dados e metadados alterados no SRD; ou ii) todos os dados e metadados alterados já estão gravados
no disco da hospedeira.
write
A primitiva write é utilizada para escrever dados em um arquivo.
Sintaxe: num = write(fd, address, nbytes); onde fd é o descritor do arquivo; address é o endereço de uma estrutura, na
área de memória da aplicação, contendo os dados que devem ser escritos no arquivo; nbytes indica o número de bytes
que deverão ser escritos; e num retorna com o número de bytes gravados.
A primitiva write tenta gravar nbytes de um buffer, apontado por address, no arquivo associado ao descritor fd. Se a
operação for bem-sucedida, retorna em num o número de bytes efetivamente gravados, normalmente igual ao valor de
nbytes. De outro modo, num retorna com o valor -1, indicando um erro. No retorno, write atualiza o apontador da
posição corrente do arquivo, adicionando o número de bytes gravados.
A primitiva write do UNIX adota, como padrão, a gravação assíncrona de dados. Desse modo, quando write retorna, as
modificações realizadas no arquivo ficam armazenadas na memória principal, em estruturas como a buffer cache, a
tabela de nós-i e a cópia do superbloco. Posteriormente, essas mudanças são transferidas para o disco, de forma
assíncrona. Portanto, o usuário não tem garantias relativas à estabilidade dessas informações, que podem ser perdidas
por um crash do sistema.
Se o arquivo foi aberto com o bit O_SYNC ligado, write realiza a gravação síncrona de dados, ou seja, só retorna
quando todos os dados e metadados do arquivo estiverem gravados em disco. Nesse caso, a aplicação tem a garantia de
que as informações gravadas podem sobreviver a crashes. Por outro lado, se o arquivo for aberto com o flag
5
O_STABLE ligado, ou se for criado através da primitiva s_creat, write realiza o armazenamento estável de dados,
conforme apresentado na primitiva anterior.
PRIMITIVA
NO UNIX
open
write
creat
mkdir
mknod
PRIMITIVA
NO SERVIÇO
open
write
s_creat
s_mkdir
s_mknod
link
unlink
chown
chmode
s_link
s_unlink
s_chown
s_chmode
OPERAÇÃO
Criação e/ou abertura de um arquivo.
Escrita de dados em um arquivo.
Criação de um arquivo regular.
Criação de um diretório.
Criação de um arquivo de qualquer tipo: regular, diretório, especial
de caracter, especial blocado ou pipe.
Criação de uma nova entrada de diretório para um arquivo existente.
Remoção de uma entrada de diretório.
Alteração do proprietário de um arquivo.
Alteração das permissões de acesso de um arquivo.
Tabela 2: Primitivas do Salius.
Em resumo, no nível lógico, o serviço possui uma nova versão de cada primitiva de alteração do sistema de arquivo
original. As primitivas do serviço realizam praticamente as mesmas ações que as primitivas do UNIX, somando a
replicação de dados, para garantir a estabilidade de informações armazenadas. A Tabela 2 relaciona as primitivas do
Salius com as primitivas correspondentes do sistema de arquivo do UNIX e descreve, sucintamente, a função de cada
primitiva.
3.4. Obtendo Armazenamento Estável
O diagrama da Figura 1 mostra como ocorre a manipulação de arquivos no UNIX, com a adição do Salius. A figura
mostra que o SAC do Salius é incorporado ao sistema de arquivo, assim como as primitivas do Salius são acrescentadas
à interface do sistema.
Processos de usuário
Primitivas do UNIX
Primitivas do Salius
Chamadas do UNIX
Chamadas do Salius
Sistema de arquivo UNIX
SAC do Salius
Nível do usuário
buffer cache
Nível do núcleo
Nível do hardware
Drivers dos dispositivos de E/S
Drivers de rede
Controladores de disco
Controladores de rede
Hardware de disco
Hardware de rede
Figura 1: Diagrama da manipulação de arquivos no UNIX com Salius.
O SAC executa uma operação solicitada, interagindo com a buffer cache, para alterar dados na memória, da mesma
forma que o sistema de arquivo do UNIX. A seguir, o SAC interage com os drivers de rede para enviar uma mensagem
ao SRD, solicitando a replicação dos dados alterados, e receber a confirmação da replicação. O programa de usuário
permanece bloqueado, até que a replicação seja confirmada. Uma confirmação só pode ser dada quando o SRD puder
6
garantir, com uma determinada probabilidade, que a informação está estável. Somente após receber a confirmação do
SRD, o SAC retorna o controle para o programa de usuário, informando que a operação requisitada foi realizada com
sucesso. Se a confirmação não chega dentro de um intervalo de tempo predefinido, o SAC assume que o SRD falhou.
Nesse caso, o SAC força a gravação síncrona de todos os dados do sistema de arquivo alterados na memória e ainda não
propagados para o disco.
Se a replicação é confirmada no tempo esperado, os dados alterados na memória principal permanecem na cache por um
certo tempo e depois são gravados em disco, de forma assíncrona, como no funcionamento padrão do sistema de arquivo
do UNIX. Assim, o Salius possibilita que o sistema de arquivo do UNIX realize caching de escrita e ofereça
armazenamento estável, simultaneamente. A depender da relação entre o volume de dados alterados e a capacidade de
memória principal disponível na hospedeira, o tempo de permanência dos dados alterados na cache pode ser aumentado
para um valor maior do que o valor padrão, contribuindo para um melhor desempenho do sistema.
Como discutido anteriormente, quando uma replicação não é confirmada no tempo esperado, o SAC assume que o SRD
falhou. Por isso, realiza a gravação síncrona, garantindo a estabilidade dos dados provenientes da operação de
atualização em curso. Porém, essa ação não é suficiente para preservar a semântica de compartilhamento do serviço. Na
prática, o SRD pode continuar operacional, e a falha detectada ser decorrente de algum problema na comunicação entre
o SAC e o SRD. Se o sistema sofrer um crash logo após a gravação síncrona dos dados, uma posterior execução do PR
poderá gravar no disco os dados replicados no SRD, antes do crash. O SRD pode conter dados desatualizados, que irão
sobrepor informações mais recentes, armazenadas com a gravação síncrona.
A situação descrita pode ser demonstrada com o seguinte exemplo: um bloco x é atualizado e replicado no SRD; em
seguida, outra operação modifica o mesmo bloco e tenta realizar a replicação, mas o SRD falha e, portanto, x é gravado
de forma síncrona; a seguir, o sistema de arquivo sofre um crash. Neste ponto o administrador do sistema executa o PR,
que grava o antigo conteúdo do bloco x, fornecido pelo SRD, violando a semântica de compartilhamento adotada pelo
serviço, já que uma atualização antiga vai sobrepor uma atualização mais recente.
Para preservar a semântica de compartilhamento, o SAC precisa evitar que dados desatualizados permaneçam no SRD.
Para tal, o SRD precisa detectar que falhou e passar por um procedimento de regeneração, que consiste em descartar os
dados do log, antes de voltar a atender a novos pedidos de replicação. A forma como o SRD detecta que falhou depende
do modo como o SRD é implementado, mais especificamente, do modelo de replicação adotado, da semântica de falha e
do protocolo de replicação do serviço. Esses detalhes serão abordados na próxima seção.
3.5. Recuperação de um Sistema de Arquivos após um Crash da Hospedeira
Considera-se a ocorrência de um crash toda vez que as estruturas de dados do sistema de arquivo, residentes em
memória, são perdidas. Isso pode ser causado por um crash da hospedeira, bem como por um crash do sistema
operacional. A recuperação de crash é o ato de restaurar o sistema de arquivo em disco para um estado consistente, de
modo que preserve as garantias oferecidas pelo Salius às aplicações. A execução do PR do Salius assegura a estabilidade
de todos os dados armazenados através de suas primitivas.
O PR utiliza um mecanismo de recuperação para frente: todos os dados e metadados atualizados no sistema de arquivo,
que são perdidos em decorrência de um crash, permanecem guardados no SRD; o PR obtém esses dados e providencia a
gravação dos mesmos no disco, na mesma ordem em que foram gerados. Assim, o mecanismo de recuperação do Salius
garante a durabilidade dos efeitos de operações realizadas antes do crash da hospedeira.
As mensagens de replicação contêm informações de controle, indicando a ordem em que as atualizações do sistema de
arquivo aconteceram. Por exemplo, a implementação do Salius pode englobar um contador de pedidos de replicação
único para cada sistema de arquivo. Assim, toda vez que o SAC executa uma operação de atualização, o contador é
incrementado e o número do pedido é enviado na mensagem de replicação, para o SRD. Quando o PR obtém as
mensagens de replicação de volta, ele ordena os dados recuperados pelo número do pedido, antes de iniciar a gravação
em disco.
Como o procedimento de recuperação realiza as atualizações na mesma ordem na qual elas foram originalmente
realizadas, a operação de recuperação é idempotente. Assim, mesmo que ocorra um crash durante a recuperação, o
procedimento pode ser repetido: mesmo que a recuperação já tenha sido parcialmente realizada, o sistema de arquivo
sempre chega ao mesmo estado final.
O PR assegura, única e exclusivamente, a recuperação de dados armazenados através de primitivas do Salius. Ele não
trata os dados armazenados pelas primitivas tradicionais do sistema de arquivo. Para esse subconjunto de dados, devem
ser utilizados os procedimentos de recuperação oferecidos pelo próprio sistema de arquivo. O UNIX, por exemplo, utiliza
um programa de recuperação, denominado fsck, para remover inconsistências do sistema de arquivo. O fsck continua
sendo necessário, para o subconjunto de dados armazenado com as primitivas originais do UNIX.
7
Existe uma situação especial, que merece ser considerada pelo PR. A explicação de tal situação será feita através de um
cenário dividido em cinco partes, cada uma delas apresentando um momento diferente do sistema de arquivo. No tempo
t1, um bloco de dados x foi atualizado e replicado por uma primitiva do Salius. No tempo t2 > t1, uma parte do conteúdo
de x foi atualizada por uma chamada de sistema original do UNIX. Em t3 > t2, x foi gravado no disco e sua cópia
replicada tornou-se desatualizada. Em t4 > t3, ocorreu um crash e o conteúdo da memória da hospedeira foi perdido. Em
t5 > t4, o PR foi ativado e gravou no disco a cópia obsoleta de x, enviada pelo SRD, sobrepondo uma atualização mais
recente.
A situação retratada é rara e pode ser evitada, se a implementação do SRD puder impedir a manutenção de blocos
obsoletos. Para tal, o SAC mantém uma tabela de pedidos pendentes em sua memória, para controlar os pedidos que já
foram estabilizados. Essa tabela mantém, para cada pedido, uma lista invertida, com os números de todos os blocos de
dados replicados pelo pedido. Quando um bloco é gravado no disco, ele é retirado das listas invertidas. Assim, quando a
lista de blocos de um pedido torna-se vazia, significa que aquele pedido foi estabilizado. Ao enviar um pedido de
replicação, o SAC consulta a tabela de pedidos pendentes, para enviar às réplicas do SRD o número do maior pedido já
estabilizado. Essa informação é utilizada pelas réplicas do SRD para descartar de seus logs os pedidos obsoletos.
Para o subconjunto de dados armazenados pelo Salius, a recuperação de crash é potencialmente muito rápida. Não é
necessário realizar verificações na estrutura de metadados do sistema, porque todos os metadados afetados numa
determinada operação são automaticamente replicados, junto com os dados alterados. Se a implementação do SRD
puder impedir a situação atípica relatada anteriormente, então, também será capaz de fornecer sempre a versão mais
atualizada dos dados e metadados do sistema de arquivo. Nesse caso, a recuperação resume-se em obter os dados
replicados antes do crash e gravá-los no disco.
4. PROJETO DE UM SRD
O SRD é implementado através de processos, denominados Servidores de Replicação de Dados, executando em várias
máquinas do sistema distribuído. Cada processo excuta dois protocolos: um protocolo de replicação que recebe e
armazena os dados replicados na execução das primitivas do Salius e envia confirmações para o SAC que enviou um
pedido de replicação; e um protocolo de recuperação que fornece a um PR os dados necessários à recuperação da
consistência de um sistema de arquivo.
4.1. Modelo do Sistema
Considera-se um sistema distribuído assíncrono [8]. Nesse tipo de sistema processadores e processos falham somente
por crash. Além disso, não há uma noção global de tempo, nem limites máximos conhecidos do atraso na comunicação
entre dois processos operacionais. Dessa forma, temporizadores não podem ser usados para detectar, confiavelmente, a
falha de um processo. Considera-se ainda que as mensagens enviadas podem ser perdidas ou recebidas fora de ordem,
mas não podem ser corrompidas ou duplicadas.
O número de réplicas que implementam o SRD é definido de acordo com o grau de tolerância a faltas desejado. Como a
semântica de falha dos processos é crash, o SRD deve ser implementado por pelo menos f+1 réplicas, para que seja
possível tolerar f faltas [5]. Nesse caso, cada pedido de replicação do SAC precisa ser confirmado por f+1 réplicas, para
que a replicação seja considerada bem-sucedida: se o SAC não receber mensagens de, pelo menos, f+1 réplicas distintas,
confirmando o recebimento de um pedido de replicação, num tempo máximo predefinido, então o SAC assume que o
SRD falhou.
Sendo n o número de réplicas, f o número máximo de falhas a tolerar e freal o número real de replicas que falharam, o
SRD pode falhar em duas situações distintas: i) quando n - freal < f+1; ou ii) quando ocorre um particionamento (real ou
virtual) entre o SAC e um número suficientemente grande de réplicas do SRD, ou seja, quando o serviço de
comunicação falha, temporariamente, impedindo que o SAC receba mensagens de confirmação de pelo menos f+1
réplicas.
O SRD precisa atender, de forma equilibrada, a dois requisitos, normalmente conflitantes: i) enviar a mensagem de
confirmação de um pedido de replicação, o mais rapidamente possível; e ii) ter uma alta probabilidade de manter estável
uma informação, para a qual uma mensagem de confirmação foi enviada a um SAC.
O balanceamento entre tais requisitos é obtido através da escolha dos valores de n e f. Quanto maior f, maior é a
probabilidade da informação poder ser recuperada, após um crash; por outro lado, quanto menor f+1 (número de
respostas para confirmar a estabilidade de um pedido), mais rapidamente a confirmação será recebida pelo SAC.
Por outro lado, se n = f+1, então, basta que uma réplica falhe, para que o SRD deixe de atender aos pedidos de
replicação e o Salius passe a utilizar a gravação síncrona, deixando de ser vantajoso, em relação às técnicas de
armazenamento estável existentes. Assim, quanto maior n - (f+1), maior a probabilidade de, pelo menos, f+1 réplicas
8
não falharem no atendimento a um pedido de replicação, diminuindo a ocorrência de gravações síncronas. Fazendo n =
2f+1, a única possibilidade de falha do SRD será devida a uma falha na comunicação entre o SAC e as réplicas.
Considera-se que o SRD é implementado por 2f+1 réplicas. Note que nesse caso, mesmo quando todas as operações de
replicação são realizadas com sucesso, algumas réplicas podem ficar desatualizadas: uma falha do serviço de
comunicação pode impedir que algumas das réplicas recebam um pedido de replicação, muito embora outras f+1
réplicas do SRD consigam atender ao pedido, enviando mensagens de confirmação ao SAC. Nesse caso, o SAC recebe
f+1 mensagens de confirmação para um pedido de replicação, mas algumas réplicas do SRD não contêm os dados
daquele pedido. Mesmo assim, ainda é possível recuperar o sistema de arquivo, como será mostrado na Subseção 3.4.
4.2. Protocolo de Replicação
Após realizar as alterações de dados e metadados de um sistema de arquivo, na memória principal, o SAC tenta replicar
todos os dados alterados, antes de retornar o controle para a aplicação. Para isso, o SAC envia um pedido de replicação
ao SRD, usando o protocolo descrito a seguir.
Conforme discutido na Subseção 2.3, a identificação de um pedido deve indicar a ordem na qual ele foi gerado. Como
sistema de arquivo do UNIX é centralizado, é possível implementar um contador de pedidos, único para cada sistema de
arquivo e armazenado numa região crítica da memória. Assim, antes de enviar uma mensagem de replicação, um SAC
obtém um número de pedido e monta o identificador do pedido, contendo: o identificador da máquina onde o sistema de
arquivo reside, o identificador do sistema de arquivo e o número do pedido.
O SAC controla os efeitos das possíveis falhas do SRD através de um mecanismo bastante simples. O SAC monta a
mensagem de replicação com os dados e metadados alterados, além de um cabeçalho com informações de controle,
dentre as quais: o identificador do pedido e o identificador do último pedido gravado sincronamente pelo SAC. Quando
termina de montar a mensagem, o SAC tenta realizar a replicação. Para isso, envia o pedido a todas as réplicas do SRD e
espera pela confirmação da replicação, durante um intervalo de tempo predefinido. Se, nesse tempo, chegarem
mensagens de confirmação para o pedido de, pelo menos, f+1 réplicas do SRD, o SAC assume que a replicação foi bemsucedida. Caso contrário, o SAC assume que o SRD falhou. Quando o SAC detecta uma falha no SRD durante uma
tentativa de replicar dados ele grava sincronamente todas as informações não estáveis e o identificador do último pedido
de replicação enviado ao SRD. O pseudocódigo apresentado na Figura 2, descreve as ações realizadas pelo SAC.
SAC:
altera dados em memória;
adquire região crítica;
m = (sac_id, último_pedido_estável, ++pedido, dados);
envia m para todas as réplicas;
inicia temporizador;
respostas = 0;
faça {
receba resposta;
se (resposta.pedido == pedido) respostas++;
} enquanto (não expirar timporizador) e (respostas < f+1);
se (respostas < f+1) { /* SRD falhou */
grava sincronamente todos os dados não estáveis;
último_pedido_estável = pedido;
grava sincronamente último_pedido_estável;
}
libera região crítica;
Figura 2: Algoritmo do SAC
Ao receber um pedido de replicação, uma réplica do SRD verifica o identificador do último pedido estável nele contido.
Se o identificador é maior que o valor do último pedido estável associado ao log da réplica, então esta detecta que está
desatualizada e inicia um procedimento de regeneração. Este procedimento consiste simplesmente em descartar todas as
informações mantidas no log relativo àquele SAC. Em seguida a réplica verifica se o identificador do pedido de
replicação é maior que o último pedido estável; se esse for o caso, então trata-se de um pedido antigo e a réplica
descarta-o. Caso contrário a informação é armazenada no log da réplica (mantido em memória principal) e uma
confirmação é enviada para o SAC correspondente. O pseudocódigo da Figura 3 ilustra o funcionamento de uma réplica.
9
Réplica do SRD:
enquanto (verdade) {
recebe m;
se (m.último_pedido_estável > último_pedido_estável) {
descarta log de m.sac_id;
último_pedido_estável = m.último_pedido_estável;
}
se (m.pedido ≤ último_pedido_estável) {
descarta m;
} senão {
armazena m em log de m.sac_id;
confirmação = (m.pedido);
envia confirmação para m.sac_id;
}
}
Figura 3: Algoritmo de uma réplica do SRD
4.3. Protocolo de Recuperação
Quando uma hospedeira reinicia, após um crash, o PR deve ser executado, para restaurar o sistema de arquivo. Para isso,
o PR interage com as réplicas do SRD, a fim de obter os dados replicados antes do crash. Para simplificar a descrição do
protocolo, vamos assumir que durante a execução do PR não há particionamentos da rede nem perda de mensagens,
dessa forma uma mensagem enviada pelo PR é sempre recebida por uma réplica operacional, e vice-versa. Normalmente
é possível definir um atraso máximo na transmissão de mensagens em um sistema distribuído (principalmente se a
estimativa desse limite máximo pode ser feita de forma conservadora), dentro do qual a maior parte das mensagens são
entregues. Na prática os sistemas distribuídos alternam entre longos períodos de estabilidade, onde a troca de mensagens
se dá dentro desse limite, e curtos períodos de instabilidade, quando esse limite não é respeitado. Dentro desse contexto,
perdas de mensagens podem ser tratadas através de um mecanismo de temporização e retransmissão [6].
O PR envia uma mensagem para cada uma das réplicas, informando o início da recuperação. Cada réplica operacional
do SRD envia uma resposta ao PR, informando o seu estado de atualização, ou seja, o identificador do último pedido de
replicação atendido.
O PR então espera pela resposta de f+1 réplicas e escolhe como pedido base para recuperação aquele com o maior valor
entre as respostas recebidas. O PR então lê do disco o valor correspondente ao último pedido gravado sincronamente
pelo SAC e compara este valor com o valor calculado com base nas respostas das réplicas; se o valor calculado é menor
que o valor armazenado no disco, significa que quando houve o crash na hospedeira, o SAC não estava usando o SRD
(por causa de um particionamento na rede, por exemplo) e portanto os dados do sistema de arquivo já foram
estabilizados (já que as alterações dos dados foram realizadas através de gravações síncronas – veja Figura 2), não
necessitando qualquer intervenção do PR. Caso contrário é preciso recuperar todos os pedidos com identificadores
maiores que o daquele gravado em disco e que estão armazenados nas réplicas do SRD.
Com base nas informações recebidas o PR envia mensagens de solicitação de retransmissão dos pedidos necessários a
todas as réplicas do SRD. O PR inicializa um temporizador e fica esperando pelas mensagens. Se o temporizador espira
antes de todas as mensagens serem recebidas (a próxima seção discute quando isso pode ocorrer) o processo é
reiniciado. Caso contrário o PR grava os dados de cada pedido de replicação no sistema de arquivo em disco,
obedecendo à ordem na qual os pedidos foram originalmente gerados. O pseudocódigo da Figura 4 mostra o
funcionamento do PR.
4.4. Considerações sobre a Corretude dos Protocolos
Teorema 1: Após um crash da hospedeira, a execução do PR recupera o sistema de arquivo, de tal forma que nenhuma
modificação feita através de uma primitiva do Salius é perdida.
10
PR:
lê último_pedido_estável do disco;
terminou = falso;
faça {
envia “pedido de recuperação” para todas as réplicas;
num_respostas = 0;
último_pedido = último_pedido_estável;
faça {
recebe m;
se (m.pedido > último_pedido) último_pedido = m.pedido;
} enquanto (++num_respostas < f+1);
se (último_pedido > último_pedido_estável) {
inicia temporizador;
para i (último_pedido_estável+1, último_pedido) faça {
envia “quero pedido i” para todas as réplicas;
recebe resposta;
}
grava pedidos ordenados pelo número do pedido;
terminou = verdade;
} senão terminou = verdade;
} enquanto (não expirou temporizador) e (terminou = false);
Figura 4: Algoritmo do PR
Prova (esboço): Sejam pu o pedido associado com a última ativação de uma primitiva do Salius que retornou com
sucesso para a aplicação, antes da hospedeira falhar; pe, pe ≤ pu, o valor do último pedido, cujos dados foram gravado no
disco da hospedeira; e pmax o maior valor de último pedido armazenado em um log obtido das primeiras f+1 respostas
recebidas pelo PR (veja algoritmo da Figura 4). Como n = 2f+1 e pelo menos f+1 réplicas confirmaram a replicação de
pu, então pu ≤ pmax.
Se pmax = pe, então, de acordo com o algoritmo da Figura 2, as modificações associadas a pmax estão gravadas no próprio
disco da hospedeira, e nehuma operação extra é requerida (veja algoritmo da Figura 4).
Caso contrário, temos duas situações: i) pe < pu = pmax; e ii) pe < pu < pmax.
Se pmax = pu então, segundo o algoritmo da Figura 2, o SAC recebeu f+1 confirmações de réplicas, indicando que pmax
foi armazenado em seus respectivos logs. Como, no máximo, f réplicas podem falhar, existe pelo menos uma réplica
operacional que armazenou p em seu log. Por sua vez, o log de uma réplica só é descartado quando ela recebe um
pedido de replicação com um identificador de último pedido estável maior do que o identificador de último pedido
estável que ela mantém localmente. Além disso, se qe é o identificador do último pedido estável associada a um log que
contém p, então qe < p (veja o algoritmo da Figura 4). Para que uma réplica que contém p em seu log descarte esse log,
e portanto p, é necessário que esta receba um pedido de replicação com um identificador de último pedido estável re ≥ p.
Dessa forma, pmax não pode Ter sido removido do log, já que os pedidos de replicação enviados pelo SAC da hospedeira
antes do crash contém identificadores de último pedido estável se, tal que se ≤ pe < pmax (veja o algoritmo da Figura 3).
O mesmo raciocínio é valido para qualquer pedido q, pe < q ≤ pmax. Portanto, o PR poderá recuperar todos os pedidos
cujas informações podem não ter sido gravadas no disco da hospedeira e pode providenciar as suas gravações na ordem
correta.
A situação em que pmax > pu ocorre apenas quando a hospedeira falha no meio da execução de uma primitiva do Salius.
Mais precisamente, quando um pedido de replicação com um identificador de pedido pmax e identificador de último
pedido estável pe é enviado às replicas do SRD e algumas réplicas do SRD recebem o pedido, mas antes de receber a
confirmação de f+1 réplicas a hospedeira falha. Note que pela definição de pu o SAC não pode receber f+1 confirmações
para o pedido pmax e como nesse caso temos pmax > pe, mesmo que o temporizador para a espera das confirmações tenha
expirado, o SAC deve necessariamente ter falhado antes de poder gravar no disco o valor de pmax como sendo o
identificador do último pedido estável. Além disso, teremos necessariamente pmax = pu+1. Nesse caso, como o pedido
pmax corresponde a uma ativação de uma primitiva do Salius que não retornou com sucesso (a hospedeira falhou antes do
retorno da primitiva), o PR não precisa necessariamente recuperar esse pedido. Como não se pode garantir que f+1
réplicas contêm pmax em seus logs, é possível que todas as réplicas que contêm pmax em seus logs falhem e o PR ficará
bloqueado esperando por uma mensagem que contenha esse pedido. Nesse caso o temporizador irá expirar e um novo
valor para pmax será calculado. Entretanto, após um número finito de tentativas o PR conseguirá recuperar o sistema de
arquivo, considerando ou não o pedido pmax.
‫ٱ‬
11
5. CONCLUSÕES
O Salius possibilita que os avanços tecnológicos em curso beneficiem mais o sistema, porque consegue diminuir a
influência da tecnologia de disco no desempenho global do sistema, ao eliminar a urgência de gravar dados em disco. O
desempenho do sistema passa a depender mais dos processadores, da capacidade de memória disponível, da velocidade
de acesso à memória, das taxas de transmissão da rede e da banda passante da rede disponível para esse serviço,
enfraquecendo o vínculo existente com a tecnologia de disco. Dessa forma, o serviço permite que o sistema utilize mais
agressivamente as técnicas de otimização de desempenho, baseadas em caching em memória principal.
Dessa forma, a nova técnica de armazenamento estável apresentada é potencialmente capaz de substituir, de forma
vantajosa, as soluções que usam apenas a gravação síncrona em disco. Baseados em nossas próprias medidas
preliminares [16] e em outros trabalhos correlatos [7, 12], acreditamos que uma implementação eficiente do Salius
deverá levar a um desempenho superior àquele de técnicas baseadas na gravação síncrona em disco.
O Salius apresenta a desvantagem de aumentar o consumo da banda passante do meio de comunicação, pois o
funcionamento do serviço exige a troca constante de mensagens entre um SAC e o seu SRD. Teoricamente, a utilização
de redes de alta velocidade diminuiria a probabilidade de um congestionamento inviabilizar a replicação de dados.
Porém, somente a experimentação, através de simulação ou implementação do serviço, permitirá uma avaliação mais
precisa dos efeitos do aumento do tráfego de dados na rede, causados pelo Salius.
REFERÊNCIAS
1. The Power Protection Handbook. Technical report, American Power Conversion, 1996.
2. Anderson, T. et al. Serverless Network File Systems. Proceedings of the 15th Symp. on Operating Systems
Principles, 109-126, dezembro 1995.
3. Baker, M. et al. Non-Volatile Memory for Fast Reliable File Systems. Fifth International Conference on
Architectural Support for Programming Languages and Operating Systema (ASPLOS-V), pp. 10-22, outubro 1992.
4. Chen, P.M. et al. The Rio File Cache: Surviving Operating Systems Crashes. Seventh International Conference on
Architectural Support for Programming Languages and Operating Systems, SIGPLAN Notices, 31(9): 74-83,
setembro 1996.
5. Cristian, F. Understanding Fault-Tolerant Distributed Systems. Communications of the ACM, 34(2): 56-78,
fevereiro 1991.
6. Cristian, F., e Fetzer, C. The Timed Asynchronous Distributed System Model. IEEE Transactions on Parallel and
Distributed Systems, 10(6): 642-657, junho 1999.
7. Dahlin, M. et al. A Quantitative Analysis of Cache Policies for Scalable Network File Systems. Proceedings of the
SIGMETRICS Conference on Measurement and Modeling of Computer Systems, pp. 150-160, maio 1994.
8. Fischer, M.J., Lynch, N.A., e Paterson, M.D. Impossibility of Distributed Consensus with One Faulty Process.
Journal of ACM, 32(2): 374-382, abril 1985.
9. Hartman, J., e Ousterhout, J. The Zebra Stripped Network File System. ACM Transactions On Computer Systems,
13(3): 274-310, agosto 1995.
10. Liskov, B. et al. Replication in the Harp File System. Proceedings of the Thirteenth ACM symposium on Operating
Systems Principles, pp. 226-238, outubro 1991.
11. McKusick, M. et al. A Fast File System for UNIX. ACM Transactions on Computer Systems, 2(3): 181-197, agosto
1984.
12. Plank, J.S., Li, K., e Puening, M.A. Diskless Checkpointing. IEEE Transactions on Parallel and Distributed
Systems, 9(10): 972-986, outubro 1998.
13. Ritchie, D., e Thompson, K. The UNIX Time-Sharing System. The Bell System Thecnical Journal, 57(6): 19051930, julho 1978.
14. Rosenblum, M. e Ousterhout, J. The Design and Implementation of a Log-Structured File System. ACM
Transactions on Computing Systems, 10(1): 26-52, fevereiro 1992.
15. Seltzer, M. et al. An Implementation of a Log-Structured File System for UNIX. Proceedings of the Winter 1993
USENIX Conference, pp. 307-326, janeiro 1993.
16. Stanchi, T.S. SALIUS – Serviço de Armazenamento Estável com Recuperação para Frente Baseado em Replicação
Remota de Buffers. Dissertação de Mestrado, Coordenação de Pós-Graduação em Informática, Universidade
Federal da Paraíba, Campina Grande, fevereiro 2000.
17. Wu, M., e Zwaenepoel, W. eNVy: Non-Volatile, Main Memory Storage Syatem. Proceedings of the 1994
International Conference on Architectural Support for Programming Languages and Operating Systems
(ASPLOS), outubro 1994.
12
Download

Armazenamento Estável através da Replicação Remota de Dados