\chapter{Cluster de Armazenamento}
\label{clusterarmazenamento}
\cutname{clusterarmazenamento.html}
\section{Introdução}

O aumento da capacidade de processamento e a maior utilização de sistemas informatizados para automatizar e auxiliar a execução dos mais variados processos e sistemas de informação, ocasionou um acúmulo de informações e de dados que necessitam ser armazenados e consolidados. 

Conjuntamente com este aumento na demanda de armazenamento dos dados, a capacidade e as tecnologias de armazenamento evoluíram expressivamente nos últimos anos, chegando recentemente a alcançar PetaBytes\footnote{ $1 PetaByte = 1.073.741.824 MegaByte$}.

No ambiente corporativo são utilizadas diversas mídias e tecnologias para armazenamento de dados, de uma maneira geral podem ser classificadas em dois grandes grupos: 


\begin{itemize}
	\item Tecnologias de Armazenamento \textit{Online} - Encontram-se nesta categoria as tecnologias de armazenamento normalmente utilizadas por aplicações ou sistemas que demandam o acesso online aos dados. Alguns exemplos de tecnologias que encontram-se neste grupo são: Disco Rígido, \textit{Storage Devices}, Sistemas de arquivos distribuídos, Sistemas de Arquivos Paralelos, Dispositivos Raid, Controladoras de Discos, entre outras.
	\item Tecnologias de Armazenamento \textit{Offline} - Encontram-se neste grupo as tecnologias de armazenamento normalmente utilizadas para armazenar dados de backup ou dados que não precisam ser acessados \textit{online}. Alguns exemplos de tecnologias que encontram-se neste grupo são: Fitas, CD, DVD, dispositivos de fitas, bibliotecas de fitas.
\end{itemize}

Em sistemas críticos normalmente são utilizados dispositivos de armazenamento proprietários denominados "\textit{Storage Devices}" e/ou "Bibliotecas de Fita" que possuem capacidade de armazenar Terabytes de informações, com funcionalidades que permitem consolidar e manter a integridade dos dados em um ambiente centralizado. 

Existem alternativas tecnológicas de Cluster e Grid baseadas em padrões abertos de hardware e software para a implementação da camada de armazenamento e consolidação de dados em sistemas críticos. 

Estas tecnologias em Cluster e Grid para armazenamento podem ser divididas em 3 categorias: 
\begin{itemize}
	\item Tecnologias baseadas em dispositivos de Blocos
	\item Sistemas de Arquivos Distribuídos
	\item Sistemas de Arquivos Paralelos
\end{itemize}
Sendo abordadas as principais tecnologias neste capítulo.
%Introdução
% Importância do armazenamento
% Consolidação dos dados
% Integridade dos dados
% Crescimento da demanda por capacidade de processamento nos órgãos de governo
% Utilização de storage devices e bibliotecas de fita para suprir esta demanda
% Possibilidade de utilização de tecnologias em Cluster

%Desenvolvimento
% Tipos de alternativas em Cluster


%HEVEA\cutdef[1]{section}

\section{\textit{Block Devices}}
\label{blockdevices}
\cutname{blockdevices.html}
% Block Devices
%  DRBD
% 	\subsubsection{Descrição}

	A definição básica de dispositivos de blocos é:

	``Bloco especial de arquivo ou dispositivo de blocos são usados para corresponder a dispositivos pelos quais os dados são transmitidos na forma de blocos. Estes nós de dispositivo são freqüentemente usados para dispositivos de comunicações paralelos como discos rígidos e drives de CD-ROM." \cite{wikiBD}

	``A diferença mais significante entre dispositivos de blocos e dispositivos de caráter, é que os dispositivos de blocos tem rotinas de \textit{buffer} para os controles de entrada e saída. O sistema operacional aloca um \textit{buffer} de dados para prender cada bloco simples para a entrada e saída. Quando um programa envia um pedido de dados para ser lido , ou escrito, no dispositivo, cada caráter de dados é armazenado no \textit{buffer} apropriado. Quando o \textit{buffer} está cheio e um bloco completo é alcançado, a operação apropriada é executada e o \textit{buffer} é limpo."\cite{wikiBD}

Os Dispositivos de Blocos são a parte de sustentação dos sistemas de arquivos dos sistemas operacionais. Sendo sua manipulação um processo básico para exploração de dispositivos de armazenamento.

Existem várias implementações de Dispositivos de Blocos com a intenção de serem utilizados em ambientes de Cluster. Neste capítulo serão apresentados os mais conhecidos.

\subsection{Arranjo Redundante de Discos - RAID}

O Arranjo redundante de discos (\textbf{Redundant Array of Independent Disks - RAID}), é um sistema que usa múltiplos discos rígidos para compartilhar ou replicar dados entre esses discos.
Dependendo da versão escolhida, o benefício do RAID é um ou mais vezes o incremento da integridade de dados, de tolerância à falhas, de desempenho ou de aumento de capacidade de armazenamento de dados, comparado com um simples disco.

Em suas implementações originais, sua vantagem chave era a habilidade de combinar  múltiplos dispositivos de baixo custo usando uma tecnologia mais antiga em uma disposição que oferecesse uma grande capacidade de armazenamento, confiabilidade, velocidade, ou uma combinação destas.
Num nível bem mais simples, RAID combina múltiplos discos rígidos em uma única unidade lógica.  Assim, em vez  do sistema operacional ver diversos discos rígidos diferentes, ele vê somente um disco rígido. O RAID é usado tipicamente em servidores, e geralmente, mas não necessariamente, é implementado com discos rígidos de tamanhos idênticos.

Com as diminuições dos preços de discos rígidos e com a disponibilidade em larga escala de RAID em \textit{chipsets} de placas-mãe, RAID vem se tornando uma opção para computadores de usuários mais avançados, assim como na criação de grandes sistemas de armazenamento de dados.

Usuários avançados vem usando RAID em suas estações de trabalho e \textit{Workstations} para aplicações que necessitam de utilização intensiva de disco, seja de leitura/escrita ou mesmo capacidade de armazenamento, como no caso de aplicações de edição de vídeo e áudio.


\subsection{RAID via Hardware e via Software}


RAID pode ser implementado por hardware, na forma de controladoras especiais de disco, ou por software, como um módulo do kernel que fica dividido entre a controladora de disco de baixo nível e o sistema de arquivos acima dele.



\textbf{RAID via hardware} é um controlador de disco, isto é, um dispositivo físico que pode através de cabos conectar os discos. Geralmente ele vem na forma de uma placa adaptadora que pode ser ``plugada"~ em um \textit{slot} ISA/EISA/PCI/S-Bus/MicroChannel. Entretanto, algumas controladoras RAID vêm na forma de uma caixa que é conectada através de um cabo entre o sistema controlador de disco e os dispositivos de disco.

RAIDs pequenos podem ser ajustados nos espaços para disco do próprio computador; outros maiores podem ser colocados em um gabinete de armazenamento, com seu próprio espaço, para disco e suprimento de energia. O hardware mais novo de RAID usado com a mais recente e rápida CPU irá provavelmente fornecer o melhor desempenho total, porém com um preço expressivo. Isto porque a maioria das controladoras RAID vem com processadores especializados na placa e memória cache, que pode eliminar uma quantidade de processamento considerável da CPU. As controladoras RAID também podem fornecer altas taxas de transferência através do cache da controladora.



RAID via hardware geralmente não é compatível entre diferentes tipos, fabricantes e modelos: se uma controladora RAID falhar, é melhor que ela seja trocada por outra controladora do mesmo tipo. Para uma controladora de RAID via hardware poder ser usada no Linux ela precisa contar com utilitários de configuração e gerenciamento, feitos para este sistema operacional e fornecidos pelo fabricante da controladora.





\textbf{RAID via software} é uma configuração de módulos do kernel, juntamente com utilitários de administração que implementam RAID puramente por software, e não requer um hardware especializado. Pode ser utilizado o sistema de arquivos ext2, ext3, DOS-FAT, etc.

Este tipo de RAID é implementado através dos módulos MD do kernel do Linux e das ferramentas relacionadas.

RAID por software, por sua natureza, tende a ser muito mais flexível que uma solução por hardware. O problema é que ele em geral requer mais ciclos e capacidade da CPU para funcionar bem, quando comparado a um sistema de hardware, mas também oferece uma importante e distinta característica: opera sobre qualquer dispositivo do bloco podendo ser um disco inteiro (por exemplo, \textit{/dev/sda}), uma partição qualquer (por exemplo, \textit{/dev/hdb1}), um dispositivo de \textit{loopback} (por exemplo, \textit{/dev/loop0}) ou qualquer outro dispositivo de bloco compatível, para criar um único dispositivo RAID. Isso diverge da maioria das soluções de RAID via \textit{hardware}, onde cada grupo unifica unidades de disco inteiras em um arranjo.

Comparando as duas soluções, o RAID via \textit{hardware} é transparente para o sistema operacional, e isto tende a simplificar o gerenciamento. Já o  via \textit{software}, tem mais opções e escolhas de configurações, fazendo sua manipulação mais complexa.

\subsection{\textit{Distributed Replicated Block Device - DRBD}}
\label{drbd}
\textbf{Projeto:DRBD}\\
\textbf{Sítio Oficial:\url{http://www.drbd.org}}\\
\textbf{Licença:GPL}\\
\textbf{Responsável: LinBit - \url{http://www.linbit.com}}\\

DRBD é um acrônimo para o nome inglês \textit{Distributed Replicated Block Device}. O DRBD consiste num módulo para o kernel de Linux, juntamente com alguns \textit{scripts} e programas, que oferecem um dispositivo de blocos projetado para disponibilizar dispositivos de armazenamento distribuídos, geralmente utilizado em clusters de alta disponibilidade. Isto é feito espelhando conjuntos de blocos via rede (dedicada). O DRBD funciona, portanto, como um sistema RAID baseado em rede.


\subsubsection{Como Funciona}

A figura \ref{fig:drbd_concept} mostra a visão do nível conceitual de funcionamento do DRBD - Trata-se de um \textit{driver} intermediário entre o \textit{block device} virtual (/dev/drbd*), o \textit{block device} real local (/dev/[sh]d*) e os \textit{block device's} remotos. Todas as transferências são efetuadas pelo protocolo TCP/IP, o que permite sua implementação até mesmo em máquinas geograficamente afastadas.


\begin{figure}[!htb]
\centering
\insimg{1.3}{imagens/DRBD_concept_overview.png}
\caption{Visão do nível conceitual de funcionamento do DRBD.}
\label{fig:drbd_concept}
\end{figure}

Cada dispositivo envolvido (tratados localmente como partições) tem um estado, que pode ser primário ou secundário. O DRBD cria, em todos os nós, um vínculo entre um dispositivo virtual (/dev/drbdX) e uma partição local, inacessível diretamente. Toda a escrita é realizada no servidor primário, que irá transferir os dados para o ''dispositivo de bloco do nível mais baixo'' (a partição) e propagá-los para os restantes servidores, de estado ''secundário''. O secundário simplesmente escreve os dados no ''dispositivo de bloco do nível mais baixo''. As leituras são sempre realizadas localmente.

Se o servidor primário falhar, o DRBD mudará o dispositivo secundário para primário e as transferências passarão a ocorrer no sentido oposto. Note que o DRBD não trabalha no nível do sistema de arquivos, mas sim ao nível de blocos do disco rígido. Nos sistemas de arquivos que não disponibilizam \textit{journaling}, deverá ser realizada após à transição primário-secundário uma verificação da consistência do sistema de arquivos; em Linux, significa executar o \textit{fsck}.

Para evitar a execução da verificação da consistência do sistema de arquivos, um processo altamente custoso, recomenda-se a utilização de sistemas de arquivos que possuam \textit{journaling}.

Se o servidor que falhou retornar, o DRBD, mediante as configurações, devolverá - ou não - o estado de primário ao servidor original, após uma sincronização. Em caso negativo, o chamado modo \textit{legacy}, o servidor que detém o estado de primário irá conservá-lo até o serviço ser encerrado nessa máquina.

Apesar do DRBD possuir o seu próprio modo de determinar qual dos servidores deverá ser primário, a sincronização com o sistema genérico não é trivial. Para reduzir estas dificuldades e a necessidade de interação do usuário,freqüentemente é utilizado um sistema gerenciador de cluster, como o \textit{heartbeat}, para tratar das transições de estado. Além desta transição de estados, o sistema será responsável por montar o sistema de arquivos na nova máquina que se tornou primária.

\subsubsection{Características}

\begin{figure}[!htb]
\centering
\insimg{1.3}{imagens/DRBD_mirroring_constraint.png}
\caption{Fluxo de intercomunicação entre as camadas dos dispositivos Linux - repare que o DRBD não tem como notificar o módulo do sistema de arquivos - mas o oposto ocorre.}
\label{fig:mirroring_constraint}
\end{figure}


Nota-se, no entanto, que:
\begin{itemize}
    \item Se as partições não forem do mesmo tamanho, o dispositivo DRBD irá automaticamente assumir-se como sendo do tamanho mínimo entre as partições envolvidas - o que permite alguma flexibilidade relativamente aos discos disponíveis em cada nó.
    \item Apenas um dos nós pode ter acesso de leitura e escrita (\textit{ReadWrite, R/W})[KROVICH], e será designado como DRBD/\textit{Primary}. O(s) restante(s) nó(s) será/serão designado(s) como DRBD/\textit{Secondary}. Embora o nó DRBD/\textit{Secondary} possa montar o dispositivo (apenas) em modo ReadOnly (R/O), é praticamente inútil, dado que as atualizações ocorrem apenas num sentido (do \textit{Primary} para o \textit{Secondary}) e a camada que gere \textit{block device's} não dispõe de nenhuma forma de notificar alterações na camada que gere o sistema de arquivos embutido.
\end{itemize}

\subsubsection{Situação do projeto}

A maioria dos clusters HA (HP,Compaq,...) atualmente utilizam dispositivos de armazenamento compartilhados; estes dispositivos, altamente dispendiosos, permitem que sejam conectados simultaneamente mais de um servidor, em geral através do barramento SCSI compartilhado ou \textit{Fiber Channel}.

O DRBD usa a mesma semântica de um dispositivo compartilhado, mas não necessita de nenhum hardware específico. Ele trabalha no topo de redes IP, que são de implementação generalizada e de baixo custo, comparativamente aos sistemas dedicados de armazenamento (como \textit{Storage Area Networks} - SAN).

Atualmente o DRBD garante acesso de leitura-escrita apenas num servidor de cada vez, o que é suficiente para a implementação de sistemas  \textit{fail-over} típico de um cluster HA. Existe uma versão de desenvolvimento 0.8 que garante acesso de leitura-escrita para dois servidores, entretanto esta versão ainda não está estável suficiente para ser utilizada em ambientes de produção. As possibilidades de aplicação serão múltiplas, como para servidores web ou banco de dados de larga escala, onde operam sistemas de arquivos como o GFS, ou OCFS2, por exemplo.

Para se utilizar a versão de desenvolvimento do drbd(0.8), no modo \newline Primário/Primário é necessário utilizar um sistema de arquivos compartilhado como por exemplo os citados acima. Somente um sistema de arquivos compartilhado é capaz de gerenciar o \textit{lock} de acesso de maneira global ao sistema de arquivos, garantindo a integridade dos dados. Não se deve ser utilizado sistemas de arquivos comuns, tais como: xfs, ext3, reiserfs, neste modo de operação do drbd.

%  GNBD
\subsection{\textit{Global Network Block Device - GNBD}}
\textbf{Projeto:} Global Network Block Device\\
\textbf{Sítio Oficial:} http://sources.redhat.com/cluster/gnbd/\\
\textbf{Licença:} GPL\\
\textbf{Responsável(eis)}: Red Hat\\

GNBD (\textit{Global Network Block Devices}) \cite{GFS} é um dispositivo que provê o acesso no nível de blocos a dispositivos de armazenamento remotos em uma rede TCP/IP. O GNBD é composto por um módulo no kernel e um conjunto de utilitários de sistema,  possuindo uma parte servidora, que é responsável por exportar o disco via rede, e uma parte cliente, que é responsável por mapear localmente um disco remoto.

A parte servidora do GNBD é capaz de exportar qualquer dispositivo de blocos, alguns exemplos de dispositivos de blocos são: Disco Rígidos Ide ou SCSI, Pendrive, Volumes lógicos, DRBD, dispositivos armazenados em \textit{storage devices}.

Normalmente um servidor GNBD exporta um dispositivo de blocos local para um nó GFS\cite{GFS}. Este dispositivo exportado em rede pode ser acessado localmente e remotamente por vários servidores simultaneamente, entretanto para manter a integridade dos dados é necessário utilizar um sistema de arquivos compartilhado, como por exemplo GFS ou OCFS2.

Também é possível agregar diversos dispositivos gnbd em um ou mais volumes lógicos LVM, utilizando a tecnologia de clusterização de volumes lógicos desenvolvida pela Red Hat, CLVM. Através da utilização do GNBD e CLVM é possível criar uma estrutura de SAN\footnote{Storage Area Network} para armazenamento de arquivos em um cluster ou rede de servidores.

O gargalo de performance para configurações com um grande número de clientes, geralmente, encontra-se na conectividade de rede, pois o GNBD utiliza uma única \textit{thread} para cada instância cliente-servidor-dispositivo, desta forma, quanto mais clientes melhor será a performance do servidor gnbd (em termos de \textit{throughput} total). Obviamente, a performance por cliente irá diminuir, por conta da limitação da largura de banda. Outro fator de performance num ambiente que utilize gnbd é a performance do disco local no servidor, se esta performance for baixa, ela não será ampliada com a utilização do GNBD. Desta forma é recomendado sempre fazer uma análise da performance dos discos locais e da rede para manter um equilíbrio e tentar conseguir a maior performance possível.

É importante salientar que o GNBD não é um dispositivo de blocos distribuído ou replicado, de forma que os os dados não são replicados ou distribuídos entre dois ou mais servidores. 

A figura \ref{diagrama:gnbd} apresenta um exemplo de cenário gnbd onde o dispositivo de blocos local do servidor gnbd é exportado via rede TCP/IP para 3 clientes gnbd que mapeiam este disco localmente.

\begin{figure}[!htb]
\centering
\insimg{1.3}{imagens/diagrama_gnbd.png}
\caption{Exemplo de cenário GNBD}
\label{diagrama:gnbd}
\end{figure}

%  ISCSI 
\subsection{Internet SCSI - iSCSI}
\textit{O Internet SCSI} (iSCSI) \cite{WikipediaISCSI} é um protocolo de rede padrão, oficialmente ratificado em 11/02/2003 pelo IETF(\textit{Internet Engineering Task Force}), que permite o uso do protocolo SCSI sobre redes TCP/IP. O iSCSI é um protocolo de camada de transporte nas especificações do \textit{framework} SCSI-3. Outros protocolos de camada de transporte incluem a interface SCSI paralela e \textit{Fiber Channel}.

A Aceitação do iSCSI em ambientes de produção corporativos foi acelerada pela grande utilização de gigabit ethernet nos dias de hoje. A construção de uma \textit{Storage Area Newtork} (SAN) baseada em iSCSI se tornou mais barato, além de uma alternativa viável a utilização de SANs baseadas em \textit{Fiber Channel}.

O protocolo iSCSI utiliza TCP/IP para sua transferência de dados. Diferente de outros protocolos de armazenamento em rede, como por exemplo \textit{Fiber Channel}, para o seu funcionamento ele requer somente uma simples interface Ethernet ou qualquer outra interface de rede capaz de suportar TCP/IP. Este fato permite a centralização do armazenamento com baixo custo, sem o ônus e os problemas de incompatibilidade naturalmente associados a utilização de \textit{Fiber Channel} em SANs. 

Algumas pessoas críticas do  protocolo iSCSI esperam uma performance pior que a existente no \textit{Fiber Channel}, isto ocorre por conta do \textit{overhead} adicionado pelo protocolo TCP/IP na comunicação entre cliente e dispositivo de armazenamento. Entretanto, novas técnicas, como por exemplo \textit{TCP Offload Engine} (TOE\footnote{\url{http://en.wikipedia.org/wiki/TCP_Offload_Engine}}) ajudam a reduzir este \textit{overhead}. De fato, com a performance disponível nos servidores modernos, uma interface de rede padrão com um driver eficiente pode superar a performance de uma placa TOE porque menos interrupções e menos transferências de memória DMA são necessárias. As soluções iniciais de iSCSI são baseadas em uma camada de \textit{software}. O Mercado iSCSI está crescendo rapidamente e deve melhorar em performance e usabilidade quanto mais organizações implementarem redes gigabit e 10 gigabit, e fabricantes integrarem suporte ao protocolo iSCSI nos seus sistemas operacionais, produtos SAN e subsistemas de armazenamento. iSCSI se torna cada vez mais interessante pois as redes ethernet estão começando a suportar velocidades maiores que o \textit{Fiber Channel}.

{\bf Dispositivos de Armazenamento}\\
No contexto do armazenamento em computadores, o iSCSI permite que um iSCSI initiator conecte a dispositivos iSCSI target remotos tais como discos e fita em uma rede do IP para I/O ao nível de bloco (\textit{block level I/O}). Do ponto da vista dos drivers de sistema operacional e de aplicações de \textit{software}, os dispositivos aparecem como dispositivos locais SCSI.  Ambientes mais complexos, que consistem de múltiplos \textit{Hosts} e/ou dispositivos, são chamados de Área de Armazenamento em Rede (\textit{Storage Area Networks} - SAN).

Os dispositivos de iSCSI não devem ser confundidos com os dispositivos \textit{Network-Attached Storage}  (NAS) que incluem softwares de servidor para o controle de requisições de acessos simultâneos de vários \textit{Hosts}. Permitir que múltiplos \textit{Hosts} tenham acesso simultâneo a um simples dispositivo é uma tarefa comumente difícil para todos os dispositivos SCSI. Sem uma comunicação entre os hosts, cada um dos hosts não possui conhecimento do estado e intenção dos outros hosts. Esta condição ocasiona corrupção de dados e race conditions.  Para realizar esta tarefa através da utilização do iSCSI é necessário utilizar um sistema de arquivos compartilhado como por exemplo o GFS e o OCFS2.

\subsubsection{iSCSI Conceitos e Visão Funcional}

O protocolo iSCSI é responsável pela execução de comandos SCSI entre dois dispositivos em uma rede TCP/IP. Comandos SCSI são executados através de chamadas iSCSI e os status SCSI são retornados como respostas.

Os termos \textit{Initiator} e \textit{Targets} referem-se à ``\textit{iSCSI initiator node}"~ e ``\textit{iSCSI target node}"~ respectivamente.

De acordo com protocolos similares, o \textit{Initiator} e \textit{Targets} dividem suas comunicações em mensagens.  O termo \textit{iSCSI protocol data unit} (iSCSI PDU) é usado para designar essas mensagens.

Por razões de performance, iSCSI permite \textit{phase-collapse}. Através de um comando os seus dados associados, podem ser enviados em conjunto do \textit{Initiator} para o \textit{Targets} e os dados e respostas  podem ser respondidos em conjunto pelos \textit{Targets}.

O sentido de transferência do iSCSI é definido com respeito ao \textit{Initiator}. Os limites de saída ou a saída de dados são transferidos do \textit{Initiator} para o \textit{Targets}, enquanto que o limite de entrada de dados ou os dados entrantes são transferências do \textit{Targets} para o \textit{Initiator}.


Implementações do \textit{Initiator}, no Linux.


	Linux \textit{Initiators}:
	\begin{itemize}
		\item Core-iSCSI - Baseado em partes GPL do comercial PyX initiator \www{http://www.kernel.org/pub/linux/utils/storage/iscsi}.
		\item Intel-iSCSI (Intel) - Prova de conceito do iSCSI intiator e target da Intel para Linux \www{http://intel-iscsi.sf.net/}.
		\item Open-iSCSI - Nova implementação do initiator para Kernel 2.6.11 e superiores \www{http://www.open-iscsi.org/}.
		\item UNH-iSCSI - Initiator e target implementado pela University of New Hampshire.
	\end{itemize}

Informações mais detalhadas sobre iSCSI podem ser obtidas nas RFCs: RFC-3720 \www{http://www.ietf.org/rfc/rfc3720.txt} e RFC-3783 \www{http://www.ietf.org/rfc/rfc3783.txt}

%  HyperSCSI

% Filesystems
%  Distribuídos
%   PVFS2
%   LUSTRE
%  Compartilhados
%   GFS
%   OCFS2
%  De Rede
%   NFS
%   CIFS
\section{Sistemas de Arquivos Distribuídos}
\label{sistemasdearquivosdistribuidos}
\cutname{sistemasdearquivosdistribuidos.html}

Os Sistemas de Arquivos Distribuídos (SADs) se destacam pelo acesso remoto aos dados de forma transparente para os usuários. Nas seções a seguir, realizamos uma resenha sobre alguns deles, começando com aqueles que deram início a toda pesquisa na área. É importante deixar claro que a maior parte dessa resenha foi baseada nos textos (\cite{Kon}, \cite{Kon94}).

\subsection{Conceitos Básicos}

Nesta sessão encontram-se alguns conceitos e serviços disponibilizados pelos sistemas de arquivos distribuídos e paralelos, assim como algumas de suas características, qualidades e soluções (\cite{Gal00}, \cite{Tan92}) que os pesquisadores e desenvolvedores da área tentam prover.

\subsubsection{Nomes e Localização}

A maioria dos arquivos armazenados em um sistema de arquivos possui um nome e um caminho, que o identifica unicamente em tal sistema. Um caminho representa um nó de uma estrutura de diretórios, que pode ser representada como uma árvore (veja fig. \ref{fig:arvorediretorio}).

\begin{figure}[!htb]
\centering
\insimg{1.3}{imagens/arvorediretorio.png}
\caption{Exemplo de uma árvore de diretórios}
\label{fig:arvorediretorio}
\end{figure}

Tal árvore possui somente uma raiz. Cada nó pode possuir árvores ou arquivos.

Dessa forma, para localizar um arquivo em uma árvore de diretórios (usados para agrupar arquivos) basta seguir o caminho do arquivo e, ao chegar no diretório final, procurar pelo nome de tal arquivo. A forma como esse nome e esse caminho são definidos depende muito do sistema operacional. Por exemplo, no Unix um caminho é definido como uma seqüência de nomes de diretórios, todos separados pelo caractere ''/''. O ultimo nome dessa seqüência pode ser o nome do arquivo ou de um diretório.

Em sistemas distribuídos, é possível encontrar o nome da máquina, em que o arquivo se encontra, dentro dessa definição de caminho. Porém procura-se deixar isso transparente para o usuário.

\subsubsection{Cache}

Para melhorar o desempenho no acesso aos arquivos de um sistema, procura-se guardar informações muito acessadas em memória, para evitar a sobrecarga de se ter que obtê-las novamente do meio físico onde estão armazenadas.

Isso ajuda muito na economia de tempo de processamento pois para acessar dados remotos,
por exemplo, o sistema está limitado à velocidade da rede, que, mesmo rápida, estará limitada à velocidade do meio físico de armazenamento do servidor remoto, pois este ainda precisaria procurar os dados, carregá-los na memória e enviá-los para o cliente.

Mesmo no acesso a dados locais, a velocidade de acesso à memória é muito maior que a velocidade de acesso ao meio de armazenamento, por exemplo, um disco rígido, que precisaria mover o braço de leitura até a trilha em que se encontram os dados e esperar até que a rotação do disco traga-os a  cabeça de leitura.

Em sistemas de arquivos distribuídos, pode-se ter caches tanto no cliente como no servidor% (veja figura 2.2)
, evitando assim que o cliente acesse muito a rede para obter os dados do servidor, enquanto que o servidor diminui o acesso ao meio físico de armazenamento dos dados para enviá-los ao cliente.

O uso de cache é uma boa solução para o problema de desempenho no acesso aos arquivos, porém existem problemas como o de sincronização dos dados do cache com os dados do meio físico. Assim, se algum outro cliente alterar os dados no servidor, este precisa avisar a todos os clientes que seus caches podem estar com uma versão antiga dos dados.

Além disso, o tamanho do cache é reduzido, o que gera a necessidade de um algoritmo para saber quais dados devem permanecer no cache e quais podem ser removidos para dar lugar a novos dados. O ideal, segundo \cite{Tan92}, é remover somente os dados que não serão mais acessados. Como não é possível prever isso, foram estudadas várias técnicas e algoritmos para que o resultado final chegue o mais próximo disso. O algoritmo LRU (\textit{Least Recently Used}), segundo \cite{Tan92}, é o que melhor se aproxima do ótimo e, talvez por isso, o mais usado nesse tipo de situação. Assim, sempre que um novo dado é acessado, este é incorporado ao cache. Se o cache estiver cheio, são removidos os dados que foram acessados há mais tempo, para dar lugar aos dados que estão vindo. Porém, se os dados retirados do cache tiverem sido alterados, estes devem ser enviados de volta ao servidor ou ao disco para serem gravados. Naturalmente, conforme o padrão de uso pode ser mais interessante usar outras políticas de substituição.

\subsubsection{Transparências para o Usuário}

Alguns sistemas de arquivos distribuídos (SADs) implementam características que o tornam transparentes para o usuário, que não precisa saber detalhes sobre o sistema de arquivos. Algumas dessas transparências  são \cite{Gal00}:

\begin{itemize}
\item {\bf Nome}: O nome do recurso a ser utilizado (como um arquivo ou diretório) não deve indicar ou conter indícios de onde este está localizado;

\item {\bf Localização}: O usuário não precisa fornecer a localização física do recurso para encontrá-lo;

\item  {\bf Acesso}: O usuário não perceberá se o arquivo que está sendo usado é local ou remoto. Essa é a filosofia usada no sistema de arquivos virtual (VFS) do Solaris e do Linux;

\item {\bf Replicação}: Os arquivos do SAD podem ter cópias armazenadas em locais diferentes. O usuário não deve perceber que existem várias cópias do mesmo arquivo. Para ele só será apresentada uma, e quem a escolherá é o SAD;

\item {\bf Concorrência ou Paralelismo}: Vários usuários podem acessar o mesmo arquivo ao mesmo tempo, mas isso não deve ser perceptível para esses usuários;

\item {\bf Falha}: O SAD deve garantir que o acesso aos arquivos seja ininterrupto e sem falhas, sem que o usuário saiba como isso é tratado.
\end{itemize}


\subsection {Serviços Oferecidos pelos SADs}

Para proporcionar um ambiente simples e fácil de usar, escondendo toda a complexidade por trás dos engenhosos algoritmos e idéias desenvolvidas pelos pesquisadores em sistemas de arquivos, existem vários serviços oferecidos pelos SADs. Muitos deles acabaram se tornando essenciais e são adotados em vários sistemas. Além disso, por ser muito comum encontrá-los, vários possuem uma interface comum independente da implementação, para ajudar o desenvolvedor das  aplicações que irão usar tais SADs.


\subsubsection{Serviço de Nomes Distribuído}

O serviço de nomes se preocupa em indicar a localização de um determinado arquivo, dado o seu nome ou caminho. Se a localização do arquivo estiver armazenada no nome dele, como por exemplo ''jaca:/tmp/teste'', então esse serviço de nomes não provê transparência de localização. Para prover  essa transparência, o nome ou caminho de um arquivo não deve ter indícios de sua localização física.

Caso esse arquivo mude de lugar, ou tenha várias cópias, o seu nome ou caminho não precisará ser alterado para ser encontrado. Para isso, o serviço precisa oferecer ou \textbf{resolução por nomes}, ou \textbf{resolução por localização}, ou ambos.

Resolução por nomes mapeia nomes de arquivos legíveis por humanos para nomes de arquivos
compreensíveis por computadores, que normalmente são números, facilmente manipuláveis pelas  máquinas. Por exemplo, o endereço \url{http://www.example.com} é mapeado para o IP $192.0.34.166$. Através desse conjunto de números é possível encontrar uma máquina na rede Internet, utilizando-se de  tabelas de rotas de endereços mascarados que indicam como chegar a posição desejada.


Resolução por localização mapeia nomes globais para uma determinada localização. Por exemplo, números de telefone possuem código do país, da localidade, etc. Se transparência por nome e por localização estiverem sendo utilizadas simultaneamente, pode ser muito difícil realizar um roteamento para determinar a localização de um determinado nome. Soluções com servidores centralizados ou distribuídos são opções, porém os centralizados podem se tornar um gargalo, enquanto os distribuídos precisam usar alguma técnica de descentralização, como por exemplo cada servidor é responsável por um determinado subconjunto de arquivos, ou cada um resolveria a localização de determinados tipos de arquivos.



\subsubsection{Serviço de Arquivos Distribuído}

O serviço de arquivos é responsável por fornecer operações sobre os arquivos que compõem o sistema, que podem ser armazenados de diferentes formas, dependendo do seu tipo e uso. Por exemplo, arquivos que compõem um banco de dados podem ser armazenados em formato de registros, arquivos que são usados por aplicações multimídia costumam ser armazenados em formato contínuo no disco, para agilizar sua leitura, etc.

Esse serviço também cuida das propriedades dos arquivos, como data de criação, data de alteração, tamanho, dono do arquivo, permissões de leitura, escrita e execução, além de qualquer outra informação relevante. Tais informações são chamadas também de meta-dados.

Também é responsabilidade desse serviço manter a integridade das operações realizadas nos arquivos. Por exemplo, quando uma aplicação altera algum arquivo, todas as demais aplicações que estiverem acessando-o devem perceber essa alteração o mais rápido possível.

Existem dois tipos de implementação de serviço de arquivos: acesso remoto e cópia remota, que podem ser com ou sem estado. No caso do acesso remoto, o cliente não possui um espaço para guardar os arquivos que estiver usando e toda e qualquer operação realizada com os arquivos será sempre através da rede. Isso pode deixar o sistema muito lento, já que depende da velocidade da rede.

Já no caso da cópia remota, o cliente recebe uma cópia do arquivo para trabalhar e, quando tiver terminado, devolve as alterações para o servidor. Isso só funciona se o cliente tiver espaço  suficiente para armazenar o arquivo. A velocidade da rede só influenciará durante as transmissões do arquivo de um local a outro e a implementação só será considerada muito eficiente caso o arquivo seja totalmente alterado. Porém, se o cliente só se interessar por um determinado trecho do arquivo, recursos de transmissão estarão sendo gastos sem necessidade. Daí existe uma variante dessa implementação onde somente os blocos que se quer trabalhar são enviados para o cliente, chamada de cache de bloco.

É possível também que esse serviço lide com replicação de arquivos, que ajuda no acesso concorrente, dando maior velocidade para as aplicações dos clientes, ajudando-o também a deixar os arquivos sempre disponíveis, caso algum servidor fique fora do ar.


\subsubsection{Serviço de Diretórios Distribuído}


Esse serviço é responsável por manter a organização dos arquivos armazenados no sistema. Ele fornece uma interface para que os usuários possam arranjar seus arquivos de forma hierárquica, que é estruturada em diretórios e subdiretórios. Na maioria dos casos, um subdiretório só tem um único pai.

O serviço precisa manter uma lista de todos os diretórios ativos, junto com seus respectivos arquivos. Ele precisa ter a capacidade de identificar e remover arquivos que não estejam em diretório algum, como por exemplo quando um diretório é removido. No caso em que são permitidos múltiplos pais, essa tarefa não é tão fácil, pois os arquivos ou subdiretórios ainda podem estar sendo referenciados por outros diretórios ou recursos. Para resolver esse problema, é colocado um contador de referências para arquivos e diretórios, que se chegar a zero significa que o arquivo ou diretório não possui nenhum outro recurso (como \textit{hard links}, subdiretórios, etc.) apontando para ele, podendo então ser removido. Note que, geralmente, os links simbólicos não influenciam nesse contador. Exemplificando, a figura \ref{fig:diretoriodistribuido} mostra uma estrutura de diretórios distribuída em dois servidores. Se for requisitada a remoção da ligação $A-E$ (um \textit{hard link} ), ou da ligação $B-E$, ou da ligação $C-E$ (um link simbólico), somente a ligação pedida será removida. Porém, somente as duas primeiras alteram o contador do diretório $E$, indicando quantas referências apontam para ele. Assim, se forem removidas as ligações $A-E$ e $B-E$ esse contador chegará a zero e os nós $E$, $F$ e $G$ serão removidos. No caso, o diretório $F$ está em um servidor diferente do diretório raiz a ser removido, mas o serviço de diretórios deve cuidar disto.


\begin{figure}[!htb]
\centering
\insimg{1.3}{imagens/estruturadiretoriodistribuida.png}
\caption{Estrutura de diretórios distribuída}
\label{fig:diretoriodistribuido}
\end{figure}

Algumas das operações sobre diretórios oferecidas pelos serviços de diretórios são criação, remoção, alteração, listagem, alteração de permissões. Além delas, o serviço também influência no gerenciamento de arquivos, como nas operações de criação, remoção, mudança de nome, busca, duplicação, entre outras.



\subsection{Algumas Características Desejadas em SADs}


Qual sistema de arquivos deve-se usar em um sistema distribuído? Para resolver essa dúvida, primeiramente analisa-se qual o tipo de aplicação que será utilizada e, a partir disso, tenta-se descobrir o que é mais importante para ela, como tolerância a falhas, acesso concorrente, ou alguma outra característica. Algumas dessas características (\cite{Gal00}, \cite{Kon94}) são descritas nessa sessão.

\subsubsection{Disponibilidade}


Depender de um serviço da rede que saiu do ar por questões de falta de energia elétrica, manutenção ou falha do hardware é algo inconveniente, ainda mais quando ocorre perda dos dados.

Dessa forma, existem vários estudos para evitar que os serviços deixem de ser oferecidos, seja qual for o motivo.

Se um servidor cair, ficar fora do ar ou da rede, o sistema de arquivos não pode perder informações e nem ficar inacessível total ou parcialmente. Além disso, o usuário não precisa saber como isso foi implementado. Ele simplesmente requisita um arquivo e o sistema de arquivos deve entregá-lo, mesmo que algum dos servidores esteja fora do ar. O arquivo não pode ficar indisponível e isso deve ser totalmente transparente ao usuário. Isso se chama transparência a falhas.

É muito comum sistemas ficarem indisponíveis não por falha do próprio servidor, mas por falha na rede de comunicações. Caso um cliente deseje acessar um arquivo que está em um servidor inacessível naquele momento, o sistema operacional do cliente costuma travar o processo que o pediu até que o servidor volte a ficar acessível.


Uma das soluções para se resolver esse problema é a replicação dos dados, ou seja, o mesmo arquivo, ou parte dele, deve estar em diferentes servidores. Assim, caso algum servidor fique fora da rede, outro fornecerá os mesmos arquivos. Alguns sistemas de arquivos distribuídos foram criados levando esse conceito às ultimas consequências, como é o caso do CODA, detalhado na sessão \ref{coda}.


\subsubsection{Escalabilidade}

Os sistemas distribuídos são, em geral, projetados e configurados pensando-se na configuração da rede naquele momento. Porém essa rede pode aumentar, ou seja, dezenas ou centenas de novos nós podem ser adquiridos e conectados nesse sistema. A menos que se tenha considerado essa situação no momento do projeto da rede, dificilmente um sistema de arquivos distribuído apresentará bom desempenho para servir a todos os clientes após esse crescimento \cite{Kon94}.

Vários problemas podem ocorrer, dentre eles, a inutilização da vantagem de se usar cache quando  o servidor responde a vários pedidos de vários clientes. O servidor mantém os dados enviados em cache, para permitir uma rápida resposta caso esse mesmo dado seja requisitado novamente. No caso de se ter muitos clientes, têm-se muitos pedidos diferentes, fazendo com que as tabelas do cache sejam atualizadas com freqüência, sem a reutilização dos dados lá contidos.

Caso se tenha cache do lado dos clientes, ao se alterar um arquivo que está sendo usado por muitas outras máquinas, o servidor terá que avisá-las que o cache local das mesmas está inválido e todas deverão se atualizar com a versão do servidor, causando sobrecarga.

Por outro lado, caso se tenha estimado que a rede seria muito grande e se tenha distribuído sistema de arquivos em muitos servidores, fica difícil descobrir onde um arquivo está armazenado fisicamente. Por exemplo, se para abrir um arquivo um cliente tiver que perguntar para cada servidor se ele é o responsável por aquele arquivo, certamente haverá um congestionamento na rede. Caso se tente resolver isso colocando um servidor central para resolver todos os caminhos para os arquivos, indicando a localização do mesmo, tal servidor sofrerá sobrecarga.

Um sistema escalável é um sistema que leva em conta esses problemas e tenta evitar sua ocorrência quando o número de clientes aumenta muito. O ANDREW é um sistema de arquivos que conseguiu adotar uma solução satisfatória \cite{Kon} para esses problemas, através da descentralização das informações e da hierarquização da rede. Esse SAD é descrito na sessão \ref{afs}.

\subsubsection{Segurança}


Compartilhar arquivos entre vários ambientes e usuários é uma das vantagens que os sistemas de arquivos distribuídos trazem. Porém, deixar que outras pessoas possam acessar arquivos confidenciais é um grande problema. Dessa forma, torna-se necessário adotar mecanismos de segurança, para evitar que pessoas desautorizadas tenham acesso aos arquivos do sistema.

Sistemas Unix adotam um método baseado em \textbf{permissões} para controlar o acesso aos seus arquivos \cite{Kon94}. Cada arquivo possui informações sobre quais usuários podem acessá-lo e de que maneira.


Nos sistemas distribuídos que executam sob o Unix, quando um servidor recebe um pedido para enviar dados de um determinado arquivo, ele também recebe informações sobre qual usuário está tentando realizar tal acesso. Com isso, verifica se tal usuário tem permissão suficiente para realizar essa solicitação, fazendo uma comparação com as informações de permissões do arquivo.

Outra forma de implementar esse controle de segurança é um sistema baseado em \textbf{capacidades} \cite{Tan92}, que consiste em enviar ao servidor uma prova de que ele possui a capacidade de acessar um determinado arquivo. Na primeira vez que o usuário acessa tal arquivo, é enviado ao servidor sua identificação e o servidor, por sua vez, retorna um código que é a sua prova de capacidade para acessar aquele arquivo. Nas próximas requisições, o cliente não precisa se identificar novamente, bastando apenas enviar a prova de sua capacidade. Deve-se tomar cuidado para não criar provas
de capacidade que sejam fáceis de ser forjadas.

E possível, também, implementar o controle de segurança através de \textbf{listas de controle de acesso} \cite{Tan92}, onde cada elemento da lista possui as permissões que cada usuário tem para acessar determinado arquivo. Isso evita que se crie, por exemplo, uma matriz de arquivos por usuários, onde cada elemento representa o tipo de acesso (o que utilizaria muita memória, dado que muitos desses elementos seriam iguais). O sistema de arquivos distribuído ANDREW utiliza esse mecanismo de listas de controle de acesso.

O controle no acesso aos arquivos é uma das medidas de segurança para protegê-los. Porém, caso haja outras máquinas no caminho de duas máquinas confiáveis, existe o risco de se ter dados interceptados ou, até mesmo, adulterados. Uma forma de se resolver esse problema é criptografar as informações antes de enviá-las.

O sistema de arquivos SWALLOW \cite{Kon94} é um sistema de arquivos distribuído que transmite os arquivos criptografados. Ele funciona em um sistema baseado em capacidades, onde a prova da capacidade é a chave criptográfica. A vantagem é que o servidor não precisa verificar se a prova da capacidade é autêntica: se ela não for, o cliente não conseguirá decodificar os dados.

Meios mais modernos e eficazes para o controle da segurança no acesso e manipulação dos dados armazenados podem ser encontrados em \cite{Gal00}.

\subsubsection{Tolerância a Falhas}

Durante a transmissão dos dados entre servidores e clientes, falhas podem ocorrer, seja por excesso de tráfego de pacotes pela rede, seja por algum dos servidores estar sobrecarregado. Além disso, podem ocorrer falhas de hardware, especialmente dos mecanismos de armazenamento, de transmissão, etc. Esses problemas acontecem em grande parte porque os sistemas distribuídos são implementados sobre redes de computadores que não são totalmente confiáveis.

Dessa forma, um sistema distribuído precisa usar um protocolo de comunicação com capacidade para detecção de erros de transmissão. Assim, caso uma mensagem chegue alterada no seu destino, o protocolo precisa perceber isso e retransmiti-la. Isso deve ocorrer também para mensagens que se perderam no caminho. Um outro problema que a rede pode ter é o seu particionamento por tempo indeterminado.

Além disso, o hardware dentro das máquinas também pode apresentar falhas. Por exemplo, um disco rígido pode deixar de funcionar de um momento para outro. Nesse caso, soluções como redundância física do equipamento (realizada através de hardware) ou redundância controlada pelo próprio sistema distribuído, que cuidaria de replicar os dados, já evitaria a perda das informações armazenadas.

Seja qual for o problema, o sistema deve evitar que o cliente fique aguardando uma resposta por muito tempo, ou que seus dados sejam danificados ou até mesmo perdidos. Isso significa que o  serviço precisa ter \textbf{disponibilidade} e \textbf{confiabilidade}.

Porém, essas características podem ser conflitantes se não forem bem aplicadas. Por exemplo, para garantir a confiabilidade é necessário implementar redundância dos dados, porém a complexidade que isso gera pode aumentar demais a carga do servidor, comprometendo a disponibilidade, pois as respostas aos clientes seriam mais lentas.

Outro mecanismo que auxilia a confiabilidade é a \textbf{transação}. Ela evita que o conteúdo de algum  arquivo fique em um estado inconsistente caso haja uma queda do servidor ou cliente durante a execução de alguma operação sobre o mesmo. Maiores detalhes sobre transações são descritas na próxima sessão.

\subsubsection{Operações Atômicas}

Uma operação em um arquivo é dita \textbf{atômica} quando as etapas da mesma não podem ser percebidas por outros processos exteriores a esta operação \cite{Tan92}. Assim, antes dessa operação o arquivo apresenta um estado e após outro, sem que apresente nenhum outro estado intermediário durante a operação. Caso alguma etapa falhe durante a operação, o arquivo volta ao estado inicial.

Dessa forma, ou todas as etapas são realizadas com sucesso, ou nenhuma será realizada.

Operações de leitura, escrita, criação ou remoção de um arquivo são implementadas de forma atômica pela maioria dos sistemas de arquivos.

\textbf{Transações} são mecanismos que permitem realizar uma seqüência de operações de forma atômica. Tais mecanismos disponibilizam determinados comandos para os usuários para que possam escolher quais operações serão executadas dentro de transações. Para montar uma transação, existem os comandos início e fim. O comando de início avisa ao sistema que todas as operações a partir daquele ponto estarão dentro da transação e o comando de finalização indica que não virá mais nenhuma operação para aquela transação.

Assim, caso alguma dessas operações falhe, o sistema ou desfaz, ou aborta todas as alterações que as operações antes daquela realizaram. Isso é chamado de \textit{rollback} ou \textit{abort}. Caso todas as operações sejam executadas sem problemas ou erros, ao chegar no fim da transação é realizado um \textit{commit}, ou seja, todas as alterações que foram executadas são efetivadas e persistidas, de tal forma que outros processo possam percebê-las.

Com isso as transações implementam a semântica do tudo ou nada, ou seja, ou todas as operações são executadas com sucesso, ou nenhuma será executada. Isso faz das transações um importante mecanismo de tolerância a falhas, pois elas evitam que pequenas falhas prejudiquem a integridade de todo o sistema.

Embora as transações sejam implementadas de forma praticamente obrigatória em sistemas de bancos de dados, elas não costumam ser implementadas em sistemas de arquivos. Os sistemas LOCUS e o QuickSilver \cite{Kon94} são algumas exceções à regra, pois implementam transações em sistemas de arquivos distribuídos.

\subsubsection{Acesso Concorrente}

Vários usuários podem acessar vários arquivos, ou os mesmos arquivos, sem sofrer danos, perda de desempenho ou quaisquer outras restrições. Isso tudo deve ocorrer sem que o usuário precise saber como o acesso é realizado pelos servidores. Assim, é necessário haver transparência de concorrência e de paralelismo.

O maior problema encontrado nas implementações desse tipo de solução é quanto à sincronização dos arquivos, o que inclui leitura e escrita concorrente. A leitura concorrente pode ser implementada facilmente se não houver escrita concorrente, pois quando um arquivo estiver sendo lido, certamente ninguém poderá escrever nele. Caso também se queira escrita concorrente, deve-se levar em conta que quando um cliente escreve em um arquivo, todos os leitores devem ser avisados que o arquivo
foi alterado e todos escritores precisam tomar cuidado para não escrever sobre as alterações que foram feitas por outros. Assim, ou vale a ultima alteração, ou os escritores discutem entre si para tentar fazer uma fusão das alterações.

Para se ter uma idéia da complexidade desse problema, imagine duas operações bancárias simultâneas na mesma conta%(exemplificado na figura 2.4)
. Uma delas é um saque de R\$100,00 e outra é um depósito de R\$1000,00. Antes dessas operações, suponha que essa conta possua R\$100,00 de saldo e também suponha que esse valor esteja armazenado em um arquivo de um sistema de arquivos distribuído. Quando o cliente da conta for realizar o saque, a aplicação irá armazenar em memória o valor atual do saldo, assim como acontecerá com a aplicação do outro caixa que estará recebendo o depósito. Esta aplicação, então, irá adicionar ao saldo o valor do depósito e gravará no arquivo o novo saldo, que será de R\$1100,00. Porém, a primeira aplicação irá subtrair do valor armazenado em memória (que para seu contexto é de R\$100,00) o valor do saque e gravará o resultado (R\$0,00) no mesmo arquivo, sobrescrevendo o valor lá existente. Dessa forma, o cliente perderia seu depósito.


Para evitar esse tipo de problema, as aplicações que operam dessa forma podem agrupar um conjunto de operações no sistema de arquivos como sendo uma única transação, deixando a cargo do sistema operacional gerenciar a melhor forma de executar isso. Existem alguns mecanismos para o controle dessa concorrência, como por exemplo o uso de bloqueios, o controle de otimista e o de controle por data e hora, que são encontrados em (\cite{Tan92}, \cite{Gal00}).

O mecanismo de bloqueios destaca-se por ser amplamente utilizado, e baseia-se no bloqueio do arquivo que se quer acessar antes de acessá-lo, através de uma chamada ao sistema operacional ou  ao sistema de arquivos. Caso um segundo processo queira usar o mesmo arquivo, tentará realizar o bloqueio, usando o mesmo comando que o primeiro processo. O sistema operacional ou o sistema de arquivos o avisará caso esse arquivo esteja bloqueado. Se estiver, cabe ao processo decidir se espera na fila pelo desbloqueio ou se continua seu processamento sem o acesso ao arquivo. Esse
desbloqueio é realizado pelo processo detentor do arquivo, através de um comando, similar ao usado para o bloqueio.


Através desses bloqueios, é tornar as transações serializáveis, isto é, o resultado da operação de várias transações simultâneas é o mesmo obtido se elas fossem realizadas uma após a outra \cite{Kon94}. Um protocolo para a realização dessa serialização é o protocolo de bloqueio de duas fases, onde na primeira fase ocorre o bloqueio de todos os arquivos a serem usados nessa transação e, na segunda fase, a liberação conjunta de todos os arquivos, após a realização das operações dentro dessas fases.

Porém esse protocolo pode gerar um travamento (\textit{deadlock}), onde um processo esperaria a liberação de um arquivo que foi bloqueado por outro processo, que também estaria esperando a liberação de um arquivo que foi bloqueado por aquele primeiro processo, por exemplo. Para evitar travamentos em sistemas distribuídos, existem técnicas e algoritmos que fogem do escopo deste trabalho, devido à complexidade, mas que são descritos em \cite{Gal00}, \cite{Tan92}.

\subsubsection{Replicação de Arquivos}

Em um ambiente distribuído, pode-se também distribuir a carga causada pelo acesso aos arquivos nos vários servidores que compõe o sistema. Pode-se replicar os arquivos em mais de um servidor, ou então replicar somente os arquivos mais acessados, ou ainda replicar somente os pedaços dos arquivos que costumam ter um alto nível de acesso. Note que o uso de cache em um sistema de arquivos pode ser encarado como uma replicação de arquivos, embora seu objetivo seja principalmente desempenho.

Além disso, se um sistema de arquivos oferece essa funcionalidade, a eficiência e a confiança do serviço de arquivos é generosamente aumentada. Eficiência em termos de tempo de resposta, carga do servidor e tráfego de rede. Confiança caso um determinado servidor caia ou fique indisponível, pois o serviço de arquivos ainda pode realizar suas obrigações por possuir cópias dos dados em outro ponto da rede.

% Figura 2.5: Aglomerado de servidores de arqui-
Dessa forma, replicação de arquivos provê tolerância a falhas, já que o usuário pode não perceber que o servidor que ele estava usando caiu e que outro entrou no lugar para prover o recurso que ele estava usando. Daí o sistema também deve oferecer transparência de replicação, pois o usuário não precisa saber como o sistema cuida da replicação desse arquivo.

O maior problema nessa característica do SAD é que a implementação pode ser muito complicada, pois é necessário manter os dados sincronizados e coerentes ao mesmo tempo.

Existem soluções centralizadas e distribuídas \cite{Gal00} para esse tipo de problema.


A centralizada consiste de um único servidor que cuida dos pedidos dos clientes através de \textit{handles}. Com esses \textit{handles}, os clientes acessam diretamente os arquivos através dos servidores  e secundários. Porém, caso o servidor primário caia, nenhum outro cliente conseguirá abrir nenhum outro \textit{handle}, somente os que já estavam abertos continuam acessando os arquivos.

No caso da solução distribuída, existem dois tipos de implementações: a primeira utiliza comunicação em grupo, que consiste em quando ocorrer uma alteração por algum dos servidores, este manda um \textit{broadcast} para os outros servidores dizendo que o arquivo foi alterado. Estes, por sua vez, podem alterar esse arquivo imediatamente ou somente quando forem utilizá-lo; a segunda utiliza votação e números de versão. Isso significa que quando um cliente pedir permissão para alterar um arquivo, os servidores votarão entre eles pra saber quem possui a versão mais recente.

Esse servidor será o servidor padrão daquele arquivo e seu número de versão será incrementado.

Todas essas idéias, além de serem complicadas de implementar, geram alguns problemas. Manter a sincronização entre os servidores, para o caso de alterações no sistema de arquivos, é uma delas.

Tal tarefa não pode interferir no desempenho (por causa da disponibilidade) e nem no uso do sistema pelos usuários (devido à transparência).
\subsubsection{Os Primeiros Sistemas de arquivos Distribuídos}

O primeiro SAD que se tem notícia, segundo \cite{Kon94}, usava a ARPANET, rede construída pelo Departamento de Defesa dos Estados Unidos em 1969 que entrou em funcionamento em 1973. Ele disponibilizava um repositório de dados para computadores que não possuíam capacidade de armazenamento adequada. Era chamado de Datacomputer e usava um serviço parecido com o FTP atual.

Depois dele, veio o \textit{Interim File Server} (IFS), criado por pesquisadores do \textit{Xerox Palo Alto Research Center} (PARC). Ele já organizava os arquivos privados e compartilhados em uma árvore de diretórios. Um sistema subseqüente foi o \textit{Woodstock File Server} (WFS), criado também pelo PARC, que permitia enviar aos clientes somente páginas dos arquivos, ao invés de enviar o arquivo completo, possibilitando trabalhar assim com máquinas sem discos locais.

Em 1977, o PARC criou o \textit{Xerox Distributed File System}, destinado a oferecer uma base para a implementação de sistemas gerenciadores de banco de dados. Ele já implementava transações atômicas envolvendo vários arquivos e servidores, usando um protocolo de duas fases e o acesso a pequenos trechos de arquivos.

Depois dele vieram o LOCUS (1980) que já implementava transparência de localização, replicação e transações atômicas aninhadas; o SWALLOW (início dos anos 80) do MIT, que usava uma técnica de controle de acesso concorrente baseado em \textit{timestamps}; o \textit{Acorn File Server} (início dos anos 80), desenvolvido para implantação de uma rede de microcomputadores em escolas a um custo muito baixo; e o VICE (1984), ancestral do AFS e do CODA.

\subsection{Network File System - NFS}
\textbf{Projeto:Network Filesystem}\\
\textbf{Sítio Oficial:\url{http://nfs.sourceforge.net}}\\
\textbf{Licença:GPL}\\ 
\textbf{Responsável: }\\

\textit{Network File System} \cite{SRO96}, \cite{Kon}, \cite{Kon94}, \cite{ML03}, sistema de arquivos distribuído desenvolvido inicialmente pela Sun, é o SAD mais utilizado em sistemas Unix. Em 1985 a Sun tornou público seu protocolo, o que permitiu que outras empresas e desenvolvedores pudessem criar clientes e servidores compatíveis.

Hoje em dia, já é possível encontrar implementações do NFS (tanto cliente como servidor) para quase todos os sistemas operacionais existentes, inclusive sistemas não-UNIX, como o Windows. Isso também foi facilitado pelo fato do NFS definir uma interface RPC \cite{SM88} que utiliza uma representação de dados independente de máquina chamada \textit{External Data Representation} (XDR).

As versões mais usadas do NFS são as 2 e 3, porém já existe a RFC3530 \cite{SCR03} que descreve o NFSv4. Assim como as versões antigas são incompatíveis entre si, essa nova versão também será. As diferenças e características de cada uma dessas versões, levando em conta funcionamento,desempenho e segurança, estão detalhadas na seção a seguir.

\textbf{Características do NFSv2 e NFSv3}

Os servidores NFSv2 e NFSv3 não guardam o estado das transações realizadas. Isso faz com que não percam nenhuma informação enviada em caso de falha na transmissão ou nos serviços, agilizando sua recuperação. Os clientes também não precisam se preocupar com essa falha, pois basta pedir os dados novamente para o servidor, até que ele responda.

Por outro lado, servidores que não guardam o estado das transações realizadas não conseguem gerenciar \textit{locks} e nem realizar transações atômicas. Existem soluções disponibilizadas à parte para resolver alguns desses problemas, como um servidor de \textit{locks}, chamado de \textit{Network Lock Manager} \cite{NLM98}, para auxiliar as políticas de acesso a arquivos de forma concorrente. Também pelo fato do NFS não manter estado, ele não pode controlar o acesso concorrente aos seus arquivos e nem garantir a sua consistência.

No NFSv3 o mecanismo de cache do servidor foi alterado para possuir tamanho variável (antes era constante) e sua política de escrita foi alterada do \textit{write-on-close} (após se fechar o arquivo, este é gravado em disco) para o \textit{delayed-write} (o arquivo é gravado em disco após ficar algum tempo no cliente sem ser alterado). Assim, caso um arquivo seja usado constantemente e depois apagado, nada será gravado.

Outra vantagem do protocolo NFSv3 em relação ao NFSv2 é o fato de que este ultimo limitava o tráfego de dados de arquivos em blocos de 8KB, enquanto que aquele permitiu enviar dados entre servidor e cliente em blocos de até 56Kbytes via UDP. Além disso, no NFSv2 o servidor só retorna o resultado da gravação desses 8Kbytes após eles estarem gravados fisicamente. Isso consumia muito tempo pois só se gravava em blocos de 8KB. No NFSv3 o disco pode gravar uma quantidade de dados maior simultaneamente, pois o servidor retorna uma resposta do pedido de escrita ao cliente antes de realmente gravar os dados no disco, acumulando-os para escrever de uma só vez.

\textbf{Segurança}

No NFSv2, o cliente era responsável pelo controle de acesso aos arquivos (sem nenhuma validação por parte do servidor). Isso mudou na versão 3, onde o servidor passou a tomar tal decisão, usando o mesmo esquema de segurança dos sistemas de arquivos locais Unix. Quando um cliente faz um pedido, ele envia o uid e o gid do usuário solicitante, e, através de uma consulta às permissões do arquivo local em questão, o servidor decide se libera o acesso ao cliente ou não.

Porém, isso necessita de sincronização de uid e gid entre as máquinas da rede. Para resolver isso foi criado o \textit{Network Information Service} (NIS), um serviço de informações distribuído que é usado para fornecer tais informações a todos os nós da rede.

Percebe-se facilmente a fragilidade disso, dado que se um cliente não for confiável ele pode fornecer uids e gids falsos, podendo, assim, acessar e alterar arquivos de outros usuários. Para resolver esse problema, o NFS possui a possibilidade de autenticação mútua entre cliente e servidor, baseada no método DES de criptografia, onde as chaves são fornecidas pelo NIS. Porém, a informação trafegada não é criptografada, o que possibilita que intrusos possam obter pedaços de arquivos que trafeguem pela rede.

\textbf{O Novo Protocolo NFSv4}

Alguns anos após o lançamento da especificação do protocolo NFSv3, foi criada uma nova versão que revê vários conceitos que não estavam presentes nos protocolos anteriores, que causam mudanças drásticas \cite{ML03} no que se conhecia até então sobre o NFS. Essa nova versão está disponível para o Linux a partir da versão 2.6 do seu kernel.

Nela, o servidor mantém o estado dos arquivos em conjunto com os clientes, diferentemente das versões anteriores. Assim, é possível que um determinado cliente pergunte ao servidor o que outros clientes estão fazendo com determinado arquivo. Isso pode indicar ao cliente se vale a pena ou não realizar um cache dos dados de forma mais agressiva.

É possível também bloquear e compartilhar partes de arquivos através do próprio protocolo NFS, sem a necessidade de servidores externos (como o NLM). O mecanismo para isso é baseado em \textit{leases}, ou seja, um cliente NFS pede ao servidor um contrato de bloqueio temporário (\textit{lease}) e deve manter contato com o mesmo para continuar prolongando esse contrato conforme a necessidade.

Além disso, foi introduzido um esquema de delegação de arquivos, onde o cliente NFS pode acessar e modificar o arquivo dentro do seu cache local sem a necessidade de mandá-lo para servidor, até que o servidor contate o cliente avisando que outro cliente gostaria de acessar o arquivo, quando então este é atualizado no servidor. Isto reduz o tráfego de rede consideravelmente nos casos em que os clientes não desejam acessar um conjunto de arquivos concorrentemente.

Quanto à comunicação entre cliente e servidor, o NFSv4 usa chamadas RPC compostas, ou seja, uma mesma chamada RPC pode conter uma operação complexa envolvendo bloqueio, abertura, leitura, etc. Essas chamadas são realizadas através de conexão TCP, ao contrário das versões mais antigas, que usam UDP.

Em relação à segurança, o NFSv4 possui mecanismos sofisticados, e todas as implementações de clientes obrigatoriamente devem tê-los. Dentre esses mecanismos estão inclusos \textbf{\textit{Kerberos} 5} e \textbf{SPKM3}, juntamente com o tradicional \textit{AUTH SYS} \cite{Eis99}. Além disso, uma nova API foi criada para permitir estender esse mecanismo no futuro.

No NFSv4 a interpretação das listas de controle de acesso (ACLs) foi padronizada tanto para o ambiente Posix quanto para o Windows. Os nomes de usuário e grupo são armazenados em forma de texto e não mais como valores. Além desses, existe a possibilidade de se ter outros atributos, conforme a necessidade. Todos eles são armazenados na codificação UTF-8.

Por fim, todos os protocolos NFS existentes (tais como stat, NLM, mount, ACL e NFS) convergem para uma única especificação, proporcionando uma melhor compatibilidade com os firewalls de rede, além de introduzir no protocolo suporte a migração e replicação de arquivos.

\textbf{Análise Crítica}

O NFSv4 tornou sua manutenção e uso muito mais simples, por possuir, agora, controle de bloqueios encapsulado no mesmo protocolo e não mais através de sistemas de terceiros, além de permitir o controle da consistência dos arquivos que estão nos caches dos seus clientes. O controle da segurança  aos arquivos era muito simplificado e frágil, permitindo que clientes não confiáveis pudessem acessar arquivos de maneira desonesta. Isso foi resolvido na versão 4 do protocolo, onde mecanismos avançados de segurança e autenticação foram incorporados.

Outro problema era o grande consumo de recursos da rede nas operações entre cliente e servidor (devido à interface RPC\slash XDR). Associado à política de cache, o NFSv3 não é muito recomendado para aplicações que necessitam de acesso contínuo aos arquivos. O NFSv4 resolve esse problema pois é possível enviar múltiplos pedidos ao servidor através da mesma chamada RPC, além do uso do cache ter melhorado por conta do controle de estado no acesso aos arquivos.

Uma excelente característica é a transparência que o sistema de arquivos fornece ao usuário final, que nem sequer percebe estar lidando com arquivos remotos. Na versão 4, onde os controles de bloqueios e estado são nativos do protocolo, isso é ainda mais evidente, dando a impressão de que se está usando o sistema de arquivos local.

Além disso, o fato de ter sua especificação aberta para que qualquer um possa implementar seu servidor ou cliente permitiu que ele se tornasse o sistema de arquivos distribuído mais utilizado no mundo.

\subsection{Andrew File System - AFS}
\label{afs}
\textbf{Projeto:Open Andrew Filesystem}\\
\textbf{Sítio Oficial:\url{http://www.openafs.org}}\\
\textbf{Licença: IBM Public License Version 1.0 }\\
\textbf{Responsável: }\\


O projeto ANDREW (\cite{Kon}, \cite{Kon94}) começou na Universidade Carnegie-Mellon em 1983, com apoio da IBM. Seu objetivo era projetar e implementar um sistema distribuído para o ambiente acadêmico de ensino e pesquisa, que ofereceria a cada professor e aluno uma estação de trabalho com um sistema operacional compatível com o UNIX BSD. Além disso, a partir de qualquer um desses computadores, o usuário deveria ter a mesma visão do sistema. Essa transparência de localização deveria ser altamente escalável, podendo aceitar de 5 a 10 mil estações de trabalho nessa rede.

Ao lado da escalabilidade, um outro problema importante que os desenvolvedores iriam enfrentar era a segurança. Com tantos clientes e usuários, era praticamente impossível confiar em todos sem provocar uma fragilidade na segurança de todo o sistema. O ANDREW sofreu modificações gradualmente durante sua existência, que foi dividida em três fases:

\begin{itemize}
\item \textbf{AFS-1}: Durante o ano de 1985, o AFS-1 operou 100 estações de trabalho e 6 servidores. O desempenho do sistema era razoável tendo até 20 clientes conectados por servidor, porém um trabalho pesado que algum deles realizasse poderia degradar o funcionamento do sistema como um todo de forma intolerável. Além disso, a administração do sistema era complicada, dado que os administradores não dispunham de ferramentas adequadas.

\item \textbf{AFS-2}: A partir de toda a experiência adquirida com o AFS-1 e com todos os seus testes de desempenho, foi possível criar uma nova versão muito mais eficiente. Eficiência ganha com o uso de algoritmos
melhores para manutenção da consistência do cache, além de uma melhoria na implementação da resolução de nomes, comunicação e estrutura dos servidores. Funcionou desde o final de 1985 até meados de 1989.

O AFS-2 \cite{Kon} trouxe o conceito de \textit{callback}, que permite ao cliente abrir e fechar um arquivo várias vezes sem precisar acessar o servidor. Quando um cliente recebe um arquivo do servidor, ele também recebe um \textit{callback}, que é uma promessa de que ele está com a versão mais recente do arquivo, que pode ser quebrado ou quando um cliente atualiza um arquivo, ou quando o servidor recebe uma nova versão desse arquivo de um outro cliente. A cópia local pode ser utilizada quantas vezes se desejar, contanto que o cliente possua um \textit{callback} válido.

O problema de escalabilidade foi amenizado ao se passar grande parte do trabalho dos servidores para os clientes: todas as operações de leitura e escrita são realizadas na cópia local do arquivo. Somente quando o arquivo alterado é fechado ele é então transferido de volta para o servidor. Uma consequência desta técnica é que o AFS utiliza semântica de sessão (e não a semântica UNIX de
acesso concorrente a arquivos). Assim, um cliente só perceberá a alteração de um arquivo, feita por um outro cliente, quando ele abrir o arquivo depois que o outro já o tiver fechado.

Como vários usuários passaram a depender do sistema, percebeu-se a importância da disponibilidade dos dados, já que a queda de um servidor provocava interrupção dos trabalhos por vários minutos. Assim, em 1987 iniciou-se o desenvolvimento de um sistema de arquivos de alta disponibilidade, baseado na escalabilidade e segurança do AFS, denominado CODA (mais detalhes na seção \ref{coda}).

\item \textbf{AFS-3}: O AFS-3, ou simplesmente AFS, foi uma iniciativa de tornar o ANDREW um sistema comercial no início de 1990. Para tanto, era necessário adotar alguns padrões, como por exemplo o \textit{Virtual File System} (VFS) da SUN, possibilitando integrá-lo a outros sistemas de arquivos.

Foi implementado o protocolo Kerberos para autenticação mútua entre clientes e servidores, resolvendo assim o problema de segurança no acesso aos dados. A proteção dos arquivos é baseada em listas de controle de acesso, que especificam quais usuários, ou grupos, têm que tipo de acesso sobre eles.

Além disso, a partir dessa implementação os arquivos deixaram de ser cacheados em sua totalidade e passaram a ser transferidos, conforme a necessidade, em blocos de 64 Kbytes, reduzindo assim a latência da abertura e tornando possível o acesso a arquivos grandes que não cabem no disco local.
\end{itemize}

\textbf{Princípios do AFS}

A fim de atingir seus objetivos, foram adotadas algumas regras para o desenvolvimento do
ANDREW e, conseqüentemente, do AFS:
\begin{enumerate}
    \item Sempre que for possível deve-se realizar as operações no cliente e não no servidor, distribuindo, assim, as tarefas entre as máquinas disponíveis, evitando sobrecarregar o servidor;
   \item  Sempre que possível usar o cache para diminuir o tráfego dos dados e a carga dos servidores;
   \item  Explorar os tipos de acesso aos arquivos. Por exemplo, manter arquivos temporários na máquina local, replicar em diversos servidores arquivos executáveis que são muito usados e raramente alterados, etc;
   \item Replicar serviços e informações sempre que possível, evitando limitar a escalabilidade de todo o sistema à capacidade dessa máquina central;
   \item Confiar no menor número possível de entidades (segurança);
   \item Agrupar o trabalho sempre que possível. Por exemplo, realizar uma leitura de 50 KB é muito mais eficiente que realizar 50 leituras de 1 KB.

\end{enumerate}

\textbf{Características do AFS}

O espaço de nomes do AFS é dividido em duas partes: os locais, que consistem dos arquivos cacheados, temporários e daqueles necessários para a inicialização da máquina; os remotos, que são aqueles que podem ser encontrados a partir de qualquer cliente conectado na mesma rede.

Ao contrário do NFS, no AFS toda informação sobre os nomes dos arquivos e diretórios é armazenada nos servidores. Deste modo, a manutenção dos clientes é trivial e a uniformidade do espaço de nomes é uma consequência natural da configuração dos servidores. Quando um cliente precisa acessar um arquivo remoto, ele pergunta a todos os servidores por sua localização, que é então guardada em cache local para futuras consultas.

O acesso concorrente a arquivos pode ser controlado a partir de chamadas UNIX para \textit{flock}, que administra bloqueios ao arquivo, de forma emulada. O responsável por esse bloqueio é o servidor que detém tal arquivo. Caso esse bloqueio dure mais de 30 minutos, o servidor automaticamente o libera, para evitar que a queda de um cliente impossibilite o acesso aos arquivos que ele bloqueou.

Em 1998 havia mais de 100 células AFS por todo o mundo dando a seus usuários a possibilidade de compartilhar seus arquivos através de diferentes continentes usando uma interface de sistema de arquivos parecida com a do UNIX. O AFS começou a ser comercializado pela Transarc Corporation, que foi comprada pela IBM. No momento em que esse texto foi escrito, o AFS estava na versão 3.6, sendo distribuído de forma independente do ANDREW. Para maiores informações visite: \www{http://www-3.ibm.com/software/stormgmt/afs/library/}.

\textbf{Análise Crítica}

O AFS é um sistema de arquivos distribuídos que evoluiu muito desde sua primeira versão.
Pensando-se sempre em escalabilidade, transparência de localização e segurança, ele foi implementado usando conceitos simples, mas que são de extrema importância para se atingir tais objetivos.

Ele oferece um serviço altamente escalável e seguro, através da adoção de semântica de sessão no acesso concorrente a arquivos, na utilização de grandes caches no disco local do cliente e no uso de listas de controle de acesso, juntamente com o protocolo de autenticação mútua Kerberos.

Por causa do cache e da iniciativa de não se compartilhar arquivos temporários, os clientes necessitam obrigatoriamente de disco local. O espaço de nomes é dividido entre local e remoto, sendo que este ultimo é mantido e organizado pelos servidores através de um banco de dados de localização.


\subsection{Constant Data Availability - CODA}
\label{coda}
\textbf{Projeto:CODA Filesystem}\\
\textbf{Sítio Oficial:\url{http://www.coda.cs.cmu.edu/doc/html/index.html}}\\
\textbf{Licença: GPL}\\
\textbf{Responsável: Carnegie Mellon University}\\


% Carnegie Mellon University
O CODA \footnote{\www{http://www.coda.cs.cmu.edu/doc/html/index.html}} (\textit{Constant Data Availability}) (\cite{SRO96}, \cite{Kon}, \cite{AEK96}, \cite{Kon94}) começou a ser desenvolvido em 1987 pela Universidade de Carnegie Mellon, EUA, tendo sua origem a partir do AFS-2.Seu principal objetivo é fornecer operações desconectadas ao sistema de arquivos para computadores portáteis, que costumam ficar grande parte do tempo fora da rede. Isso provê uma máxima disponibilidade dos arquivos aos seus usuários.

Para que isso seja possível, o CODA implementa alguns mecanismos de replicação não presentes no AFS, dado que ele foi criado para lidar com estações de trabalho portáteis ou que permanecem conectadas aos servidores por curtos períodos de tempo.

{\bf Replicação dos Dados.}

Pelo CODA, cada volume (um conjunto de diretórios do sistema de arquivos) é associado a um \textit{volume storage group} (VSG), que consiste de um conjunto de servidores que replicam o volume. O conjunto de servidores acessíveis de um certo grupo em um certo momento é chamado de AVSG (accessible VSG). Essa organização é melhor visualizada na figura \ref{fig:coda}. A coerência entre as várias cópias de um arquivo é mantida por um sistema parecido com o de \textit{callbacks} do AFS.

\begin{figure}[!htb]
\centering
\insimg{1}{imagens/coda.png}
\caption{Volumes, VSGs e AVSGs}
\label{fig:coda}
\end{figure}
%INCLUIR FIGURA
Quando um cliente envia uma atualização de um arquivo para o servidor, a atualização é enviada para todos os servidores AVSG usando um mecanismo denominado \textit{multiRPC}. Além disso, são enviadas mensagens aos clientes quebrando o \textit{callback} que eles possuem para aquele arquivo, invalidando o cache do mesmo.

Se um servidor que estava caído volta à rede, nada é feito inicialmente para atualizar seus arquivos. Porém, sempre que um cliente envia uma requisição para abrir um arquivo para o seu servidor preferido, ele também pede a todos os servidores AVSG que enviem a versão daquele arquivo que eles detêm. Assim, o cliente pode descobrir se existe algum servidor com uma cópia desatualizada, avisando-o para atualizar esse arquivo. Dessa forma, quem toma as iniciativas para atualização dos arquivos que possuem réplicas inconsistentes são os próprios clientes.

Essa replicação aumenta a disponibilidade dos arquivos, o que aumenta a segurança para os clientes encontrarem o que procuram e guardarem os dados que possuem. Por exemplo, se um computador portátil perder todos seus dados, a chance de recuperá-los com a replicação é maior. Além disso, o espaço em disco nos servidores tende a ser maior que nos clientes, facilitando ainda mais o uso dessa característica.

\subsubsection{Controle de Consistência}

O CODA tenta prover ao máximo as operações desconectadas. Para isso, ele permite que os clientes possam ler e escrever seus arquivos de forma indiscriminada, a partir de qualquer servidor da rede que possua os dados que ele precise, mesmo que a rede seja particionada devido à queda de algum servidor ou conexão entre eles. Isso pode gerar perda de informação e acesso a dados inconsistentes quando, por exemplo, dois usuários alteram o mesmo arquivo em partições diferentes.


\subsubsection{Operações Off-Line}

A parte mais interessante do CODA é a possibilidade de acessar um sistema de arquivos distribuído estando completamente desconectado da rede. Se um arquivo está armazenado localmente na máquina, o usuário pode ler e escrever no arquivo sem a prévia permissão do servidor.

Isso só é possível graças a um software chamado venus \footnote{\url{http://www.coda.cs.cmu.edu/doc/html/kernel-venus-protocol.html}}, que é o responsável pelo sistema de arquivos do lado do cliente. Ele possui três estados de funcionamento:
\begin{itemize}
    \item \textbf{Cacheando}: Esse é seu estado normal de funcionamento. Aqui a comunicação com os servidores é possível sempre que necessário, mas o cliente procura estar preparado para o caso de uma desconexão da rede, seja voluntária ou não;

    \item \textbf{Emulação}: Esse estado é atingido quando o cliente perde a conexão com os servidores. Nesse caso, o venus tenta fazer o papel dos servidores, disponibilizando as réplicas dos arquivos gravadas localmente, como se ainda estivessem sendo acessados através dos servidores;

    \item \textbf{Reintegração}: Assim que o computador é conectado à rede, entra-se no modo de reintegração, onde ele passa a fornecer aos servidores responsáveis, os arquivos em seu cache que sofreram alterações. Após o final dessa operação, volta-se ao primeiro estado.
\end{itemize}

\subsubsection{Desempenho}

Alguns testes \cite{SKM93} realizados em situações normais de uso mostraram que o tamanho do cache local necessário para uma semana desconectado e o tempo de reintegração dos dados após esse mesmo período não são muito grandes.

Além disso, concluiu-se que os problemas de acesso concorrente, que poderiam causar conflitos na reintegração, são raros, dado que 99\% das alterações dos arquivos são realizadas pelo mesmo usuário que já o alterou anteriormente.

O desempenho com 4 servidores replicados do CODA foi no máximo 5\% pior que o do AFS, este sem replicação. Porém, o CODA se mostrou menos escalável que o AFS nesses testes \cite{SKM93}.


\subsubsection{Análise Crítica}

O CODA apresenta inovações que auxiliam usuários que necessitam de um sistema de arquivos distribuído de alta disponibilidade. Por exemplo, ele permite que um usuário defina os arquivos que devem estar acessíveis a todo momento, dando assim a facilidade de se conectar à rede por alguns instantes, atualizar seus arquivos e os da rede e voltar a se desconectar, para ir trabalhar em casa como se estivesse conectado.

A replicação dos dados permite aumentar ainda mais essa disponibilidade e a segurança dos dados, já que não só os servidores possuem os arquivos, mas também os clientes. O problema é que isso diminui as garantias de consistência dos arquivos em caso de acesso concorrente.

O CODA não respeita a semântica de sessão (ao contrário do AFS), dado que alterações realizadas por clientes desconectados são aceitas pelo sistema, mas não são informadas a outros usuários. Isso é tolerável, considerando o ganho extra de disponibilidade no sistema de arquivos.


\subsection{Lustre}
\label{lustre}

\textbf{Projeto:} Lustre \\
\textbf{Sítio Oficial:} http://www.lustre.org/\\
\textbf{Licença:} GPL\\
\textbf{Responsável(eis)}: Cluster File Systems, Inc\\


Lustre é um sistema de arquivos distribuídos de código aberto, largamente utilizado em clusters de grande porte. O projeto tenta prover um sistemas de arquivos para um cluster de dezenas de milhares de nós e pentabytes de capacidade de armazenamento, sem comprometer a estabilidade e a segurança.


Cada arquivo armazenado em um sistema de arquivos Lustre é considerado um objeto. Lustre apresenta a todos os clientes uma semântica POSIX padrão e acesso de leitura e escrita concorrente aos objetos compartilhados. Um sistema de arquivos Lustre tem quatro unidades funcionais: um ``Servidor de Meta dados"~ (MDS) para armazenar os  meta dados; um Armazenador de Alvos de Objeto (OST) para armazenar os dados atuais; um Servidor de Objetos Armazenados (OSS) para administrar o OSTs e cliente(s) para acessar e o usar os dados. OSTs são baseados em dispositivos de blocos. Um MDS, OSS, e um OST podem estar no mesmo nó ou em nós diferentes. Lustre não fala diretamente e não administra OSTs, ele apenas delega esta responsabilidade a OSSs para assegurar escalabilidade a grandes clusters  e supercomputadores.


\section{Sistemas de Arquivos Paralelos}
\label{sistemasdearquivosparalelos}
\cutname{sistemasdearquivosparalelos.html}

Sistemas de arquivos paralelos são SADs projetados para proporcionar alto desempenho sob grande demanda e concorrência de acesso. Como essa não é uma tarefa fácil, os projetistas acabam não se preocupando tanto com a transparência no acesso, a segurança ou mesmo a qualidade do serviço. Porém, isso vem mudando.

A seguir, realizamos uma resenha de alguns SADs que têm foco em desempenho, deixando um pouco de lado praticidade ou segurança, sendo muito usados por aplicações paralelas.

\subsection{\textit{Parallel Virtual Filesystem Version 1} - PVFS}

\textbf{Projeto:} Parallel Virtual Filesystem Version 1 \\
\textbf{Sítio Oficial:} http://www.parl.clemson.edu/pvfs/\\
\textbf{Licença:} GPL/LGPL\\
\textbf{Responsável(eis)}: Argonne National Laboratory e Clemson University\\

Atualmente os aglomerados de PCs têm se tornado cada vez mais populares para aplicações paralelas. Com isso, a demanda por software para esse tipo de plataforma tem crescido muito. Hoje em dia encontra-se todo tipo de software para o ambiente de computação paralela, como sistemas operacionais confiáveis, sistemas de armazenamento de dados local e sistemas de envio de mensagens.

O \textit{Parallel Virtual File System} (\cite{CIRT00}, \cite{Had00}) se encaixa na área de sistemas de arquivos paralelo, pois é um sistema de arquivos distribuído desenvolvido para prover alto desempenho e escalabilidade paralela para aglomerados de PCs linux. Em geral, o PVFS promete 4 características:
\begin{itemize}
\item  Um espaço de nomes consistente para todo o aglomerado;
\item  Acesso transparente para programas e aplicações já existentes, sem a necessidade de recompilá-los;
\item  Distribuição física de dados em múltiplos discos e múltiplos nós;
\item Alto desempenho no acesso em modo usuário.
\end{itemize}

Para que um sistema de arquivos paralelo possa ser usado de maneira fácil, ele deve prover um espaço de nomes único em todo o aglomerado e deve ser possível acessá-lo através de utilitários comuns.

Para prover acesso de alto desempenho para os clientes do aglomerado, os dados armazenados no PVFS estão distribuídos entre os vários nós que compõe o aglomerado, assim como o \textbf{BRIDGE} faz, porém usando algoritmos de distribuição diferentes. Cada um desses nós é chamado de \textbf{I/O node.}

Dessa forma, para se obter os dados de um determinado arquivo, é necessário acessar várias máquinas, utilizando-se, assim, de vários caminhos pela rede para chegar aos respectivos discos em que estão armazenados. Isso elimina o gargalo da transferência de dados que se tem quando toda a informação está em uma só máquina, distribuindo a carga e aumentando o potencial total da banda para múltiplos clientes.

Usar mecanismos tradicionais de chamadas de sistema para acesso a arquivos pode ser conveniente, mas pode causar uma sobrecarga muito grande para o sistema como um todo, especialmente o \textit{kernel}. Assim, é possível acessar os arquivos do PVFS usando uma API (\textit{Application Programming Interface}) disponibilizada como biblioteca, que contém operações comuns, além de outras específicas do PVFS, que contactam diretamente os servidores, evitando acessos ao \textit{kernel} local. Essas bibliotecas, como a \textit{ROMIO MPI-IO} \cite{Tha03}, podem ser usadas pelas aplicações ou por outras bibliotecas para acesso de alta velocidade ao PVFS.

\subsubsection{Os componentes do PVFS}


%incluir figura
\textbf{O servidor de meta-dados (MGR} na figura \ref{fig:pvfs}) é um programa que gerencia todos os dados que constituem informações sobre o arquivo (exceto seu conteúdo), como seu nome, sua localização na hierarquia de diretórios, seu dono, seus atributos e como seus dados estão distribuídos entre os vários nós de dados do sistema. Esse programa realiza todas as operações sobre os meta-dados dos arquivos atomicamente, evitando assim ter que implementar esquemas complexos de concorrência, \textit{locks}, consistência, etc, para múltiplos acessos simultâneos.


\begin{figure}[!htb]
\centering
\insimg{1}{imagens/pvfs.png}
\caption{Visão Geral do PVFS}
\label{fig:pvfs}
\end{figure}

\textbf{O servidor de dados (ION} na figura \ref{fig:pvfs}) gerencia o armazenamento do conteúdo dos arquivos, bem como a recuperação dos mesmos, nos discos locais conectados nos nós. Esse servidor grava os dados dos arquivos do PVFS em um sistema de arquivos local, através de chama das a funções tradicionais, como \textit{read}(), \textit{write}() e \textit{mmap}(), para acessá-los.
 
Isso significa que pode-se usar qualquer tipo de sistema de arquivos local, como Ext2, Ext3 ou Reiser \cite{vH03}, por exemplo. Adicionalmente é possível usar suporte a RAID para que cada nó possua tolerância a falhas de disco de forma transparente e confiável para todo o sistema.

Os servidores do PVFS não possuem estado, da mesma forma que o NFS, o que simplifica sua implementação, que não considera casos como quando um cliente se desconecta da rede sem aviso prévio. Isso pode gerar problemas de consistência, pois o servidor pode não conter a versão mais recente do arquivo (caso o cliente possuísse um cache sujo), ou algum arquivo pode ficar bloqueado para escrita.

A \textbf{API nativa do PVFS} possibilita acesso em modo usuário aos servidores do PVFS. Esta biblioteca, chamada de \textit{libpvfs}, cuida das operações necessárias para mover dados entre os clientes e servidores, mantendo-as transparentes para o usuário. Para operações que necessitam de meta-dados, a biblioteca se comunica com o servidor de meta-dados, conforme figura \ref{fig:ricardo001}(a). Para acesso aos dados dos arquivos, o servidor de meta-dados é deixado de lado e os servidores de dados são acessados diretamente, conforme figura \ref{fig:ricardo001}(b). Essa é a chave para se obter um alto desempenho agregado no acesso aos dados.


\begin{figure}[!htb]
\centering
\insimg{1}{imagens/ricardo-001.png}
\caption{Clientes acessando o PVFS}
\label{fig:ricardo001}
\end{figure}


O \textbf{suporte no kernel do linux para o PVFS} provê as funcionalidades necessárias para se usar comando \textit{mount} nos clientes. Isso permite acesso aos arquivos do PVFS sem necessidade de alteração das aplicações ou programas já existentes. Esse suporte não é necessário para se usar o PVFS, mas ele traz uma enorme conveniência para a interatividade com o sistema. Para isso, é necessário instalar um módulo no \textit{kernel} do linux (existe um patch para carregá-lo diretamente no \textit{kernel} ) e um Figura \ref{fig:ricardo002}: Fluxo de dados pelo \textit{kernel} programa chamado (\textit{pvfsd}) que se encarrega de buscar os dados para as aplicações. Ele se utiliza da biblioteca \textit{libpvfs} para realizar essas operações. A figura \ref{fig:ricardo002} mostra como o fluxo de dados passa por esses componentes.


\begin{figure}[!htb]
\centering
\insimg{1}{imagens/ricardo-002.png}
\caption{Fluxo de dados pelo kernel}
\label{fig:ricardo002}
\end{figure}

Além disso, existe a implementação da interface \textit{ROMIO MPI-IO} para o PVFS, possibilitando que aplicações paralelas se utilizem do PVFS sem precisar passar pelo \textit{kernel}, além de poderem usar outras funções específicas desse sistema que possibilitam um ajuste fino no acesso e armazenamento dos arquivos.

\subsubsection{Análise Crítica}

O PVFS é um sistema de arquivos distribuído e paralelo que se preocupa em diminuir o gargalo provocado pelo tráfego de dados, seja pela rede, seja pela velocidade do armazenamento físico, usando a mesma técnica de distribuição de dados encontrada no BRIDGE.

Alguns problemas existentes são quanto à segurança no acesso dos dados, já que se o cliente souber onde os dados estão, basta pedi-los para os nós de dados que eles responderão, sem se preocupar com nenhum tipo de validação de permissão de acesso. Quem cuida da permissão é o servidor de meta-dados, sendo que esse mecanismo não é muito sofisticado. Outro problema existente é quando o servidor de meta-dados fica indisponível. Somente os arquivos já abertos continuarão sendo acessados, até serem fechados. Todos os outros arquivos do sistema não poderão ser acessados. Além disso, o servidor de meta-dados pode representar um gargalo no sistema, já que ele é único.

É um sistema de arquivos paralelo que já apresenta bons resultados, mesmo tendo problemas visíveis. Para aplicações paralelas e confiáveis, em uma rede privativa e fechada, ele pode ser usado sem grandes problemas de segurança

\subsection{\textit{Parallel Virtual Filesystem Version 2} - PVFS2}
\textbf{Projeto:} Parallel Virtual Filesystem Version 2 \\
\textbf{Sítio Oficial:} http://www.pvfs.org\\
\textbf{Licença:} GPL/LGPL\\
\textbf{Responsável(eis)}: Argonne National Laboratory e Clemson University\\


PVFS2 é uma reimplementação das melhores características da primeira versão do PVFS, usando uma nova arquitetura para torná-lo mais flexível. Isso possibilitou a implementação de novas características, técnicas e inovações que foram sendo discutidas e requisitadas durante as correções de defeitos da primeira versão.

As novidades (\cite{RLC02}, \cite{Tea03}) implementadas (ou ainda a serem implementadas) no PVFS2 e sua nova arquitetura estão detalhadas nas próximas seções.% No capítulo 5 há mais detalhes sobre o desempenho do PVFS2.

\subsubsection{Novas características}

 \textbf{Suporte modular para múltiplos protocolos de rede e armazenamento}

        O PVFS1 foi desenvolvido com a idéia de que seus dados seriam acessados via soquete e armazenados em sistemas de arquivos locais. Analisando os aglomerados de computadores existentes hoje, nota-se que existem muitas tecnologias diferentes em cada um deles, sendo que algumas são mais populares que outras. O mesmo ocorre com os sistemas de armazenamento de dados locais. Dessa forma, o PVFS2 foi projetado usando o \textit{\textbf{BMI}} \cite{CRIW05} (\textit{Buffered Messaging Interface}) como interface de acesso à rede e o \textit{\textbf{Trove}} como interface de acesso ao sistema de armazenamento físico. O objetivo é abstrair do projeto os detalhes do mecanismo de transmissões e armazenamento. Isso permite que um desenvolvedor personalize módulos específicos para seu ambiente, sem ter que alterar o núcleo do PVFS2.

 \textbf{Acesso a dados estruturados não-contínuos}

        Muitas aplicações científicas possuem estruturas de dados complexas que nem sempre podem ser armazenadas de forma contínua, pois isto certamente impacta o desempenho da aplicação como um todo.

O Trove é uma interface desenvolvida pela equipe do PVFS2, sendo que até agosto de 2005 não havia um documento público descrevendo-a, a não ser pelo seu próprio código-fonte.

     Assim como o PVFS1, o PVFS2 dá suporte ao \textit{ROMIO MPI-IO}, que permite ao desenvolvedor da aplicação descrever seus dados usando tipos MPI, melhorando o desempenho na leitura dos dados persistidos.

\textbf{Distribuição de dados flexível}

     No PVFS1 os dados são distribuídos entre os servidores de dados usando o algoritmo round-robin, isto é, um arquivo é dividido em blocos de igual tamanho e cada bloco subseqüente é armazenado no próximo servidor, sendo que ao chegar no ultimo servidor volta-se para o primeiro, até que todos os blocos estejam armazenados. Isso é muito eficiente como uma técnica genérica para quando não se conhece o padrão de acesso ao arquivo.
     Porém, em geral sabe-se qual é o padrão de acesso de um arquivo e isso poderia ser usado para otimizar o acesso a ele. O PVFS2 permite que se informe esse padrão de acesso e decide qual a melhor forma de armazenar os dados para máxima eficiência, podendo até mesmo utilizar-se de redundância.

 \textbf{Servidores de meta-dados distribuídos}

     No PVFS1 o servidor de meta-dados (que armazena informações sobre estrutura de diretórios, data de criação de arquivos, etc) é centralizado, podendo representar um gargalo maior conforme o número de clientes aumenta.

     O PVFS2 permite ter mais de um servidor de meta-dados, que pode ou não ser um subconjunto dos servidores de dados.

 \textbf{Suporte explícito à concorrência}

     Um sistema de arquivos paralelo deve ser extremamente eficiente quanto a prover dados para vários clientes simultaneamente.

     O projeto do servidor e cliente PVFS2 foi baseado em uma máquina de estados que está intimamente ligada a um componente de monitoramento da finalização das operações em todos os sistemas envolvidos. Isto é, permite-se que se realize acesso sem bloqueios a todos os tipos de dispositivos. Isso dá suporte a operações assíncronas nativamente, facilitando a implementação do \textit{ROMIO MPI-IO}.

\textbf{Semânticas de consistência ajustáveis}

     Muitos sistemas de arquivos distribuídos implementam as semânticas POSIX, que são muito estritas. O NFS, por exemplo, não implementa essas semânticas, pois não garante que o cache de seus clientes estejam coerentes o tempo todo.

     Por existirem vantagens e desvantagens em cada tipo de semântica, o PVFS2 permite que o usuário opte por uma semântica mais estrita, para permitir a implementação do \textit{ROMIO MPI-IO}, ou mais relaxada, permitindo um uso mais amplo.

\textbf{Mapeamento flexível de referências de arquivos para servidores}

     E possível reconfigurar os servidores de meta-dados para escolher onde armazenar um determinado arquivo. Isso é muito útil na administração do sistema de arquivos, para, por exemplo, remover um servidor ou adicionar outro. Isso também pode ser feito sem a necessidade de se desativar o sistema de arquivos.

\textbf{Redundância de dados e meta-dados}

       O PVFS1 possui um grande problema com relação à tolerância a falhas: caso um servidor saia da rede, perde-se o acesso aos seus dados. Pode-se utilizar um sistema RAID de disco para evitar a perda dos dados, mas isto não garante tolerância à falhas.

       Está sendo estudado para versões futuras do PVFS2 um sistema de redundância relaxada dos dados. A idéia é realizar uma cópia dos dados e meta-dados de um servidor em outro, utilizando-se de uma operação explícita ao cliente. Isto significa que o cliente PVFS2 teria que realizar essa cópia.

       A desvantagem nisso está em realizar operações de forma atômica e em encontrar formas de se evitar uma grande perda de desempenho. A vantagem é que a operação seria otimizada, ao criar as informações redundantes em paralelo.

\subsubsection{Arquitetura do PVFS2}

\textbf{Servidores}

       No PVFS1 cada servidor tem papel distinto: servir meta-dados ou somente dados. Além disso, o servidor de meta-dados é único. No PVFS2, cada servidor pode atuar tanto como servidor de meta-dados como também de dados. A definição do papel que cada um vai representar está no arquivo de configurações, lido durante a inicialização. Além disso, pode-se ter múltiplos servidores de meta-dados.

\textbf{Redes}

       Como já mencionado, utilizando-se o BMI, é possível que o PVFS2 se comunique por TCP/IP, InfiniBand \ref{infinitband} , Myricom \ref{myricom} ou qualquer outro protocolo de rede que venha a ser implementado.

\textbf{Interfaces}

       Os clientes podem acessar o PVFS2 através de duas interfaces: UNIX nativo, representado pelo cliente do sistema operacional, ou \textit{ROMIO MPI-IO}. Ambas as formas seguem o mesmo perfil que foi desenvolvido para o PVFS1.

\textbf{Interações cliente-servidor}

       Durante o primeiro acesso ao PVFS2, os clientes acessam algum dos servidores para obter informações sobre a configuração do sistema de arquivos. Esse processo ocorre de forma similar ao NFS: para abrir um arquivo, o cliente pede ao servidor um \textit{handle}. Tendo um \textit{handle}, o cliente pode acessar qualquer trecho do arquivo, desde que tenha permissão de a acesso. Quando esse \textit{handle} expirar, o servidor avisará o cliente no momento do acesso.

%      \url{http://www.infiniband.org/about/}
%      \url{http://www.myricom.com/}

      Esse tipo de estratégia permite que um processo possa passar seu \textit{handle} a outro processo, que evita uma nova busca pelo arquivo junto ao servidor. Como os clientes e servidores não possuem estado, uma desvantagem é que se um arquivo é removido, o cliente que tiver o \textit{handle} ainda poderá acessá-lo por um tempo, até expirar. Esse tipo de problema também ocorre em sistemas de arquivos locais.

\textbf{Consistências do ponto de vista do cliente}

      O PVFS2 permite que vários clientes realizem escritas simultâneas em regiões não-coincidentes dos arquivos, até mesmo em regiões não-contínuas, de forma atômica. Isso possibilita paralelizar a escrita sem correr o risco de se gerar inconsistências entre servidor e clientes.

      Quanto à consistência do cache, o PVFS2 permite colocar no cache do cliente a estrutura de diretórios do servidor de meta-dados. Isso pode gerar inconsistências temporárias, pois caso haja alguma mudança em tal estrutura, o cliente ficará desatualizado por um certo tempo (configurável).

 \textbf{Consistência do sistema de arquivos}

      Ao realizar alterações na estrutura de diretórios do PVFS2, o sistema de arquivos é bloqueado enquanto essa tarefa é realizada. Foi notado que esse tipo de tarefa não representa um gargalo na maioria das aplicações, mesmo em larga escala. Porém, esses bloqueios não ocorrem em todas as operações. Por exemplo, para criar um arquivo deve-se:
\begin{enumerate}
        \item Criar uma entrada no diretório;
        \item Criar um objeto de meta-dados;
        \item Apontar a entrada no diretório para o objeto de meta-dados;
        \item Criar um conjunto de objetos de dados para o novo arquivo e apontá-los aos objeto de meta-dados.
\end{enumerate}

      Cada uma dessas operações é realizada atomicamente, mas o conjunto delas não. Isso é um problema para o PVFS2, caso a execução dessas tarefas seja interrompida.

\subsubsection{Análise Crítica}

    O PVFS2 realmente evoluiu muito em comparação ao PVFS original. As novas características que estão sendo adotadas permitem que ele seja cada vez mais utilizado, o que ajuda os desenvolvedores a entender a real necessidade que os pesquisadores têm de um sistema de arquivos paralelo para suas aplicações.
    
    A mudança na forma como o código foi implementado facilita sua evolução, atraindo desenvolvedores de plataformas específicas a criar módulos robustos para o PVFS2, que permitem usar esse SAP em cada vez mais aglomerados de computadores. %Conforme nossos testes da versão 1.0.1 (descritos no capítulo 5), muitos dos itens citados nesta resenha não foram implementados, ou ainda estão em testes e portanto não puderam ser analisados, porém a facilidade na instalação e a estabilidade e desempenho alcançados com relação à sua primeira versão mostram que essa área de pesquisa continua em constante evolução.
%Conclusão


%HEVEA\cutend

