U NIVERSIDADE DE L ISBOA Faculdade de Ciências Departamento de Informática SUBSTRATO DE COORDENAÇÃO E SERVIÇO DE DIRECTORIAS PARA SISTEMAS DE FICHEIROS SEGUROS PARA CLOUD-OF-CLOUDS Ricardo Samuel Portinha Mendes DISSERTAÇÃO MESTRADO EM ENGENHARIA INFORMÁTICA Especialização em Arquitectura, Sistemas e Redes de Computadores 2012 U NIVERSIDADE DE L ISBOA Faculdade de Ciências Departamento de Informática SUBSTRATO DE COORDENAÇÃO E SERVIÇO DE DIRECTORIAS PARA SISTEMAS DE FICHEIROS SEGUROS PARA CLOUD-OF-CLOUDS Ricardo Samuel Portinha Mendes DISSERTAÇÃO Dissertação orientada pelo Prof. Doutor Alysson Neves Bessani e co-orientada pelo Prof. Doutor Marcelo Pasin MESTRADO EM ENGENHARIA INFORMÁTICA Especialização em Arquitectura, Sistemas e Redes de Computadores 2012 Agradecimentos Em primeiro lugar quero expressar, não só o meu agradecimento, mas também a minha admiração para com os meus orientadores, o Prof. Alysson Bessani e o Prof. Marcelo Pasin pois, para além da enorme quantidade de conhecimento que tive o privilégio de receber destes, é admirável a relação informal e descontraída que mantiveram durante este ano, proporcionando um ambiente perfeito para o debate de ideias. É de louvar o facto de terem mantido sempre a porta dos seus gabinetes aberta para me receber, a mim e às minhas dúvidas. A eles o meu muito obrigado. Em segundo lugar, quero agradecer também à minha família, nomeadamente aos meus pais e irmãos, por me passarem os valores pelos quais me rejo em todas as minhas decisões. Um agradecimento também à família Gomes pelo apoio e carinho com que me têm brindado nestes últimos anos. Quero agradecer de uma forma muito especial ao Tiago Oliveira, pelas muitas ideias discutidas no processo de desenvolvimento do trabalho apresentado neste documento, e pelo companheiro e amigo que tem sido durante todos estes anos. No meu percurso académico conheci muitas pessoas, algumas delas que, estou certo, ficarão para sempre como bons amigos. Um agradecimento ao Zabibo, Tó Zé, Fernandinho, Reis, Rui Teixeira, Guns e Panka pelos muitos momentos bem passados que me proporcionaram durante estes anos. Ao João Martins, um grande amigo e parceiro de trabalhos durante a licenciatura e início de mestrado, um muito obrigado por tudo. Agradeço também aos meus grandes amigos da minha terra natal. Ao Mário, ao Careca, ao “meu gordinho”, ao Chico, ao Varela, ao Fernando e à minha Cristininha, um muito obrigado pelos muitos momentos épicos que temos passado e pela força em momentos menos bons. Um agradecimento especial ao Diogo que, como um grande amigo que é, me ajudou no tratamento dos resultados apresentados na secção de avaliação deste documento. Por fim, mas de maneira nenhuma menos importante, um muito obrigado à minha namorada Inês que, mesmo com a minha falta de tempo, me congratula sempre com um sorriso e boa disposição. Um muito obrigado pelo apoio incondicional, pelo carinho e pelo suporte. A todos estes e aos demais que de alguma forma possam ter contribuído para o meu sucesso, o meu mais sincero obrigado. iii À minha Inês e à minha Carolina. Resumo O C2FS (Cloud-of-Clouds File System) é um sistema de ficheiros distribuído que fornece aos programadores uma interface POSIX, e que tem por objectivo armazenar os dados numa cloud-of-clouds, utilizando vários provedores de armazenamento nas clouds ao invés de apenas um para aumentar a disponibilidade e privacidade dos dados. Este projecto visa desenvolver dois dos serviços do C2FS: um serviço de directorias distribuído, que ofereça confidencialidade e disponibilidade dos metadados, controlo de acesso aos mesmos por parte de vários utilizadores e fortes garantias de tolerância a faltas; e um serviço de locks para coordenar o acesso aos ficheiros do sistema por parte de vários processos escritores, de forma a garantir a consistência destes ficheiros. Estes componentes do C2FS usam o DepSpace, um serviço de coordenação tolerante a faltas bizantinas que fornece uma abstracção de espaço de tuplos. Para a sua implementação foi necessário alterar a API e arquitectura deste serviço, adicionando uma nova operação que permite a substituição de tuplos e uma camada de suporte a Triggers. Por questões de desempenho foram ainda desenvolvidas duas variações do serviço de directorias: uma que mantém, temporariamente, os metadados utilizados em cache, e outra para a utilização do sistema sem partilha de ficheiros. Para além disso foi desenvolvido um mecanismo, chamado espaço de nomes pessoal, que permite, para além de aumentar o desempenho do serviço de directorias, diminuir a quantidade de informação mantida pelo mesmo. Neste projecto, foi também desenvolvido um mecanismo que permite ao C2FS fornecer garantias de consistência forte mesmo recorrendo a clouds de armazenamento que fornecem apenas consistência eventual. Foi ainda feita uma avaliação experimental que permite perceber, em termos de desempenho, qual é o custo de utilizar um serviço de coordenação para armazenar os metadados do sistema de ficheiros e se esse custo pode ser minimizado através do uso de uma cache de metadados. Palavras-chave: sistema de ficheiros, computação em clouds, armazenamento nas clouds, tolerância a faltas bizantinas. vii Abstract C2FS (Cloud-of-Clouds File System) is a distributed file system that allows developers to take advantage of its POSIX-like interface. It store file system data in a cloud-ofclouds, using several cloud storage providers (instead of only one) to improve the privacy and availability of the data. The goals of this project are to develop two services to C2FS: a distributed and fault tolerant directory service, which maintain the C2FS’s metadata, ensuring its confidentiality, availability, and providing access control to this metadata by various users; and a lock service to coordinate the accesses to files by several writers in order to ensure the consistency of shared files. This service uses DepSpace, a Byzantine fault tolerant coordination service that provides a tuple space abstraction. To implement these services it was necessary to change the API and architecture of DepSpace, adding a new operation to replace tuples and support of triggers. For performance reasons it was developed two directory service variations: one that temporarily maintains the metadata used in cache, and another that allows users to use the system without file sharing. Besides this, it was developed a mechanism, called personal namespace, that decrease the amount of data stored by the service, increasing its performance for accessing non-shared files. In this project was also developed a mechanism that allows C2FS to provide strong consistency guaranties, even if cloud storage providers (used by the system to store its data) provide only eventual consistency guaranties. Finally, it was made an experimental evaluation in order to understand, in terms of performance, what is the cost of use a coordination service to store the file system metadata and if that cost can be minimized through the use of a metadata cache. Keywords: file system, cloud computing, cloud storage, Byzantine fault tolerance. ix Conteúdo Lista de Figuras xv Lista de Tabelas xvii 1 2 Introdução 1.1 Motivação . . . . . . . . 1.2 Objectivos . . . . . . . . 1.3 Contribuições . . . . . . 1.4 Publicações . . . . . . . 1.5 Planeamento . . . . . . . 1.6 Estrutura do Documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Trabalhos Relacionados 2.1 Serviços de Coordenação . . . . . . . . . 2.1.1 Chubby . . . . . . . . . . . . . . 2.1.2 Zookeeper . . . . . . . . . . . . 2.1.3 DepSpace . . . . . . . . . . . . . 2.1.4 Discussão . . . . . . . . . . . . . 2.2 Sistemas de Ficheiros Distribuídos . . . . 2.2.1 Ceph . . . . . . . . . . . . . . . 2.2.2 WheelFS . . . . . . . . . . . . . 2.2.3 Frangipani . . . . . . . . . . . . 2.2.4 Andrew File System . . . . . . . 2.2.5 Coda . . . . . . . . . . . . . . . 2.2.6 Farsite . . . . . . . . . . . . . . . 2.3 Sistemas de Ficheiros para Clouds . . . . 2.3.1 Frugal Cloud File System - FCFS 2.3.2 BlueSky . . . . . . . . . . . . . . 2.3.3 S3FS . . . . . . . . . . . . . . . 2.3.4 S3QL . . . . . . . . . . . . . . . 2.4 Considerações Finais . . . . . . . . . . . xi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 3 3 4 4 5 . . . . . . . . . . . . . . . . . . 7 7 8 9 10 12 12 12 14 15 16 18 20 21 22 23 24 25 26 3 4 5 6 Metadados e Locks no C2FS 3.1 C2FS . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Arquitectura Geral . . . . . . . . . . . . . . . . 3.1.2 Modelo de Sistema . . . . . . . . . . . . . . . . 3.2 Metadados . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 DepSpace . . . . . . . . . . . . . . . . . . . . . 3.2.2 Serviço de Directorias . . . . . . . . . . . . . . 3.2.3 Cache no Serviço de Directorias . . . . . . . . . 3.2.4 Espaço de Nomes Pessoal . . . . . . . . . . . . 3.2.5 Serviço de Directorias sem Partilha de Ficheiros 3.3 Serviço de Locks . . . . . . . . . . . . . . . . . . . . . 3.4 Consistência no C2FS . . . . . . . . . . . . . . . . . . . 3.5 Considerações Finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 27 27 30 31 31 33 36 40 41 42 44 46 . . . . . . 47 47 49 51 51 52 57 . . . . . . 59 59 60 61 65 66 68 Conclusão 6.1 Trabalho futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 70 . . . . . . . . . . . . . . . . . . . . . . . . Concretização dos Serviços de Directorias e de Locks do C2FS 4.1 Considerações Gerais . . . . . . . . . . . . . . . . . . . . . 4.2 Trigger de Substituição de Tuplos no DepSpace . . . . . . . 4.3 Diagramas UML . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Diagrama de Classes . . . . . . . . . . . . . . . . . 4.3.2 Diagramas de Sequência . . . . . . . . . . . . . . . 4.3.3 Considerações Finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Avaliação Experimental 5.1 Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Número de Operações sobre os Metadados . . . . . . . . . . . . 5.3 Desempenho dos Serviços de Directorias e Locks . . . . . . . . 5.4 Desempenho do Serviço de Directorias sem Partilha de Ficheiros 5.5 Desempenho com a utilização do Espaço de Nomes Pessoal . . . 5.6 Considerações Finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A Prova Informal do Serviço de Trincos 71 Bibliografia 78 xii xiv Lista de Figuras 2.1 2.2 2.3 2.4 2.5 2.6 Serviço de coordenação e serviço de comunicação em grupo. Arquitectura do Ceph [54]. . . . . . . . . . . . . . . . . . . Arquitectura do Frangipani. . . . . . . . . . . . . . . . . . . Arquitectura do AFS. . . . . . . . . . . . . . . . . . . . . . Arquitectura do BlueSky. . . . . . . . . . . . . . . . . . . . Arquitectura do S3FS. . . . . . . . . . . . . . . . . . . . . . . . . . . 7 13 15 17 23 25 3.1 3.2 Arquitectura do C2FS. . . . . . . . . . . . . . . . . . . . . . . . . . . . Cloud-of-clouds. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 29 4.1 4.2 4.3 4.4 Diagrama de classes dos serviços de directorias e locks. . . . . . . . . . Diagrama de sequência de uma operação inserção de metadados . . . . Diagrama de sequência de uma operação de obtenção de metadados. . . Diagrama de sequência de uma operação de actualização de metadados. . . . . 53 54 55 56 5.1 5.2 5.3 5.4 5.5 Latência das operações do DepSpace. . . . . . . . . . . . . Latência da obtenção de metadados. . . . . . . . . . . . . . Latência das operações do sistema de ficheiros. . . . . . . . Tempo de execução de benchmarks. . . . . . . . . . . . . . Latências de operações sobre o C2FS e tempos de execução marks usando o serviço de directorias sem partilha. . . . . . Latências de operações sobre o C2FS e tempos de execução marks com ficheiros pessoais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . dos bench. . . . . . . dos bench. . . . . . . 62 63 64 65 5.6 xv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 67 Lista de Tabelas 3.1 Interacção do serviço de directorias com o DepSpace. . . . . . . . . . . . 34 4.1 Número de linhas de código dos módulos desenvolvidos. . . . . . . . . . 49 5.1 Número de operações do sistema de ficheiros chamadas pelos benchmarks. 61 xvii Capítulo 1 Introdução A popularização dos serviços de armazenamento em clouds tem levado alguns utilizadores e empresas a exteriorizar o armazenamento dos seus dados, tirando partido de todas as vantagens que a utilização destes serviços fornece, como por exemplo a facilidade de acesso, o modelo de pagamento consoante o uso e ainda a ausência de investimento inicial. Exemplos deste tipo de serviços são o DropBox [6], GoogleDrive [12], iCloud [5] e o Amazon S3 [4]. A utilização destes serviços levanta, no entanto, problemas no que diz respeito à disponibilidade, integridade e privacidade dos dados. Problemas como a indisponibilidade do provedor usado para armazenar os dados (ou da ligação até ele), o acesso irrestrito por parte do deste aos dados que armazena ou a possibilidade de o mesmo corromper os dados devido a faltas na sua infraestrutura (sejam estas maliciosas ou não), tornam inviável a utilização destes serviços para armazenar dados sensíveis ou críticos. Há ainda um problema relacionado com o preço do serviço prestado pelos provedores. Estes podem aumentar o preço do serviço de tal forma que se torne impossível ao utilizador retirar de lá os seus dados, fenómeno este conhecido por vendor lock-in [21]. Uma outra questão a ser levantada está relacionada com o modelo de acesso a este serviço por parte das aplicações. Nos dias de hoje, o modelo mais comummente usado pelos provedores de armazenamento para permitir às aplicações manusear dados na cloud é a disponibilização de serviços web como o REST, SOAP ou XML-RPC que, embora não obriguem à troca explícita de mensagens, são sobretudo orientados ao controlo ao invés de orientados aos dados. Há ainda uma limitação importante relacionada com as garantias de consistência oferecidas por estes serviços. A maioria dos serviços deste género fornece apenas garantias de consistência eventual [51]. Tal como no caso dos serviços de armazenamento, também a crescente popularidade dos serviços de computação nas clouds tem levado os utilizadores e empresas a migrar as suas aplicações para as clouds. A ausência de investimento inicial e de custos de manutenção com as máquinas, a possibilidade de adequar as características das máquinas utilizadas às necessidades da aplicação que estas correm, assim como o facto de não haver 1 Capítulo 1. Introdução 2 preocupação com upgrades nas máquinas que, com o tempo, vão ficando obsoletas, são bons atractivos para quem deseja correr as suas aplicações de forma eficiente e barata. Exemplos deste tipo de serviços são o Google App Engine [10], Microsoft Windows Azure [13] e o Amazon EC2 [2]. No entanto, para que não tenhamos de confiar na segurança e fiabilidade das infraestruturas dos provedores do serviço de computação, é necessário que haja uma preocupação extra com segurança e tolerância a faltas na construção das aplicações a serem instaladas nestes serviços. 1.1 Motivação A equipa dos Navigators está envolvida num projecto europeu chamado TClouds [17] que tem, entre outros, o objectivo de mitigar todas as limitações descritas na secção anterior. Neste âmbito foi recentemente desenvolvido o DepSky [24], um sistema que prova ser possível reduzir os referidos problemas através do uso de múltiplos provedores independentes, aliado a técnicas de tolerância a faltas e criptografia. Este sistema permite armazenar objectos (blocos opacos de dados associados a uma chave de acesso) numa cloud-of-clouds composta por vários provedores de tal forma que os dados sejam acessíveis e privados mesmo que uma fracção dos provedores estejam sujeitos a faltas bizantinas (exibindo um comportamento arbitrário, fora da sua especificação) [36]. Porém, o DepSky disponibiliza uma interface de baixo nível que se assemelha a um disco virtual, disco este utilizado para armazenar blocos de dados. Embora exista um leque muito grande de aplicações que podem tirar partido da interface ao nível do bloco disponibilizada pelo DepSky, esta interface é de difícil uso tanto por programadores (que constroem aplicações com armazenamento de dados na cloud-ofclouds) quanto por utilizadores, que apenas querem guardar os seus ficheiros na cloud de forma segura e fiável. Dado isto, existe a necessidade de fornecer uma abstracção mais amigável que permita aos utilizadores e suas aplicações armazenar dados na cloud-of-clouds, minimizando alterações nas aplicações e o esforço de aprendizagem por parte dos utilizadores. Uma abstracção que mitiga estas necessidades é a abstracção de sistema de ficheiros, na qual os utilizadores tendem a sentir-se confortáveis. A ideia de armazenar os dados nas clouds já foi concretizada por outros sistemas de ficheiros. Alguns exemplos são o S3FS [18], o S3QL [19], o BlueSky [52] e o FCFS [42]. No entanto, estes sistemas têm a limitação de usar apenas um provedor de armazenamento na cloud, dependendo do mesmo nos vários aspectos referidos anteriormente (fiabilidade, disponibilidade, politicas de acesso, custos, entre outros). Neste âmbito, surgiu o desafio de desenvolver um sistema de ficheiros distribuído tolerante a faltas bizantinas, tanto por parte das infraestruturas que armazenam os dados Capítulo 1. Introdução 3 como das que armazenam os metadados, que permita a partilha de ficheiros controlada, que não exija confiança em nenhuma cloud de armazenamento individualmente e que forneça a garantia de consistência forte. A este sistema de ficheiros foi dado o nome de C2FS (Cloud-of-Clouds File System). 1.2 Objectivos Os objectivos deste trabalho foram desenvolver um serviço de directorias e um serviço de locks para o C2FS, mostrar que estes serviços têm um desempenho aceitável, e ainda desenvolver um mecanismo que permita ao sistema oferecer a garantia de consistência forte mesmo recorrendo a clouds de armazenamento que fornecem apenas consistência eventual. O serviço de directorias é responsável por armazenar os metadados do sistema de ficheiros e por efectuar controlo de acesso aos seus recursos, enquanto que o serviço de locks é responsável por gerir escritas concorrentes sobre o mesmo ficheiro por parte de diferentes utilizadores. Para que se possam cumprir os requisitos do C2FS, ambos os serviços devem ser eficientes, seguros e tolerantes a faltas bizantinas. Desta forma, a abordagem utilizada foi instalar um serviço de coordenação evoluído nas clouds de computação (como a Amazon EC2) e tirar vantagem desse serviço para desenvolver os serviços de armazenamento e de locks. A utilização desta abordagem justifica-se com o facto de os serviços de coordenação evoluídos permitirem implementar várias premissas sobre eles, ao mesmo tempo que fornecem um bom desempenho e boas garantias de tolerância a faltas. Dadas as necessidades dos serviços já descritos, o serviço de coordenação escolhido foi o DepSpace [23], um serviço de coordenação seguro e tolerante a faltas bizantinas que fornece uma abstracção de espaço de tuplos. Assim, um outro objectivo deste trabalho foi o estudo das limitações, estrutura e desempenho deste serviço de coordenação, assim como, caso fosse necessário, a modificação do mesmo de acordo com as necessidades do C2FS. 1.3 Contribuições As principais contribuições desta dissertação são: • A modificação do serviço de coordenação DepSpace de forma a este suportar operações de actualização de tuplos guardados no espaço. • A modificação do DepSpace para que este suporte “Triggers” que executam várias operações de actualização de tuplos de uma forma atómica. Capítulo 1. Introdução 4 • Um serviço de directorias para o C2FS que tem por base o DepSpace. Este serviço herda todas as garantias do DepSpace logo é seguro, fiável e tolerante a faltas bizantinas. Para além de armazenar os metadados do C2FS, o serviço de directorias faz controlo de acesso aos recursos do sistema e permite reduzir o número de operações feitas ao DepSpace (através do uso de uma cache de metadados). • Um serviço de locks fiável, também ele desenvolvido tendo o DepSpace como base, que é usado pelo C2FS para coordenar escritas concorrentes de vários utilizadores sobre o mesmo ficheiro. • A integração destes serviços com outros módulos do C2FS (como o serviço de armazenamento [40]) em desenvolvimento paralelamente a este trabalho. • Um mecanismo que permite ao C2FS fornecer uma semântica de consistência forte, mesmo estando assente sobre clouds que fornecem consistência eventual. • Avaliação experimental dos módulos desenvolvidos com benchmarks utilizados na indústria. 1.4 Publicações O trabalho descrito neste documento contribuiu para a publicação de um artigo científico no INForum 2012, na track “Computação Paralela, Distribuída e de Larga Escala” [38]. 1.5 Planeamento Inicialmente, o planeamento deste trabalho consistia nas seguintes tarefas: • Tarefa 1 (Setembro de 2011): Revisão bibliográfica, estudo do DepSpace e familiarização com as tecnologias envolvidas na computação em clouds. • Tarefa 2 (Outubro e Novembro de 2011): Desenho da abstracção de coordenação e serviço de directorias para um sistema de ficheiros e estudo da sua integração num protótipo. Modificação do DepSpace para que este possa suportar as abstracções desenhadas. • Tarefa 3 (Dezembro de 2011 e Janeiro de 2012): Concretização dos serviços de coordenação e directorias para um sistema de ficheiros para cloud-of-clouds utilizando a nova versão do DepSpace. Integração do trabalho feito com outros mecanismos, como por exemplo o armazenamento. Concretização do primeiro protótipo do sistema de ficheiros para cloud-of-clouds. Capítulo 1. Introdução 5 • Tarefa 4 (Fevereiro de 2012): Instalação dos servidores do DepSpace nas clouds. Concretização do controlo de acesso no serviço de directorias usando a nova versão do DepSpace, modificando-o se necessário. • Tarefa 5 (Março de 2012): Estudo dos modelos de consistência e, caso exista um modelo melhor, modificação do protótipo para integrar esse modelo. • Tarefa 6 (Abril de 2012): Avaliação do sistema recorrendo a benchmarks para sistemas de ficheiros utilizados na indústria. • Tarefa 7 (Maio de 2012): Escrita da tese e de um artigo científico para um workshop ou conferência de médio porte. Este planeamento foi cumprido sensivelmente como descrito, excepto no caso da Tarefa 7. O início desta tarefa foi atrasado devido à necessidade de um esforço extra para a conclusão da tarefa anterior, pois, para atingir melhores resultados nas medições efectuadas, foram incluídas algumas tarefas de optimização do protótipo. Estas tarefas de optimização resultaram numa melhoria de desempenho bastante assinalável. 1.6 Estrutura do Documento Este documento está organizado da seguinte forma: • Capítulo 2 – Este capítulo descreve o trabalho relacionado com os serviços desenvolvidos e com o sistema que irá fazer uso destes. Aqui são apresentados sistemas de ficheiros, serviços de coordenação, sistemas de ficheiros para clouds e um serviço de directorias. Para todos eles são analisadas em especial detalhe todas as características que mais se relacionem com o presente trabalho. • Capítulo 3 – Aqui é apresentado o C2FS, a sua arquitectura e o seu funcionamento, dando a conhecer o contexto no qual os serviços desenvolvidos são inseridos. São também descritos detalhadamente os serviços de directorias e de locks, explicando o seu funcionamento e potencialidades. É ainda explicado o mecanismo que permite ao C2FS fornecer consistência forte. Por fim, é introduzido o conceito de Espaço de Nomes Pessoal, a sua motivação e o seu funcionamento. • Capítulo 4 – Apresentação dos detalhes de concretização do serviço de directorias e de locks. • Capítulo 5 – Este capítulo contém uma avaliação preliminar feita ao serviço de directorias do C2FS. O comportamento deste é avaliado configurando a sua cache de diferentes formas com vista a mostrar as vantagens e desvantagens do uso da mesma. Capítulo 1. Introdução 6 • Capítulo 6 – Neste último capítulo são apresentadas as conclusões retiradas deste trabalho assim como algum trabalho a ser desenvolvido no futuro para melhorar as garantias de consistência oferecidas pelo C2FS. Capítulo 2 Trabalhos Relacionados Nesta secção serão apresentados vários sistemas que de alguma forma relacionam com o trabalho desenvolvido. Serão apresentados em primeiro lugar alguns serviços de coordenação, seguindo-se a apresentação de alguns sistemas de ficheiros distribuídos, um serviço de directorias e ainda dois sistemas de ficheiros para clouds. 2.1 Serviços de Coordenação Os serviços de coordenação são serviços com grande utilidade no âmbito dos sistemas distribuídos pois permitem manter informação de controlo ou de configuração de vários processos num sistema deste tipo. Permitem também fazer sincronização distribuída. Desta forma, estes serviços permitem ao programador de aplicações distribuídas focar-se mais no desenvolvimento da aplicação em si e não tanto no mecanismo de coordenação entre os vários processos da sua aplicação, trazendo ganhos tanto no esforço necessário no desenvolvimento deste tipo de aplicações como na fiabilidade das mesmas. Figura 2.1: Serviço de coordenação e serviço de comunicação em grupo. Na figura 2.1 podemos perceber a diferença existente entre um serviço de coordenação e um serviço de comunicação em grupo. Um serviço de comunicação em grupo, nos moldes do Appia [39], consiste numa abstracção em que cada participante está apto 7 Capítulo 2. Trabalhos Relacionados 8 a enviar mensagens para todos os outros participantes de um grupo. Por outro lado, um serviço de coordenação permite aos seus clientes, através da disponibilização de um objecto com poder de coordenação, a possibilidade de efectuar eleição de líder, partilhar estado, detectar falhas e até trocar mensagens entre vários processos. Nesta secção serão apresentados alguns destes serviços. 2.1.1 Chubby O Chubby [26] é um serviço de locks para sistemas distribuídos fracamente acoplados que tem como objectivo sincronizar as actividades de um grande número de clientes, ao mesmo tempo que fornece boas garantias de disponibilidade e fiabilidade. Este serviço de coordenação foi desenvolvido pelo Google e é utilizado no Google File System [29] para fazer eleição de líder. Este serviço de locks usa uma abstracção de sistema de ficheiros que permite aos clientes guardar pequenas quantidades de informação, ou seja, criar pequenos ficheiros, chamados nós. O uso desta abstracção reduz significativamente o esforço de aprendizagem dos programadores para a utilização deste serviço. Assim, o Chubby provê um conjunto de operações que podem ser chamadas recorrendo a um handle do Chubby. Este handle é criado quando o cliente abre um ficheiro do serviço e destruído aquando do fecho do mesmo. O Chubby apenas permite ao cliente ler e escrever o conteúdo de um ficheiro na íntegra. Esta abordagem tem como objectivo desencorajar a criação de ficheiros grandes. Todos os nós do Chubby podem actuar como um lock, fornecendo este serviço dois tipos de locks: os exclusivos e os partilhados, sendo que os locks exclusivos podem ser usados para reservar recursos para escrita, enquanto que os partilhados para reservar um qualquer recurso para leitura. Os locks são de granularidade elevada (são validos por horas ou mesmo dias). Segundo os autores, esta abordagem explica-se com a dificuldade de tolerar a falha dos servidores sem perder nenhum lock, aliado com a dificuldade de transferir locks entre clientes. A arquitectura do Chubby tem dois componentes principais, a biblioteca cliente e os servidores, que comunicam entre si através de chamadas a procedimentos remotos (RPC). Estes servidores são agrupados em células Chubby, sendo usada replicação entre os servidores da célula para tolerar a falha de uma fracção destes. Cada célula Chubby tem um líder responsável por tratar todos os pedidos que a sua célula recebe. É possível, não só ao cliente perceber quando o servidor Chubby falha, mas também ao servidor detectar a falha de um cliente detentor de um lock. Para isso, uma sessão temporária entre um cliente e uma célula Chubby é mantida através de mensagens KeepAlive periódicas. Quando o líder falha, um novo líder é eleito, através de um protocolo de consenso [35]. Para maximizar o desempenho, o serviço permite que clientes do Chubby guardem Capítulo 2. Trabalhos Relacionados 9 os dados e metadados dos nós numa cache guardada em memória local. Para manter a consistência das caches, as operações de escrita são bloqueadas pelos servidores até todos os clientes serem notificados, e assim, invalidarem as suas caches. Os clientes do Chubby podem também subscrever um conjunto de eventos. Quando isto acontece, o cliente é notificado assincronamente quando a acção correspondente aos eventos subscritos acontece. O controlo de acesso é feito associando uma ACL (access control list) a cada ficheiro. Esta lista mantém a informação de todos os utilizadores do serviço que estão aptos a ler e escrever no ficheiro, assim como quais estão aptos a modificar as permissões do mesmo. Por questões de persistência dos dados, com a frequência de poucas horas, o servidor líder de cada célula faz um backup da base de dados da sua célula para um servidor de ficheiros GFS [29]. 2.1.2 Zookeeper O Zookeeper [32] é um serviço de coordenação que fornece um pequeno conjunto de primitivas simples e gerais para armazenamento e coordenação, permitindo aos clientes criar primitivas de coordenação mais complexas como comunicação e gestão de grupos, registos partilhados e serviços de locks distribuídos. Desta forma, ao invés de implementar primitivas de coordenação específicas, o Zookeeper fornece uma API que manipula objectos de dados wait-free, simples e organizados hierarquicamente, permitindo aos programadores criar as suas próprias primitivas de uma forma eficiente e tolerante a faltas. No entanto, a propriedade wait-free não é suficiente para fornecer coordenação. Devido a isto, este serviço fornece a possibilidade da utilização dos seus recursos com diferentes garantias de ordem, nomeadamente, ordem para todas as operações de um cliente (FIFO) e ainda linearização para todos os pedidos que modifiquem o estado do sistema (usando o protocolo Zab [43]). Este serviço utiliza uma abstracção de espaço de nomes hierárquico “estilo sistema de ficheiros”, onde uma colecção de objectos e dados, chamados znodes, são organizados numa árvore. No entanto, os znodes não foram desenhados para guardar um tipo qualquer de dados, mas sim alguma informação que pode ser útil numa computação distribuída, como por exemplo, metadados ou informações de configuração. Os znodes podem ser de dois tipos: • os regulares, que após a sua criação necessitam ser eliminados explicitamente pelo cliente. • e os efémeros, que são eliminados pelo sistema quando a sessão com o cliente que os criou termina (deliberadamente ou em caso de falha do cliente) ou podem ser apagados pelo cliente explicitamente. Capítulo 2. Trabalhos Relacionados 10 O Zookeeper implementa watches, um mecanismo dirigido a eventos que pode ser subscrito pelos clientes. Este mecanismo permite ao cliente, após subscrição aos eventos de um znode, receber notificações quando esse znode é modificado. Um exemplo da utilidade deste mecanismo é a implementação da primitiva de invalidação de cache. Para aumentar a disponibilidade, o serviço pode ser replicado entre várias máquinas. Uma das réplicas é o líder, sendo esta responsável por coordenar as escritas, ao passo que qualquer uma das réplicas pode responder de imediato a leituras. Periodicamente são criados snapshots do estado do sistema. Estes snapshots são usados para, quando uma máquina recupera após uma falha, recebe o snapshot com o estado do sistema, podendo actualizar os seus dados localmente e, então, começar a atender pedidos dos clientes. Para não ser necessário efectuar um snapshot a cada alteração do estado do sistema, este snapshot é sempre acompanhado de uma lista das operações efectuadas após a criação do snapshot mais actual. Note-se que este serviço assume apenas faltas por paragem e que as réplicas podem recuperar. Para permitir aos servidores perceber quando um cliente falha, este envia mensagens chamadas heartbeats para manter a conexão aberta. Assim, quando o tempo sem receber nenhum heartbeat ou qualquer outra mensagem excede um timeout predefinido, o servidor fecha a conexão, assumindo que o cliente falhou. Os servidores resolvem todas as leituras usando um espaço de nomes hierárquico guardado em memória. Este mecanismo ajuda o sistema a atingir um alto desempenho em ambientes onde as leituras dominam sobre as escritas. Permite ainda que o serviço seja altamente escalável no que diz respeito às leituras pois, visto cada servidor poder resolver localmente qualquer leitura, a cada réplica adicionada ao serviço, a quantidade de leituras suportadas aumenta. No entanto, por uma questão de durabilidade dos dados, todas as escritas são feitas no disco local dos servidores Zookeeper antes de serem escritas na cópia em memória volátil. 2.1.3 DepSpace O DepSpace [23] é um serviço de coordenação tolerante a faltas bizantinas que fornece uma abstracção de espaço de tuplos [20] e que suporta comunicação desacoplada no tempo e no espaço. Um espaço de tuplos é um objecto de memória partilhada que provê operações para manipular dados em estruturas, chamadas tuplos, que guardam um conjunto de campos de tipos genéricos. Existem dois tipos de tuplos: entries, que têm todos os campos com valor definido; e templates, que têm alguns campos não definidos (representados com o wildcard ‘*’). Os templates são importantes porque permitem que os tuplos sejam endereçados pelo seu conteúdo, sem necessariamente saber o valor de todos os campos. Note-se que é ainda suportada a utilização de múltiplos espaços de tuplos. Este serviço exporta um interface para os clientes que lhes permitindo operar sobre o espaço de tuplos. Esta interface aos clientes ler, escrever e remover tuplos do espaço, Capítulo 2. Trabalhos Relacionados 11 através da disponibilização das operações RD, OUT e IN respectivamente. As operações de leitura e remoção de tuplos podem ainda ser executadas de forma assíncrona, através das operações RDP e INP. Existe ainda uma operação chamada CAS (conditional atomic swap) cuja semântica consiste em apenas inserir um determinado tuplo no espaço no caso de não existir ainda nenhum tuplo que corresponda a um template dado. Esta operação é importante pois fornece uma primitiva de coordenação que permite resolver problemas importantes como o consenso. Para isso, basta que cada cliente que tenha um valor para propor tente inserir um tuplo no espaço com o valor da sua proposta utilizando a operação CAS, sendo que o valor escolhido é o valor que permanece no espaço após todos os clientes terem feito a sua proposta. Esta interface e as garantias asseguradas pelo DepSpace são apropriadas para coordenar clientes não confiáveis num sistema distribuído. O DepSpace é constituído por um conjunto de servidores que, através da utilização de vários mecanismos, garante a confidencialidade, disponibilidade e integridade dos tuplos armazenados, mesmo na presença de servidores faltosos. Desta forma, o número de réplicas requeridas pelo DepSpace é de n ≥ 3f + 1, sendo n o número total de réplicas e f o número de réplicas faltosas toleradas pelo serviço. No que diz respeito à disponibilidade, é utilizada replicação para garantir que todos os servidores do DepSpace mantêm o mesmo estado. A estratégia de replicação usada é a replicação de máquina de estados (que garante linearização), juntamente com determinismo das réplicas e com o protocolo de difusão com ordem total baseado no Paxos bizantino [47]. Para garantir confidencialidade, este serviço recorre ao PVSS (publicly verifiable secret sharing scheme) [46] juntamente com primitivas de criptografia para ter a certeza de que apenas partes autorizadas terão acesso a um determinado tuplo em claro. Para além disto, todos os canais usados para comunicação entre os clientes e os servidores do DepSpace são canais fiáveis autenticados ponto-a-ponto, através do uso de TCP juntamente com códigos de autenticação de mensagens. O DepSpace não necessita de nenhuma suposição de tempo mas, devido ao uso de multicast com ordem total e por razões de liveness, uma sincronia eventual é requerida. Não há decisões sobre controlo de acesso aos tuplos neste serviço, pois a melhor opção depende da aplicação. Em vez disto, o DepSpace usa uma camada chamada policy enforcement que fornece a possibilidade de definir políticas de acesso refinadas de acordo com as necessidades da aplicação [25]. Este tipo de política permite ao sistema decidir se uma operação é ou não válida baseando-se, não apenas no identificador do cliente que invoca a operação, mas também, na operação chamada, os seus argumentos e ainda os tuplos actualmente guardados no espaço. Além disso, o serviço possibilita a criação de tuplos temporários: tuplos que permanecem no espaço por um tempo definido e, a menos que este seja revalidado (através da chamada da operação renew), são automaticamente removidos quando expirados. Capítulo 2. Trabalhos Relacionados 2.1.4 12 Discussão Nesta secção foram apresentados os serviços de coordenação estudados. Entre estes serviços, o ZooKeeper destaca-se no que diz respeito ao desempenho. Por outro lado, no que diz respeito à fiabilidade, o serviço estudado que mais se destaca é o DepSpace devido às suas garantias de confidencialidade, integridade e tolerância a faltas bizantinas. Devido a isto, este foi o serviço de coordenação escolhido para servir de base aos serviços de directorias e locks. 2.2 Sistemas de Ficheiros Distribuídos Um sistema de ficheiros tem a função de criar uma estrutura lógica de acesso a dados armazenados numa memória secundária (como sendo um disco magnético, um serviço de armazenamento, ou mesmo as clouds). Estes sistemas organizam os dados em ficheiros que, normalmente, são organizados numa árvore de directorias. A cada ficheiro ou directoria de um sistema de ficheiros estão associados um conjunto de informações chamado metadados. Nos metadados são mantidas, entre outras, informações sobre a localização dos dados de cada ficheiro, o seu caminho na árvore de directorias ou o tamanho dos seus dados. Nesta secção serão apresentados alguns dos sistemas de ficheiros estudados. Todos os sistemas apresentados têm uma natureza distribuída. Um sistema de ficheiros distribuído permite aos utilizadores armazenar os seus dados numa localização remota de forma transparento, podendo estes utilizar este tipo de sistemas da mesma forma que utilizam um sistema de ficheiros local. Estes sistemas de ficheiros utilizam um modelo cliente-servidor. A escolha deste tipo de sistemas de ficheiros para serem descritos nesta secção é justificada com o facto de estes apresentarem mais parecenças com o sistema de ficheiros onde este trabalho foi integrado que os sistemas de ficheiros centralizados. 2.2.1 Ceph O Ceph [54] é um sistema de ficheiros distribuído que fornece um alto nível de escalabilidade, fiabilidade e desempenho através do uso da separação entre a gestão de dados e dos metadados, aliado com o uso de dispositivos de armazenamento de objectos (OSDs). Os OSDs substituem a interface ao nível do bloco de dados por uma interface que permite ao cliente ler e escrever grandes quantidades de dados (muitas vezes de tamanho variável) sobre um objecto com um determinado nome, sem preocupações com replicação, serialização de actualizações, fiabilidade ou tolerância a falhas. Estes componentes fornecem um serviço de locks aos clientes que permite o acesso exclusivo a um determinado OSD. Isto é útil, por exemplo, para esconder latência através da aquisição do lock e Capítulo 2. Trabalhos Relacionados 13 do envio dos dados assincronamente. Na figura 2.2 é apresentada a arquitectura do Ceph. Como podemos ver, o sistema tem três componentes principais: o cliente, que pode ser um sistema de ficheiros montado no espaço do utilizador (recorrendo ao FUSE [8]) ou pode interagir directamente com os outros componentes; o cluster de OSDs, responsável por armazenar todos os dados e metadados; e o cluster de servidores de metadados (MDS) que faz a gestão do espaço de nomes enquanto coordena a segurança, coerência e consistência dos ficheiros do sistema. Figura 2.2: Arquitectura do Ceph [54]. O cluster de servidores de metadados tem uma arquitectura altamente distribuída baseada na partição distribuída de sub-árvores, permitindo distribuir a responsabilidade de gestão hierárquica de directorias do sistema de ficheiros pelos MDSs. Esta abordagem permite ao Ceph aumentar a escalabilidade no acesso aos metadados, e assim, a escalabilidade de todo o sistema. Os clientes do Ceph fazem I/O sobre os ficheiros directamente com os OSDs. Isto é conseguido recorrendo à função CRUSH [53] que, através do identificador do ficheiro (inode), permite ao cliente saber qual OSD responsável por armazenar o ficheiro sobre o qual pretende operar. O inode é único e é obtido pelo cliente quando este chama a operação open no MDS. O controlo de acesso aos ficheiros é também feito pelos MDSs aquando da chamada desta operação. Por questões de eficiência, os MDSs satisfazem a maioria dos pedidos recorrendo à sua cache local, mas as operações de actualização dos metadados têm de ser armazenadas de forma persistente. Para isso, os MDSs usam os OSDs de forma eficiente para armazenar os metadados. Os clientes do Ceph armazenam em cache dados de ficheiros, sendo esta cache invalidada pelo MDS. Os MDSs invalidam a cache dos dados de um ficheiro em todos os clientes quando mais de um cliente abre um ficheiro para escrita. Quando isso acontece, o cliente detentor do lock é forçado a fazer todas as escritas e leituras sobre esse ficheiro de forma síncrona. Capítulo 2. Trabalhos Relacionados 2.2.2 14 WheelFS O WheelFS [48] é um sistema de armazenamento distribuído com uma interface POSIX [16] desenhado para ser usado por aplicações distribuídas com o propósito de partilhar dados e ganhar tolerância a faltas. Foi idealizado para manter quase todos os servidores sempre acessíveis, com falhas ocasionais, não tolerando faltas bizantinas. Em termos de segurança, garante apenas controlo de acesso aos clientes e validação do conjunto de servidores participantes no sistema. Este sistema de armazenamento permite aos clientes ajustar algumas configurações do sistema através do fornecimento de “pistas semânticas”. Estas permitem configurar o comportamento do sistema no que diz respeito ao tratamento de faltas, localização dos ficheiros e das réplicas, política de replicação e garantias de consistência. O facto de estas pistas serem especificadas nos caminhos dos ficheiros permite manter a interface POSIX inalterada, no entanto, pode levantar problemas em algumas aplicações que “partem” o caminho do ficheiro e assumem que a pista é uma directoria. O WheelFS armazena objectos do tipo ficheiro ou directoria, replicando cada objecto por um conjunto de servidores, chamado slice, que utilizam replicação do tipo primary/backup1 para gerir cada objecto. Os metadados são mantidos por um serviço de configuração que é instalado de forma independente num pequeno conjunto de máquinas que usa replicação de máquina de estados e usam Paxos para eleger um líder sempre que necessário. Este serviço mantém uma tabela de slices que guarda, para cada slice, a política de replicação e uma lista de replicação que mantém o identificador dos servidores que estão a armazenar os objectos dessa slice em cada momento. O serviço de configuração exporta um serviço de locks estilo Chubby [26] para ser usado pelos servidores do sistema. Este serviço de locks permite aos servidores executar operações de lock sobre uma determinada slice. Um lock sobre uma slice garante ao seu detentor o direito de ser o líder dessa slice, podendo assim especificar os valores de configuração durante este período. Os locks das slices são válidos por um período limitado de tempo, após o qual, tem de ser renovado. Os clientes guardam a tabela de slices em cache de forma periódica, permitindo-lhes descobrir, dentro de uma slice, quais os servidores que devem contactar para aceder a um determinado objecto. Nesta cache são também guardados dados de ficheiros. No entanto, antes de poderem utilizar os valores guardados em cache, os clientes têm que obter dos servidores um lease sobre o objecto. Os servidores revogam todos os leases sobre um ficheiro a cada actualização para garantir a consistência de todas as caches. O WheelFS fornece consistência ao fechar pois é o padrão esperado por muitas aplicações. 1 O servidor primário recebe as operações, propaga-as pelas réplicas de backup, e só depois responde ao cliente. Capítulo 2. Trabalhos Relacionados 2.2.3 15 Frangipani O Frangipani [50] é um sistema de ficheiros distribuído que fornece várias garantias como escalabilidade, facilidade de administração, consistência dos ficheiros e disponibilidade mesmo na presença de falhas. O Frangipani usa o Petal [37], um sistema de discos virtuais, para armazenar os seus dados e metadados. O Petal consiste numa colecção de servidores que, de uma forma cooperativa, gerem um conjunto de discos físicos. Este exporta uma abstracção de discos virtuais nos quais os clientes podem armazenar dados recorrendo a uma interface ao nível do bloco. Estes discos virtuais estão disponíveis a todos os clientes do sistema e podem ser criados com o tamanho desejado pelo cliente, escondendo a capacidade total dos discos físicos geridos pelo Petal. Este sistema de armazenamento apresenta bons valores de escalabilidade, tanto no número de servidores que tratam os pedidos como na capacidade de dados suportada, através da adição de mais servidores ao sistema. Tem ainda um desempenho comparável ao de um disco local, ao mesmo tempo que permite tolerar e recuperar de falhas em qualquer componente do sistema, fornecer suporte para backup e recuperação, e fazer balanceamento de carga de forma uniforme pelos servidores. Visto o Frangipani usar o Petal como o seu sistema de armazenamento, este herda todas as garantias descritas. Figura 2.3: Arquitectura do Frangipani. Na figura 2.3 é apresentada a arquitectura do Frangipani. Como podemos ver, os clientes acedem ao sistema usando uma interface de chamadas de sistema padrão fornecida por servidores de ficheiros do Frangipani, instalados na mesma máquina que o cliente. Abaixo do servidor de ficheiros do Frangipani existem duas camadas: a driver do dispositivo Petal e um serviço de locks distribuído. Note-se que os servidores do Frangipani Capítulo 2. Trabalhos Relacionados 16 apenas comunicam com estas duas camadas, nunca havendo comunicação entre si. O driver do dispositivo Petal esconde a natureza distribuída do Petal e é usado pelos servidores do Frangipani para aceder aos discos virtuais fornecidos pelos servidores do Petal e, assim, guardarem todos os dados e metadados do sistema de ficheiros. O Frangipani usa o grande e esparso espaço de disco fornecido pelo Petal para criar estruturas que facilitam o armazenamento dos seus dados e metadados. Desta forma, o Frangipani utiliza discos de 264 bytes que são divididos em regiões para armazenar parâmetros partilhados, logs, bitmaps de alocação, inodes e blocos de dados. O serviço de locks distribuído permite ao Frangipani manter a consistência dos ficheiros partilhados e coordenar o acesso concorrente aos mesmos. Este serviço fornece locks do tipo um-escritor/múltiplos-leitores sobre os blocos. Na realidade, uma limitação do Frangipani consiste no facto de, visto o petal exportar uma interface ao nível do bloco, apenas permitir reservar ficheiros inteiros ao invés de blocos de dados. Ao invés disto, uma abordagem mais interessante seria permitir reservar blocos de dados individualmente, sendo possível que diferentes clientes pudessem escrever em blocos de dados diferentes do mesmo ficheiro em simultâneo. Por questões de desempenho, os servidores do Frangipani mantêm uma cache dos dados lidos. Quando estes adquirem o lock para leitura sobre um ficheiro, estão então aptos para guardar em cache os dados lidos. Estes dados em cache são válido enquanto nenhum servidor adquirir um lock de escrita sobre o mesmo ficheiro. Neste caso, visto este acontecimento representar uma possível alteração dos dados do ficheiro, é pedido a todos os servidores com o lock de leitura que libertem o lock e retirem os dados desse ficheiro da sua cache. 2.2.4 Andrew File System O Andrew File System (AFS) [44] é um sistema de ficheiros distribuído cujo desenho é focado na transparência, suporte à heterogeneidade, escalabilidade e segurança. Este sistema de ficheiros foi desenhado nos anos 80 para permitir aos estudantes da Universidade de Carnegie-Mellon partilhar ficheiros entre si. Esta versão do AFS não está apta a suportar grandes bases de dados, sendo apenas adequada para suportar a partilha de ficheiros com poucos megabytes entre relativamente poucos utilizadores (de 5000 a 10000). A figura 2.4 apresenta a arquitectura do AFS. Como podemos observar, este é composto por dois componentes chave: o Vice e a Virtue. O Vice é uma colecção de recursos de comunicação e de computação, compostos por um conjunto de servidores semiautónomos conectados entre si por uma LAN. Este sistema de ficheiros assume que todas as comunicações e computações dentro da Vice são seguros. A Virtue é uma estação de trabalho ligada a um dos servidores do Vice, servidor este responsável por interagir com os restantes servidores. Cada Virtue tem anexada a si uma outra entidade, chamada Venus, que é responsável pela comunicação com o Vice e por gerir a cache local. Dado isto, o sis- Capítulo 2. Trabalhos Relacionados 17 Figura 2.4: Arquitectura do AFS. tema, num todo, é composto por um conjunto de servidores que armazenam os ficheiros do sistema, formando o já referido Vice. A cada um destes servidores podem estar ligadas várias estações de trabalho, cada uma com uma Virtue. A decomposição do Vice num conjunto de servidores existe para tratar o problema de escalabilidade. Assim, para aumentar o número de clientes suportados basta adicionar mais servidores. Por questões de desempenho, cada Virtue deve usar o servidor ao qual se encontra ligada sempre que possível, reduzindo assim o tráfego entre servidores e os atrasos nas bridges que conectam os vários servidores, tudo isto ao mesmo tempo que fornece um bom balanceamento de carga. Devido à natureza não confiável da Virtue, é necessária uma autenticação mutua entre a Virtue e o Vice antes de estabelecer uma conexão. Para isto é usada uma chave de encriptação partilhada entre estes de modo a obter uma chave de sessão. Esta chave de sessão é gerada recorrendo a uma palavra-chave fornecida peço utilizador, e é posteriormente utilizada para cifrar toda a comunicação entre o Vice e uma Virtue durante uma sessão. Existem dois espaços de nomes onde os ficheiros podem ser armazenados: o espaço de nomes local, onde o disco local da estação de trabalho é utilizado; e o espaço de nomes partilhado, que recorre ao Vice para armazenar os ficheiros. No espaço de nomes local são armazenados os ficheiros temporários, os ficheiros privados e os ficheiros usados para inicializar a conexão com o Vice. No espaço de nomes partilhado, visto ser comum a todos os utilizadores, contém todos os ficheiros partilhados por eles. Para fornecer transparência da localização dos ficheiros, o Vice provê um mecanismo para localizar os ficheiros. Todos os servidores mantêm uma base de dados completa que mapeia cada ficheiro para um conjunto de guardiões. Um guardião de um ficheiro é um servidor pertencente ao Vice responsável por armazenar e por tratar todas as operações Capítulo 2. Trabalhos Relacionados 18 feitas sobre esse ficheiro. No AFS são usadas transferências dos ficheiros na íntegra ao invés de transferências de blocos individuais de ficheiros, sendo usado um modelo de consistência ao fechar. Esta abordagem permite, entre outras coisas, reduzir o número de acessos aos guardiões e a sobrecarga da rede. Para atingir melhor desempenho e diminuir o número de acessos feitos aos servidores é utilizada cache do lado do cliente, neste caso a Virtue. Todas as leituras e escritas são feitas na cópia local do ficheiro, sendo este propagado na íntegra para o Vice apenas quando o ficheiro é fechado. Nesta versão do AFS, a validação da consistência da cache é feita quando o ficheiro é aberto (check-on-open). Para garantir que apenas utilizadores autorizados podem aceder a um determinado ficheiro, o AFS fornece um mecanismo de controlo de acesso. Este replica uma base de dados por todos os servidores com a informação de quais utilizadores e grupos podem aceder a cada recurso. Assim, para garantir o acesso a um ficheiro por parte de um determinado utilizador é apenas necessário adicioná-lo à lista de acesso. Para facilitar a revogação de direitos a um determinado utilizador, o AFS usa o conceito de Direitos Negativos nas listas de acesso. Isto permite adicionar à lista de direitos utilizadores que não têm direitos de acesso de uma forma fácil e rápida. O Vice fornece também um mecanismo que provê primitivas de lock do tipo umescritor/múltiplos-leitores. Os locks obtidos através deste mecanismo têm uma natureza consultiva. No entanto, o Vice não requer a reserva de ficheiros antes do seu uso pois este utiliza mecanismos que mantêm a consistência de um ficheiro mesmo este não estando reservado. 2.2.5 Coda O Coda [45] é um sistema de ficheiros distribuído de larga escala para estações de trabalho UNIX. É um descendente do Andrew File System (AFS) [31], mas fornece mais garantias no que diz respeito aos aspectos de tolerância a faltas. Assim, este sistema de ficheiros tem como objectivo manter constante a disponibilidade dos dados, permitindo aos utilizadores continuar a trabalhar sobre os ficheiros mesmo em caso de falha do servidor. Desta forma, o Coda tira vantagem de algumas funcionalidades do AFS que contribuem para a sua segurança, fiabilidade e escalabilidade: • os ficheiros mantidos em cache são transferidos e guardados na integra. O facto de todos os ficheiros serem guardados em cache facilita na tolerância a falhas da rede ao mesmo tempo que fornece mobilidade. • os clientes guardam também em cache alguns metadados, por exemplo, o identificador dos servidores que mantêm os ficheiros guardados. Capítulo 2. Trabalhos Relacionados 19 • é usada autenticação entre clientes e servidores antes de qualquer comunicação, sendo que todas as mensagens trocadas entre estes são cifradas. • é usado um modelo onde poucos servidores seguros e confiáveis são acedidos por vários clientes não-confiáveis. A invalidação da cache usa a mesma estratégia que a versão 2 do AFS [31], onde um mecanismo de callback é usado. Neste mecanismo, o servidor usado pelo cliente para obter um ficheiro, promete enviar-lhe uma notificação (callback) quando esse ficheiro for alterado. Para aumentar a disponibilidade e tolerância a faltas, o Coda usa servidores replicados e permite que os seus clientes façam operações mesmo não estando conectados a estes. No entanto, esta abordagem levanta o problema da possibilidade de existência de conflitos de versões em ficheiros partilhados por vários clientes. Neste caso, o sistema tenta em primeiro lugar, resolver estes conflitos de forma automática e, caso tal não seja possível, este fornece uma ferramenta de reparação que permite aos clientes resolver os conflitos manualmente. A unidade da replicação do Coda é o volume, uma sub-árvore parcial do espaço de nomes partilhado composto por ficheiros e directorias. Quando um volume é criado, é especificada a informação sobre o grau de replicação deste e quais os servidores a serem utilizados para o armazenar. Esta informação é armazenada numa base de dados que é partilhada por todos os servidores. O conjunto de servidores que armazenam um volume é chamado de volume storage group (VSG). Quando um volume é lido, este é guardado numa cache no disco local do cliente. Por cada volume guardado em cache, o gestor da cache do cliente mantém um subconjunto chamado accessible VSG (AVSG) com todos os VSGs acessíveis a cada instante. Note-se que, para um mesmo volume, diferentes clientes podem ter diferentes AVSGs. Para abrir um ficheiro, o cliente verifica se tem uma cópia válida desse ficheiro em cache. Caso isto não se verifique, então o ficheiro é obtido do membro do AVSG com a versão mais recente do ficheiro. Este servidor é chamado de “servidor preferido” e o compromisso da recepção de um callback é estabelecido com ele. Depois de uma modificação, o ficheiro é fechado e é então transferido em paralelo para todos os membros do AVSG. Devido ao facto de o Coda usar uma estratégia optimista, só após a transferência dos dados para os servidores, é feita uma verificação para tentar encontrar conflitos entre versões. Quando um conflito acontece, o Coda tenta, de uma forma automática, resolve-lo. Quando tal não é possível, o Coda marca o ficheiro como inconsistente em todos os servidores que o armazenam, deixando para o utilizador a responsabilidade de resolver o conflito manualmente. O Coda fornece uma ferramenta de reparação de conflitos com uma interface especial que permite operar sobre ficheiros e directorias com inconsistências. Capítulo 2. Trabalhos Relacionados 20 Este sistema de ficheiros garante que todos os clientes são informados com um atraso nunca superior a T segundos quando qualquer um dos seguintes eventos acontece: • A redução do AVSG através da inacessibilidade de um servidor do AVSG. • A extensão de um AVSG, ou seja, quando algum servidor passa de inacessível para acessível. • A perda de um evento callback. Como vimos acima, as operações desconectadas permitem continuar a trabalhar sobre os ficheiros mesmo em caso de a conexão se ter perdido, aumentando, assim, a disponibilidade do sistema. As operações desconectadas começam quando um cliente não tem nenhum membro no AVSG. Este modo é idealmente temporário e o cliente volta ao modo normal assim que possível. A mudança entre estes dois modos é transparente ao cliente excepto no caso de faltar um ficheiro na cache (cache miss) no modo desconectado ou na ocorrência de inconsistências no modo conectado. A ocorrência de eventos de cache miss no modo normal é transparente aos utilizadores, no entanto, estes resultam numa diminuição do desempenho do sistema. Quando estes acontecem no modo de operação desconectado, o sistema bloqueia a computação até que consiga reestabelecer a conexão e assim obter o ficheiro. Devido a isto é importante manter em cache todos os ficheiros sobre os quais o cliente queira operar. Neste contexto, o Coda permite aos utilizadores especificar uma lista de ficheiros (com diferentes níveis de prioridade) que devem ser mantidos em cache. Em resumo, o Coda é um sistema de ficheiros altamente disponível, pois permite operar sobre ficheiros mesmo que não haja conexão com os servidores de forma transparente. Este utiliza uma cache do lado do cliente, não sendo necessária troca de mensagens antes de a utilizar (devido à utilização de callbacks). É utilizada uma abordagem optimista no que diz respeito à existência de ficheiros inconsistentes, sendo fornecidos mecanismos para resolver este problema, tanto de forma automática como manual. O Coda faz armazenamento conjunto dos dados e metadados. 2.2.6 Farsite O Farsite [22] é um sistema de ficheiros distribuído fiável e fácil de administrar que funciona como um servidor de ficheiros centralizado mas que é distribuído fisicamente entre uma rede de máquinas. Este fornece facilidade de administração pois substitui o esforço dos administradores de sistema por processos automáticos. O Farsite protege e preserva os seus dados e metadados recorrendo a técnicas de criptografia e replicação. Para manter a privacidade, integridade e durabilidade dos dados, estes são cifrados e replicados pelos vários servidores do sistema, sendo também mantido um hash dos mesmos Capítulo 2. Trabalhos Relacionados 21 juntamente com os dados e metadados. Por outro lado, os metadados do sistema necessitam ter alguns campos em claro. Assim, estes são mantidos por máquinas de estado replicadas tolerantes a faltas bizantinas, que garante a disponibilidade e integridade dos dados, e é utilizada criptografia para cifrar os nomes dos ficheiros ou directorias do sistema, mantendo estes campos imperceptíveis aos clientes não autorizados. Para impedir clientes maliciosos de criar ficheiros ou directorias com nomes que, após serem decifrados, são sintaticamente ilegais é utilizada uma técnica chamada exclusive encription [27] que garante a decifração de nomes apenas gera nomes legais. Para efectuar controlo de acesso, os metadados do sistema mantêm uma ACL com informações sobre as permissões dos clientes sobre cada ficheiro ou directoria. Em [28] é apresentado um novo serviço de directorias para o Farsite que fornece todas garantias que o anterior serviço fornecia, fornecendo ainda uma melhoria no que diz respeito à escalabilidade. Isto é conseguido particionando os metadados entre vários servidores e utilizando mitigação de pontos críticos (hotspots). Este serviço de directorias divide os metadados pelos vários servidores tendo em conta o identificador do ficheiro (imutável e invisível ao utilizador). Esta abordagem simplifica o problema da alteração do nome de ficheiros pois cada servidor é responsável por um ficheiro (ou conjunto de ficheiros) com um identificador imutável. Para lidar com actualizações aos metadados são utilizados leases. Estes leases podem ser de escrita ou de leitura. Quando um cliente pretende efectuar uma operação sobre os metadados de um ficheiro, este tem de, não só obter uma cópia dos metadados sobre os quais pretende operar, mas também obter um lease sobre os mesmos. Durante o tempo de validade do lease, o cliente pode ler ou alterar os valores dos metadados (dependendo se o lease foi apenas para leitura ou se permite também modificações). No caso dos leases de escrita, o servidor perde a autoridade sobre os metadados enquanto o lease for válido. Nesta nova versão do serviço de directorias do Farsite, os leases dizem respeito, não sobre todos os campos dos metadados de um ficheiro, mas apenas sobre um campo dos mesmos. Esta abordagem permite mitigar pontos críticos. Este serviço de directorias permite ainda, por questões de desempenho, que os clientes guardem em cache quais os servidores que armazenam os metadados de cada ficheiro. 2.3 Sistemas de Ficheiros para Clouds Como já foi referido, hoje em dia muitas empresas têm migrado os seus serviços para as clouds com o objectivo de reduzirem custos no que diz respeito ao investimento em equipamentos e em manutenção dos mesmos. Um dos serviços críticos numa empresa é o seu sistema de ficheiros, utilizado pelos seus colaboradores para manter os seus ficheiros. Visto o trabalho descrito neste relatório ter sido integrado num sistema de ficheiros para clouds, nesta secção serão descritos dois sistemas de ficheiros deste tipo. Capítulo 2. Trabalhos Relacionados 2.3.1 22 Frugal Cloud File System - FCFS O FCFS [42] é um sistema de ficheiros vocacionado a optimizar os custos inerentes à utilização dos serviços de armazenamento das clouds. Este sistema tira partido da utilização de vários destes serviços para reduzir os custos da sua utilização. Os serviços de armazenamento apresentam diferentes preços no que diz respeito ao armazenamento e à transferência dos dados. Os autores do FCFS apresentam como exemplos os custos de transferência e armazenamento do Amazon S3 [4], Amazon EBS [1] e Amazon ElastiCache [3]. O Amazon S3 tem um custo de armazenamento baixo, mas um custo de transferência elevado, enquanto que o Amazon EBS tem um custo de armazenamento relativamente elevado e um custo de transferência relativamente baixo. Por fim, o Amazon ElastiCache tem um custo de armazenamento muito elevado, não havendo custos associados à transferência de dados. É importante notar que o custo de armazenamento nestes serviços reflecte também a o seu desempenho, nomeadamente, a latência. Assim, quanto menor o custo de armazenamento de um serviço, maior o custo de transferência dos dados por si armazenados e maior a latência de acesso aos mesmos. Neste âmbito, este sistema reduz os custos de armazenamento dos dados nas clouds através da transferência dos dados entre os vários serviços de armazenamento de acordo com a carga de trabalho do sistema. A abordagem utilizada consiste em utilizar dois níveis de armazenamento dos dados. No início, todos os dados são armazenados no serviço onde o armazenamento é mais barato (como é o caso do Amazon S3), sendo este nível de armazenamento denominado de disco. Visto as transferências serem muito caras neste serviço, quando há muita carga de trabalho sobre um determinado ficheiro, este é transferido para um serviço onde as transferências sejam mais baratas (como o Amazon EBS), sendo este nível de armazenamento chamado de cache. Desta forma, quando há muitos acessos a um ficheiro, este é trazido para a cache onde, para além de oferecer um maior desempenho, o aumento dos custos inerentes ao seu armazenamento são rentabilizados pelo dinheiro poupado no acesso a ele. No Amazon EBS, os ficheiros são mantidos em volumes de disco. Estes volumes são ajustáveis no que diz respeito ao tamanho, sendo importante mantê-los o mais pequenos possível para minimizar os custos. Quando não é rentável aumentar o tamanho do volume para armazenar mais ficheiros em cache, são usadas políticas de substituição de cache (como o LRU2 ) para seleccionar os ficheiros a substitui-los na cache por outros que sejam mais úteis naquele instante. Este sistema tem a importante limitação de, para poder usufruir de alguns dos serviços de armazenamento na cloud de um provedor, nomeadamente o Amazon EBS e o Amazon ElastiCache, necessita ter acesso a instâncias de computação fornecidas pelo mesmo provedor. Esta necessidade acrescenta custos à utilização deste sistema. Não é apresentado nenhum mecanismo que permita a partilha controlada de ficheiros 2 Substitui o objecto em cache que, no instante da substituição, não é utilizado há mais tempo. Capítulo 2. Trabalhos Relacionados 23 entre vários utilizadores, assim como não é apresentada qualquer informação sobre como são mantidos os metadados do FCFS. Uma outra limitação a ter em conta é o facto não haver nenhuma preocupação com tolerância a faltas do provedor do serviço de armazenamento nas clouds utilizado pelo sistema. 2.3.2 BlueSky O BlueSky [52] é um sistema de ficheiros de rede com armazenamento na cloud, desenhado para servir um conjunto de utilizadores num contexto empresarial. Este sistema tira partido das garantias de disponibilidade e vasta capacidade de armazenamento fornecidas pelos serviços de armazenamento nas clouds. A figura 2.5 apresenta a arquitectura do BlueSky. Como podemos ver na figura, os clientes acedem aos dados armazenados através de um proxy que suporta os protocolos NFS (versão 3) e CIFS, dando aos clientes a ilusão de estarem a comunicar com um servidor de ficheiros tradicional. Este componente está situado entre os clientes e os provedores de armazenamento na cloud. Idealmente, o proxy deve estar instalado na mesma rede que os clientes, de forma a reduzir a latência da comunicação entre eles. Figura 2.5: Arquitectura do BlueSky. Todas as escritas efectuadas sobre ficheiros do BlueSky são tratas localmente pelo proxy. Para isso, ele escreve os novos dados no seu disco local, respondendo ao cliente de seguida. Estes novos dados são enviados periodicamente para a cloud de forma assíncrona. No entanto, esta abordagem pode levar a que, em caso de falha do proxy e do seu disco local, algumas escritas não sejam propagadas para a cloud. Para tratar das leituras localmente, o proxy mantém uma cache que lhe permite tratar alguns pedidos. Quando os dados a serem lidos não estão em cache, estes são obtidos da cloud e armazenados na cache local. Visto o proxy ter uma capacidade de disco limitada, quando o número de ficheiros em cache atinge um limite pré-definido, é utilizada a política LRU para seleccionar o ficheiro a ser substituído. O proxy permite a partilha controlada de ficheiros entre os clientes a si ligados. No entanto, em caso de falha deste componente, todos os clientes deixam de ter acesso aos seus ficheiros. Note-se ainda que, na versão do BlueSky apresentada, é apenas permitida a existência de uma instância deste componente, não podendo os clientes, em caso de falha do proxy, ligar-se a uma outra instância para ter acesso aos seus dados. O BlueSky Capítulo 2. Trabalhos Relacionados 24 tem também a limitação de usar apenas uma cloud para armazenar os dados, dependendo desta em vários aspectos, nomeadamente no que diz respeito à disponibilidade dos dados do sistema. O BlueSky utiliza um esquema de dados estruturado num log, sendo este log armazenado na cloud. Existem quatro tipos de objectos que representam dados e metadados neste log: blocos de dados, inodes, mapas de inomes e checkpoints. Os blocos de dados são utilizados para armazenar os dados dos ficheiros. O BlueSky utiliza blocos fixos de 32 KB. Por sua vez, os inodes são utilizados para armazenar os metadados de cada ficheiro, como por exemplo as permissões de acesso, o identificador do seu dono e uma lista de apontadores para os seus blocos de dados. Os mapas de inodes listam a localização da versão mais recente de cada inode no log, ao passo que cada checkpoint mantém a localização no log dos mapas de inodes em uso. Este último objecto é útil para manter a integridade do sistema mesmo em caso de falha do proxy pois, visto este objecto ser sempre um dos últimos a ser escrito, basta ao proxy localizar este objecto para estar apto a obter os metadados dos ficheiros mais recentes. Por questões de segurança, os objectos armazenados no log são cifrados individualmente (com AES) e protegidos com códigos de autenticação de mensagens (com HMACSHA-256) pelo proxy antes de serem enviados para a cloud, mantendo a integridade e confidencialidade dos dados armazenados. No entanto, é necessário um certo nível de confiança no provedor de armazenamento, pois este está habilitado a eliminar ou corromper os dados, causando a indisponibilidade dos mesmos. Como qualquer sistema de ficheiros estruturado em log, é necessária a existência de um colector de lixo para apagar dados desactualizados. O BlueSky utiliza um colector de lixo que tanto pode estar instalado no proxy como numa cloud de computação fornecida pelo mesmo provedor que armazena os dados. A segunda solução permite que o colector efectue a sua tarefa mais rápido e com menos custos. 2.3.3 S3FS O S3FS é um sistema de ficheiros para sistemas operativos UNIX que utiliza o Amazon S3 [4] para armazenar os dados. Como podemos ver na figura 2.6, este sistema é montado na máquina local (utilizando o FUSE [8]) do cliente que acede directamente à cloud. Este sistema tem a limitação de não permitir a partilha controlada de ficheiros entre diferentes utilizadores, i.e., não controla o acesso aos mesmos por parte de diferentes processos escritores. Tal como os anteriores sistemas de ficheiros para clouds apresentados, também o S3FS tem a limitação de usar apenas um provedor de armazenamento na cloud, não tolerando faltas do mesmo. É possível ao cliente configurar o sistema para utilizar uma cache local, mantida em disco, para aumentar o desempenho deste. É utilizada uma semântica de consistência ao fechar, sendo cada ficheiro obtido da cloud para a cache aquando da sua abertura e escrito Capítulo 2. Trabalhos Relacionados 25 Figura 2.6: Arquitectura do S3FS. no seu fecho. Assim, todas as escritas e leituras efectuadas sobre um determinado ficheiro são feitas localmente. Quando a transferência dos dados de um ficheiro para a cloud não tem sucesso, o sistema volta a tentar duas vezes antes de abortar a transferência e devolver um erro. Note-se que os ficheiros são transferidos na íntegra. A cache dos dados mantida em disco pode crescer de tal forma que ocupe todo o espaço deste, sendo da responsabilidade do cliente seleccionar os ficheiros a remover da cache para libertar espaço. O S3FS mantém também uma cache em memória principal com os metadados dos ficheiros. 2.3.4 S3QL O S3QL é um sistema de ficheiros que armazena os dados na clouds, podendo este ser configurado para utilizar o Google Storage [11], o Amazon S3 [4] ou o OpenStack Cloud Files [14]. Este sistema pode ser montado em sistemas de ficheiros UNIX. Tal como o S3FS, também este sistema é montado na máquina local do cliente que acede directamente à cloud, não permitindo partilha controlada de ficheiros entre utilizadores e dependendo do provedor de armazenamento em vários aspectos, nomeadamente na disponibilidade dos dados. Este sistema utiliza uma base de dados local como cache para armazenar tanto dados como metadados, sendo todas as operações de metadados feitas sobre esta base de dados. Os dados dos ficheiros de sistema são armazenados na cache e na cloud em blocos de pequena dimensão. Esta abordagem permite optimizar o desempenho do sistema e ainda diminuir os custos associados ao envio e obtenção de dados da cloud pois apenas são transferidos os blocos sobre os quais se pretende operar. Todos os envios feitos para a cloud são feitos de forma assíncrona. Para reduzir a quantidade de informação transferida para garantir a confidencialidade dos dados, antes de enviar os dados para a cloud, o sistema comprime os dados (utilizando os mecanismos de compressão LZMA ou bzip2) e cifra os mesmos (utilizando a técnica AES com chave de 256 bits). Para garantir a integridade dos dados, o S3QL mantém localmente um resumo criptográfico de cada bloco armazenado na cloud. Assim, quando obtém os dados, o sistema compara o resumo criptográfico dos dados lidos com o resumo guardado localmente podendo, desta forma, perceber se estes dados foram corrompidos. O S3QL fornece ainda um mecanismo que permite efectuar backup de directorias. Capítulo 2. Trabalhos Relacionados 2.4 26 Considerações Finais Neste capítulo foram apresentados vários sistemas que, de alguma forma, estão relacionados com o trabalho desenvolvido neste projecto. No próximo capítulo será apresentado esse trabalho, sendo em primeiro lugar descrito o contexto no qual este foi integrado, através da apresentação do C2FS como um todo, sendo em seguida dada ênfase à descrição detalhada do substrato de coordenação (concretizado num serviço de locks) e do serviço de directorias. Capítulo 3 Metadados e Locks no C2FS Neste capítulo são apresentados o mecanismo utilizado para gerir os metadados no C2FS, assim como é garantida a consistência dos seus ficheiros. Em primeiro lugar é apresentado o C2FS como um todo para fornecer o contexto do ambiente no qual o trabalho desenvolvido foi integrado. Em seguida são apresentadas várias versões do serviço de directorias utilizado para armazenar os dados, assim como o serviço de locks desenvolvido. Para o desenvolvimento destes serviços, foi necessário adicionar algumas funcionalidades novas ao DepSpace [23], sendo estas também explicadas em detalhe neste capítulo. 3.1 C2FS O C2FS é um sistema de ficheiros com interface POSIX [16] que armazena os dados numa cloud-of-clouds, recorrendo ao DepSky [24]. Este sistema garante a privacidade, integridade e disponibilidade dos dados, admitindo que uma fracção dos provedores de armazenamento utilizados falhe de forma Bizantina. Os metadados são armazenados recorrendo ao um serviço de coordenação também tolerante a faltas bizantinas [23], que garante que os metadados são armazenados de forma segura. 3.1.1 Arquitectura Geral A figura 3.1 apresenta a arquitectura do C2FS e a estrutura dos seus serviços. Como se pode observar, na base da arquitectura temos o módulo FUSE [8]. Este módulo é responsável por interceptar as chamadas ao sistema operativo referentes a recursos do C2FS. Estas chamadas são entregues ao agente C2FS. Neste sistema é usada uma concretização do FUSE em Java, chamada FUSE-J [9]. O agente C2FS é responsável por interagir com os serviços de armazenamento, locks e directorias de acordo com a chamada recebida do módulo FUSE. Uma das tarefas deste trabalho era a integração dos serviços de directorias e de locks com o serviço de armazenamento. Esta tarefa foi concretizada neste componente. 27 Capítulo 3. Metadados e Locks no C2FS 28 Figura 3.1: Arquitectura do C2FS. O serviço de armazenamento do C2FS [40] permite, recorrendo ao DepSky [24], guardar os dados do sistema na cloud-of-clouds assegurando-se da integridade, disponibilidade e confidencialidade dos mesmos. Por uma questão de desempenho, este serviço mantém em cache os dados dos ficheiros do C2FS. Esta abordagem permite que, excepto nos casos em que os dados não estão em cache ou em que um outro cliente escreve uma versão mais recente dos dados em cache, todas as leituras sejam feitas localmente. Fornece ainda dois níveis de cache (memória principal e disco) com diferentes desempenhos e garantiras de consistência. Para verificar se os dados mantidos em cache são ou não a versão mais recente, o agente C2FS fornece a este serviço o resumo criptográfico da versão mais recente dos dados, resumo este que é comparado com o resumo criptográfico dos dados em cache. Este serviço é configurável, permitindo ao cliente do serviço (neste caso o agente C2FS) definir qual o nível de cache que pretende utilizar, assim como se as escritas para as clouds são síncronas (o sistema bloqueia até que a operação esteja completa) ou assíncronas (escrita para as clouds é feita em background), podendo o cliente adaptar o funcionamento do serviço às suas necessidades em termos de desempenho e de consistência dos dados nas clouds. O serviço de armazenamento é responsável também por cifrar os dados antes de os enviar para a cloud-of-clouds. Este processo é feito recorrendo a uma chave fornecida pelo agente C2FS quando este efectua uma escritas. Aquando de uma leitura de dados, o serviço de armazenamento é também responsável por decifrar os dados usando, mais uma vez, uma chave fornecida pelo agente C2FS. Como veremos na secção 3.2.2, esta chave é armazenada no serviço de directorias. O serviço de locks permite manter a consistência dos ficheiros do C2FS, garantindo que, em cada instante, existe no máximo um utilizador a escrever num contentor de dados. Capítulo 3. Metadados e Locks no C2FS 29 O serviço de directorias utiliza o DepSpace [23]1 para armazenar os metadados e efectuar o controlo de acesso aos ficheiros do C2FS. Como podemos verificar na figura 3.1, este serviço mantém uma cache de metadados que permite diminuir o número de chamadas ao DepSpace, diminuindo os custos inerentes à utilização do sistema e aumentar o desempenho do sistema. Estes dois serviços vão ser descritos em maior detalhe nas secções 3.2.2 e 3.3. Tanto o serviço de armazenamento como o serviço de directorias mantêm uma fila de tarefas que correm em background. Estas tarefas permitem propagar alterações de dados e metadados de forma assíncrona no sistema, representando um incremento do desempenho do mesmo. Figura 3.2: Cloud-of-clouds. Na figura 3.2 é apresentada uma visão geral do C2FS, onde um conjunto de utilizadores acede a ficheiros cujos dados e metadados estão armazenados em diferentes provedores de armazenamento e computação nas clouds. Exemplos de serviços deste género são o Amazon S3 [4] e o Amazon EC2 [2], respectivamente. Como podemos perceber, foi decidido separar os dados dos metadados. Outros sistemas de ficheiros [54, 48] optaram também por esta abordagem. As razões que levaram à utilização de um serviço de coordenação instalado nas clouds de computação para o armazenamento dos metadados ao invés de os armazenar nas clouds de armazenamento são essencialmente as seguintes: • Um serviço de coordenação fornece primitivas eficientes para a implementação de um serviço de locks. • O desempenho é superior para operações com pouca transferência de dados (como é o caso do acesso aos metadados), conforme será mostrado na secção 5. 1 Assume-se implicitamente que as réplicas do DepSpace vão estar a correr em diferentes provedores de computação em cloud, fazendo também uso do paradigma cloud-of-clouds. Capítulo 3. Metadados e Locks no C2FS 30 • Ter um serviço de metadados consistente permite ter um sistema de ficheiros consistente. Esta afirmação será explicada em pormenor no capítulo 3.4. O serviço de coordenação utilizado, como já foi referido anteriormente, é o DepSpace [23]. Esta escolha deve-se ao facto de este ser o serviço de coordenação disponível que mais garantias de segurança e fiabilidade oferece entre os serviços estudados (ver secção 2.1). 3.1.2 Modelo de Sistema O sistema suporta um conjunto ilimitado de clientes que correm os serviços de armazenamento, directorias e locks. Assume-se que cada um destes clientes tem um identificador único (clientId). Os serviços de directorias e locks recorrem ao DepSpace [23] para exercer a sua função. Toda a comunicação entre estes serviços e o DepSpace é feita utilizando canais fiáveis autenticados ponto-a-ponto através do uso de sockets TCP, códigos de autenticação de mensagens (MAC) e de chaves de sessão. É também assumido que a rede pode descartar, corromper ou atrasar mensagens, mas não pode interromper indefinidamente a comunicação entre processos correctos. Não é necessária nenhuma garantia de tempo explícita, sendo no entanto, por uma questão de liveness, necessário um modelo de sistema eventualmente síncrono. Esta necessidade deve-se ao uso da primitiva de difusão com ordem total, baseada no protocolo de consenso bizantino Paxos, para garantir que todos os servidores do DepSpace executam as mesmas operações pela mesma ordem [47]. O serviço de armazenamento, por sua vez, recorre ao DepSky [24] para armazenar os seus dados na cloud-of-clouds. Cada cloud utilizada para armazenar dados representa um servidor passivo (não executando nenhum código específico para o protocolo) com uma semântica de consistência regular, ou seja, para operações de leitura que ocorrem concorrentemente com operações de escrita, o valor lido é sempre, ou o valor antigo, ou o valor a ser escrito, nunca um valor intermédio. O sistema tolera faltas bizantinas por parte dos servidores do DepSpace, do serviço de directorias, do serviço de locks, dos provedores de armazenamento nas clouds e do serviço de armazenamento (enquanto processo leitor de dados no DepSky). Embora o C2FS garanta que, a cada instante, não existe mais que um processo escritor para um mesmo contentor no DepSky, não são considerados escritores maliciosos pois, tendo acesso ao ficheiro, um cliente malicioso poderia escrever dados sem sentido para a aplicação de qualquer forma. Todos os serviços de armazenamento que efectuam leituras (recorrendo ao DepSky) têm acesso à chave pública dos escritores, permitindo efectuar verificação e validação dos dados lidos (previamente assinados). Tanto no caso dos servidores DepSpace como das clouds usadas pelo DepSky, devido ao uso de quóruns bizantinos, o sistema requer n ≥ 3f +1 servidores (ou clouds) para tolerar f faltas, assumindo, no entanto, que as falhas dos servidores não são correlacionadas. No entanto, o sistema tolera um número ilimitado de clientes faltosos. Capítulo 3. Metadados e Locks no C2FS 3.2 31 Metadados Os metadados no contexto de um sistema de ficheiros, tem a função de guardar informações referentes a cada ficheiro, tais como a localização dos seus dados na memória secundária, o seu dono, as permissões de acesso por parte de diferentes utilizadores, entre outros. Tal como todos os sistemas de ficheiros, também o C2FS necessita de um mecanismo que lhe permita armazenar e manusear os metadados do sistema. Neste contexto, foram desenvolvidas algumas versões de um serviço de directorias para efectuar estas tarefas. Todas as versões deste serviço de directorias que permitem a partilha de ficheiros utilizam o DepSpace [23] para armazenar os metadados. Abaixo, serão descritas as alterações necessárias neste serviço de coordenação, assim como o modo de funcionamento dos vários mecanismos desenvolvidos para armazenar e manusear os metadados do C2FS. 3.2.1 DepSpace Como referido na secção 2.1.3, o DepSpace é um serviço de coordenação seguro e tolerante a faltas bizantinas. Este serviço utiliza uma abstracção de espaço de tuplos, fornecendo aos clientes a possibilidade de armazenar estruturas de dados genéricas (chamadas tuplos). Além de simplesmente armazenar tuplos, este serviço possibilita definir políticas de acesso aos tuplos contidos no espaço, nomeadamente definir quais os clientes que estão habilitados a ler ou modificar o conteúdo de um determinado tuplo contido no espaço. Possibilita ainda a criação de tuplos temporários, ou seja, tuplos que permanecem no espaço de tuplos durante um espaço de tempo previamente definido, sendo estes, a menos que sejam revalidados (através da chamada da operação renew), removidos automaticamente quando expirados. Para a implementação de um serviço de directorias eficiente para o C2FS, foi necessário adicionar duas novas funcionalidades ao DepSpace. Operação replace. Uma das limitações do modelo de espaço de tuplos é a impossibilidade de modificar um tuplo no espaço. Esta limitação aparece para um serviço de directorias quando, por exemplo, é necessário renomear um nó da árvore de directorias, que é representado por um tuplo no DepSpace. A forma usual de se alterar tuplos é remover a versão antiga e adicionar uma nova. No entanto, esta solução levanta problemas tanto de desempenho (pelo menos duas operações no espaço) como de consistência (as duas operações não são atómicas). A solução encontrada para este problema foi adicionar uma nova operação à interface exportada pelo DepSpace, operação esta chamada replace(t̄,t). Esta nova operação substitui o tuplo mais antigo no espaço que satisfaça t̄ por t, retornando true no caso de ter sido modificado algum tuplo e false caso contrário. Capítulo 3. Metadados e Locks no C2FS 32 Suporte a triggers. Um segundo problema, mais grave, ocorre quando renomeamos uma directoria. Quando isso acontece, é necessário actualizar o campo “nó pai” de todos os nós dentro dessa directoria. Como veremos mais à frente (secção 3.2.2), o identificador guardado no tuplo que permite ao sistema saber qual “nó pai” de um determinado nó é o caminho (path) deste. À primeira vista, este problema poderia ser resolvido substituindo este identificador por um identificador imutável (como o container_id), o qual não necessitaria ser alterado quando o nó é renomeado. Na verdade, esta abordagem seria ainda mais problemática pois, visto o sistema operativo executar as chamadas sobre o sistema de ficheiros utilizando o path dos nós sobre os quais pretende operar, teriam de ser feitas várias chamadas sobre o serviço de directorias até se obter os metadados do nó pretendido, e só então, operar sobre os mesmos. Por exemplo, supondo que existem os ficheiros /m/foo/file e /m/fuu/file com os container_ids 3 e 4, e que as directorias /m/foo e /m/fuu têm os container_ids 1 e 2 respectivamente, os tuplos guardados, segundo esta abordagem alternativa, seriam (numa versão simplificada): hF ILE, 1, f ile, 3i, hF ILE, 2, f ile, 4i, hDIR, 0, f oo, 1i e hDIR, 0, f oo, 2i. Numa operação de stat2 sobre o ficheiro /m/foo/file, visto termos mais que um tuplo com o nome file, ao pesquisarmos por esse nome através do template h∗, ∗, f ile, ∗i, obteríamos os tuplos hF ILE, 1, f ile, 3i e hF ILE, 2, f ile, 4i. Em seguida, teríamos ainda de perceber, através de nova chamada ao DepSpace, qual dos dois é referente à directoria /m/foo. Para isso seria usado o template h∗, ∗, f oo, ∗i, obtendo então os metadados da directoria procurada, e assim o seu container_id. Neste caso, bastariam estas duas chamadas, pois bastava comparar os container_ids dos campos “nó pai” dos tuplos obtidos da primeira chamada com o container_id do nó obtido na segunda para perceber qual o tuplo com os metadados do ficheiro /m/foo/file. Note-se no entanto que poderiam ser necessárias mais chamadas caso existissem mais nós no sistema com o nome foo. Como podemos perceber, esta abordagem levantaria problemas de atomicidade e de desempenho da operação. A abordagem utilizada para resolver este problema de forma eficiente, i.e., evitar a execução de um replace por cada nó filho do nó renomeado, foi adicionar uma nova camada para suporte a Triggers. Quando é executada uma operação de replace no DepSpace é activado um gatilho que, de forma recursiva, executa um conjunto de outras operações replace nos servidores, actualizando o campo “nó pai” de todos os nós abaixo do nó renomeado na árvore de directorias. Uma outra função desta camada é permitir a substituição de tuplos quando um nó é renomeado. Por exemplo, existindo os ficheiros /A e /B, se pretendermos renomear o ficheiro /A para /B, o comportamento esperado é que o ficheiro /A deixe de existir, passando o ficheiro /B a conter os dados de /A. Neste contexto, se simplesmente modificarmos o nome de /A para /B, passariam a existir dois nós com o mesmo nome. Neste sentido, sempre que já exista no espaço um tuplo cujo caminho seja igual ao novo caminho de 2 Operação do sistema de ficheiros utilizada para obter os metadados de um dado nó. Capítulo 3. Metadados e Locks no C2FS 33 um nó renomeado, este tuplo é apagado do espaço. Uma outra potencialidade desta camada é permitir utilizar valores dos metadados dos nós substituídos, ou seja, caso existam campos no novo tuplo que não estejam definidos (tenham o valor ’*’), quando este tuplo substitui o antigo, estes campos são preenchidos com o valor dos campos correspondentes no antigo tuplo. Todas as operações já referidas que são efectuadas por um trigger são executadas de forma atómica. Note-se também que os Triggers só são requeridos quando há necessidade de renomear um nó. 3.2.2 Serviço de Directorias O C2FS usa um serviço de directorias que tem por base o DepSpace. Esta abordagem faz com que os metadados possam ser guardados utilizando a abstracção de espaço de tuplos ao mesmo tempo que permite que o serviço herde todas as garantias fornecidas pelo serviço subjacente. Cada serviço de directorias é então cliente do DepSpace e tem um identificador único que o identifica. Formato dos Metadados Os metadados de todos os ficheiros, directorias e ligações simbólicas são representados como tuplos no espaço. Para o caso dos ficheiros e directorias, esses tuplos têm o seguinte formato: hNODE , parent_folder , node_name, node_type, node_metadata, container _id i O campo parent_folder guarda o caminho do “nó pai” do nó em questão, enquanto que o campo node_name é o nome do nó. Para obter o caminho de um determinado nó basta, portanto, concatenar o valor do campo parent_folder com o carácter ‘\’ seguido do valor do campo node_name. O campo node_type pode tomar o valor de FILE, DIR consoante os metadados sejam de um ficheiro ou uma directoria, respectivamente. O campo node_metadata contém toda a informação dos metadados de um determinado nó, tais como as permissões sobre ele por parte dos vários utilizadores do sistema, o identificador do dono do ficheiro, o tamanho do ficheiro, o resumo criptográfico (hash) dos dados a que este se refere e a chave simétrica utilizada para cifrar estes dados. A importância de manter o resumo criptográfico e a chave neste serviço será explicada em detalhe mais à frente. O campo container_id é o identificador único do contentor onde os dados de um determinado ficheiro são armazenados. No caso das directorias, este identificador é ignorado pelo sistema. Este identificador é criado pelo cliente do serviço de directorias que cria o contentor. Para garantir que dois clientes não criam dois contentores com o mesmo identificador, este é gerado concatenando o identificador do cliente no serviço de directorias (que o serviço garante ser único) com um timestamp local. Capítulo 3. Metadados e Locks no C2FS Op. do Serviço de Directorias Op. do DepSpace getMetadata(path) rdp(hNODE, parent(path), name(path), *, *, *, *i); putMetadata(mdata) cas(hNODE, parent(mdata), name(mdata), *, *, *, *i, 34 hNODE, parent(mdata), name(mdata), nodeType(mdata), mdata, contId(mdata)i); removeMetadata(path) inp(hNODE, parent(path), name(path), *, *, *, *i); updateMetadata(path, mdata) replace(hNODE, parent(path), name(path), *, *, *, *i, hNODE, parent(mdata), name(mdata), nodeType(mdata), mdata, contId(mdata)i); getChildren(parent) rdAll(hNODE, parent, *, *, *, *, *i); getLinks(contId) rdAll(hNODE, *, *, *, *, *, contIdi); updateLocalMetadata(contId, hash, size) - commitLocalMetadata(contId) replace(hNODE, parent, name, *, *, *, *i, hNODE, parent, name, nodeType, mdata, contIdi); putPrivateNamespace(namespaceStats) cas(hPRIVATE_NAMESPACE, *, *, *i, hPRIVATE_NAMESPACE, contID, key, hashi); getPrivateNamespace() rdp(hPRIVATE_NAMESPACE, contID, *, *i); Tabela 3.1: Interacção do serviço de directorias com o DepSpace. No caso das ligações simbólicas, visto este tipo de nós consistirem num apontador para um outro nó, alguns dos campos deste formato são utilizados para armazenar diferentes informações. Assim, no campo container_id, ao invés do identificador do contentor de dados do nó, é guardado o caminho do nó para o qual esta ligação aponta. Os campos parent_folder e node_name são utilizados para armazenar o caminho do “nó pai” da ligação e o seu nome, respectivamente. Os restantes campos do formato apresentado mantêm a função anteriormente descrita, sendo que neste caso, como é fácil de perceber, o campo node_type tem o valor SYMLINK. Operações do Serviço de Directorias O serviço de directorias exporta uma API que permite efectuar todas as operações necessárias para manipular os metadados do sistema. Assim, estão disponíveis operações para adicionar, remover, alterar e obter os metadados de um nó do sistema de ficheiros. A tabela 3.1 apresenta uma lista dessas operações e a sua interacção com o DepSpace. Como podemos perceber, para armazenar os metadados dos nós do sistema de ficheiros, o serviço de directorias insere tuplos no espaço. A operação usada para inserir estes tuplos é a operação cas pois permite, de uma forma atómica, inserir um tuplo no espaço apenas no caso de não existir nenhum outro que corresponda ao mesmo nó do sistema de ficheiros. Para obter os metadados de um dado nó, o serviço faz uma leitura ao espaço, com a operação rdp que devolve o tuplo mais antigo no espaço que satisfaça um template dado. Para remover tuplos do espaço é usada a operação inp do DepSpace, enquanto que para as operações do serviço que necessitam obter os metadados de mais que um nó é utilizada a operação rdAll. A operação inp permite remover os metadados de um nó, en- Capítulo 3. Metadados e Locks no C2FS 35 quanto que a operação rdAll permite obter uma colecção com os tuplos que correspondam com o template fornecido pelo serviço de directorias. Para lidar com actualizações de metadados em consequência de actualizações de dados, o serviço permite modificar os valores do tamanho e resumo criptográfico dos dados localmente, mantendo estas alterações por tempo indeterminado até que o cliente do serviço decida efectuar essas alterações de forma definitiva no DepSpace. Isto é usado, e.g., quando o cliente tem de fazer escritas demoradas de dados. Neste caso o sistema primeiro efectua a escrita dos dados numa cache em disco local, depois altera os metadados localmente e retorna ao sistema operativo, fazendo a alteração no DepSpace apenas quando a escrita dos dados terminar. No caso concreto do C2FS, este mecanismo é útil quando o serviço de armazenamento faz as escritas para as clouds de forma assíncrona. Nesta configuração, este mecanismo permite que durante a execução das escritas em background, geridas pelo serviço de armazenamento, o cliente possa efectuar leituras aos dados com os metadados correctos, ao mesmo tempo que previne outros clientes do sistema, que correm uma outra instância do serviço de directorias, de obter metadados errados para o mesmo nó. Esta potencialidade é implementada através das operações updateLocalMetadata(contId, hash, size) e commitLocalMetadata(contId), sendo a primeira para actualizar os valores do tamanho e resumo criptográfico dos dados localmente e a segunda para propagar estas actualizações para o DepSpace, ficando então disponíveis a todos os clientes do sistema. Como podemos perceber na definição das operações na tabela 3.1, a operação updateLocalMetadata(contId, hash, size) não faz qualquer operação no DepSpace. Nesta operação, os valores alterados são armazenados numa estrutura de dados mantida na memória principal e ainda em disco local. A utilização do disco local para armazenar estes valores é imprescindível pois, em caso de falha do serviço de directorias durante o envio dos em dados em background para a cloud-of-clouds, é possível recuperar os metadados referentes à escrita em curso. Assim, na operação commitLocalMetadata(contId), os metadados guardados localmente são actualizados no DepSpace e apagados tanto da estrutura de dados em memória como do disco local. Na verdade, os únicos campos actualizados por esta operação são o tamanho e o resumo criptográfico dos dados. Esta abordagem permite que o cliente do serviço possa fazer alterações a outros campos dos metadados enquanto os metadados estão guardados localmente, i.e., enquanto a escrita do ficheiro está a decorrer. As operações putPrivateNamespace e getPrivateNamespace têm por função inserir e obter as informações referentes ao espaço de nomes pessoal de cada cliente. Estas operações serão descritas em pormenor na secção 3.2.4. Controlo de Acesso aos Ficheiros O serviço de directorias fornece um mecanismo que permite controlar o acesso aos metadados. Este permite aos clientes definir, a qualquer instante, quais os clientes do Capítulo 3. Metadados e Locks no C2FS 36 sistema de ficheiros que podem ler ou modificar os metadados. Este mecanismo está assente sobre as políticas de controlo de acesso aos tuplos do DepSpace [23]. O que é feito pelo serviço de directorias é definir quais os identificadores dos clientes com permissões de leitura e escrita sobre cada tuplo. Desta forma, um outro cliente do sistema de ficheiros (que corre um serviço de directorias próprio com um identificador único no DepSpace) apenas consegue obter ou alterar os metadados de nós cujos tuplos tenham o seu identificador na lista de clientes aptos para ler ou escrever. É com o mecanismo de controlo de acesso aos metadados descrito, aliado com o facto de o serviço de armazenamento [40] cifrar os dados com a chave simétrica armazenada juntamente com os metadados, que o C2FS faz controlo de acesso aos ficheiros. Para um cliente ler os dados de um determinado ficheiro este tem que, em primeiro lugar, ter acesso à chave usada para cifrar os mesmos. Caso este seja um cliente não autorizado, este não conseguirá obter os metadados do ficheiro e, assim sendo, não conseguirá obter a chave para decifrar os dados. Desta forma, mesmo que um cliente consiga obter os dados directamente das clouds sem usar o serviço de armazenamento, este não consegue aceder os dados em claro. 3.2.3 Cache no Serviço de Directorias Conforme já descrito, o serviço de directorias pode realizar caching de metadados em memória local de forma a minimizar tanto a latência de acesso aos metadados3 , quanto o número de chamadas feitas ao DepSpace (permitindo a este atender mais clientes e reduzir os custos da utilização deste serviço). A cache de metadados do C2FS é concretizada utilizando tarefas temporizadas, responsáveis pela actualização dos metadados no DepSpace após a expiração de um temporizador, sendo que cada tarefa é responsável por actualizar os metadados de um único nó. Estas tarefas são criadas com o objectivo de efectuar actualizações nos metadados de um determinado nó no DepSpace de forma assíncrona ao sistema e com um atraso esperado de no máximo ∆ ms, sendo ∆ um parâmetro do serviço. Este mecanismo permite também que todas as actualizações feitas aos metadados de um nó em cache durante um intervalo de ∆ ms sejam executadas de uma única vez no DepSpace. O valor de ∆ define também por quanto tempo os metadados de um determinado nó estão em cache no serviço de directorias. Assim, a definição deste parâmetro deve ter em conta que, quanto maior seu valor, menor o número de chamadas feitas ao DepSpace, e maior o atraso de propagação de alterações de metadados, o que pode ter efeitos negativos na consistência do sistema. Para além das operações descritas na tabela 3.1, esta versão do serviço de directorias fornece uma operação extra, chamada removeFromCache(path), responsável por limpar da cache toda a informação referente aos metadados do nó com o caminho 3 Acedidos através das chamada stat, identificada em muitos estudos como a operação mais comumente invocada pelos sistemas de ficheiros (como é mostrado na secção 5.2). Capítulo 3. Metadados e Locks no C2FS 37 dado. Os algoritmos 1, 2 e 3 descrevem em detalhe o comportamento das operações putMetada, getMetadata e updateMetadata do serviço de directorias com cache activada. Variáveis utilizadas. Nestes algoritmos o objecto noCacheDiS representa um objecto do serviço de directorias sem cache que disponibiliza as operações e comportamento descritos na tabela 3.1. Os objectos cache e localMetadata representam a cache de metadados e a estrutura de dados em memória principal que mantém as actualizações de metadados localmente, respectivamente. Os objectos UpdaterTask representam as tarefas temporizadas responsáveis por actualizar os metadados no DepSpace de forma assíncrona, enquanto que o objecto scheduler representa um objecto que mantém as tarefas de actualização, e as executa com um atraso pré-definido. No algoritmo 4 há ainda os objectos stopped e cacheDiS. O primeiro é um booleano que indica se a tarefa foi ou não cancelada, enquanto que o segundo é um objecto do serviço de directorias com cache. Algoritmos. No algoritmo 1 podemos ver que o nó é criado no sistema através da inserção dos seus metadados no DepSpace (linha 2). Estes metadados são também guardados em cache (linha 4), permitindo que as operações feitas sobre eles nos ∆ ms seguintes possam ser feitas numa só chamada ao DepSpace. Algorithm 1: putMetadata(m) Map h String, MetadataCacheEntry i cache; 1 2 3 4 Entrada: m - metadados a inserir início noCacheDiS.putM etadata(m); entry ←− M etadataCacheEntry(m, currentT ime); cache.put(m.path, entry); fim A operação referente à obtenção de dados (algoritmo 2) é um pouco mais complexa. Em primeiro lugar o serviço verifica se os metadados referentes ao nó pedido estão em cache, caso isto não se verifique, os metadados são obtidos recorrendo ao serviço de directorias sem cache e guardados em cache, como podemos ver nas linhas 4 e 6 do algoritmo. Caso os metadados se encontrem em cache, é necessário verificar se estes ainda se encontram válidos, ou seja, estão guardados em cache há menos de ∆ ms (linha 7). Se os metadados guardados em cache forem inválidos, são então obtidos do DepSpace recorrendo ao serviço de directorias sem cache, como se pode observar na linha 10. Caso existam metadados guardados na estrutura localMetadata, os campos referentes ao tamanho dos dados e resumo criptográfico guardados nos metadados desta estrutura são substituídos nos metadados a retornar por esta operação (linhas 15 e 16). Capítulo 3. Metadados e Locks no C2FS 38 Algorithm 2: getMetadata(path) Map h String, MetadataCacheEntry i cache; Map h String, NodeMetadata i localMetadata; 1 2 3 4 5 6 7 8 9 10 11 12 Entrada: path - caminho do ficheiro a obter Saída: metadados de path início entry ←− cache.get(path); se (entry =⊥) então mdata ←− noCacheDiS.getM etadata(path); entry ←− M etadataCacheEntry(mdata, currentT ime); cache.put(path, entry); senão se (currentT ime ≤ (entry.time + ∆)) então mdata ←− entry.metadata; senão cache.remove(path); mdata ←− noCacheDiS.getM etadata(path); entry ←− M etadataCacheEntry(m, currentT ime); cache.put(path, entry); 16 mdata0 ←− localM etadata.get(mdata.containerId); se (mdata0 6=⊥) então mdata.dataSize ←− mdata0 .dataSize; mdata.dataHash ←− mdata0 .dataHash; 17 retorna mdata; 13 14 15 fim Na operação updateMetadata apresentada no algoritmo 3, o primeiro procedimento efectuado no caso em que os metadados do nó referente ao caminho dado não estejam em cache (ou estejam inválidos) é obtê-los. Este procedimento é feito através da chamada da operação getMetadata. Em seguida, caso não exista ainda nenhuma tarefa de actualização para o nó referente ao caminho dado, essa tarefa tem de ser lançada. Esta tarefa, como podemos ver na linha 7 do algoritmo em descrição, é agendada para ∆ ms após a execução da tarefa menos a quantidade de tempo em que os metadados a actualizar estão em cache. Isto acontece para garantir que não são feitas actualizações sobre metadados inválidos em cache. Após isso basta alterar o valor dos metadados em cache pois, após (quanto muito) ∆ ms, é esse o valor enviado pela tarefa de actualização. Há, no entanto, o problema de a operação ter por objectivo renomear um nó da árvore de directorias. Neste caso, não basta modificar o caminho do nó e esperar que a tarefa de actualização propague essa modificação para o DepSpace. Esta abordagem tem o problema de poder já existir um nó cujo caminho é igual ao novo caminho do nó renomeado. Neste caso, poderia acontecer que esse nó estivesse em cache, logo, pudesse ter uma tarefa de actualização para alterar Capítulo 3. Metadados e Locks no C2FS 39 Algorithm 3: updateMetadata(path, m) Map h String, NodeMetadata i cache; Map h String, NodeMetadata i localMetadata; 1 2 3 4 Entrada: path - caminho dos metadados, m - nova versão dos metadados início oldMDataEntry ←− cache.get(path); se ((oldMDataEntry =⊥) ∨ (currentT ime ≥ oldMDataEntry.time)) então getM etadata(path) ; // metadados ficam em cache se (!scheduler.contains(path)) então updaterT ask ←− UpdaterTask (path, m, N oCacheDiS, this); t ←− (∆ − (currentT ime − entry.time)); scheduler.schedule(m.path, updaterT ask, t); 5 6 7 8 se (path 6= m.path) então schedule.cancel(path); cache.remove(path); replacedMData ←− getM etadata(m.path); se (replacedMData 6=⊥) então se (replacedMData.numContainerLinks ≤ 1) então localMetadata.remove(replacedMData.containerId); 9 10 11 12 13 14 15 se (cache.get(m.path) 6=⊥) então schedule.cancel(m.path); cache.remove(m.path); 16 17 18 noCacheDiS.updateM etadata(path, m); senão cache.remove(path); entry ←− MetadataCacheEntry(m, currentT ime); cache.put(path, entry); 19 20 21 22 fim os seus metadados. Assim, a tarefa de actualização deste segundo nó poderia alterar os metadados do nó renomeado. Para solucionar este problema, sempre que esta operação tenha por objectivo renomear um nó, o serviço verifica se existem tarefas de actualização para o nó renomeado. Caso exista, essa tarefa é abortada (linha 10). Em seguida, o serviço verifica se existe um nó cujo caminho corresponda ao novo caminho do nó renomeado. Caso isto se verifique, a tarefa de actualização referente a este nó, caso exista, é abortada (linha 17). Nas linhas 14 e 15 do algoritmo em descrição, podemos perceber que, na existência de um nó que irá ser substituído por um nó renomeado, caso o número de ligações ao seu contentor seja menor ou igual a um, os seus metadados são apagados da estrutura de dados que mantém as actualizações de metadados feitas localmente. Isto acontece pois, dada a substituição do nó em questão, o seu contentor de dados irá perder uma ligação, Capítulo 3. Metadados e Locks no C2FS 40 logo, esta informação deixa de ser útil. Algorithm 4: UpdaterTask.run() NodeMetadata initialMData; NodeMetadata mData; Boolean stoped; 1 2 3 Entrada: m - metadados a inserir início se (!stopped ∧ (initialMData 6= mData)) então noCacheDiS.updateM etadata(initialMData.path, mData); cacheDiS.removeF romCache(initialMData.path); 4 fim O comportamento das tarefas de actualização, que são executadas após ∆ ms pelo Scheduler, resume-se a, caso hajam, propagar as actualizações feitas ao seu nó para o DepSpace. Na linha 2 do algoritmo 4 são comparados os metadados iniciais com os metadados actuais, sem a actualização efectuada apenas no caso de estes dois objectos não coincidirem. Note-se que o objecto initialMData é obtido através da chamada do método clone sobre o objecto mData aquando da construção da tarefa, enquanto que o objecto mData referência o objecto de metadados mantido em cache pelo serviço de directorias. Após as rotinas descritas acima, é chamada a operação removerFromCache(path) (linha 4), que permite ao serviço de directorias remover os metadados da estrutura cache. 3.2.4 Espaço de Nomes Pessoal O facto de o DepSpace guardar todos os tuplos na memória principal é uma limitação deste serviço. Desta forma, também o serviço de directorias herda esta limitação pois, o espaço de memória das réplicas onde o DepSpace está instalado oferece um limite quanto à quantidade de metadados que o serviço de directorias pode armazenar. Para minimizar esta limitação introduzimos o conceito de espaço de nomes pessoal: um objecto que guarda uma série de metadados referentes a nós que são privados ao seu dono, ou seja, que não são partilhados. Com a utilização destes objectos, os metadados, ao invés de serem guardados no DepSpace, são guardados numa estrutura de dados serializável. Esta estrutura é guardada juntamente com os dados do sistema de ficheiros (neste caso, no serviço de armazenamento), sendo apenas guardado no serviço de directorias um tipo de metadados especial que tem as informações necessárias para o utilizador poder obter a referida estrutura de dados. O espaço de nomes pessoal é enviado para escrita no serviço de armazenamento sempre que é feita uma modificação na estrutura de dados que mantém os metadados. O serviço de directorias, através das operações putPrivateNamespace e getPrivateNamespace, permite armazenar e obter a informação relativa ao armazenamento do es- Capítulo 3. Metadados e Locks no C2FS 41 paço de nomes pessoal na cloud-of-clouds. Esta informação, tal como os metadados dos ficheiros partilhados, é armazenada no DepSpace, sendo as permissões de escrita e leitura do tuplo onde a esta informação é armazenada atribuídas unicamente ao dono do espaço de nomes pessoal. Esta abordagem garante que apenas o dono do espaço de nomes pessoal consiga obter e modificar o tuplo que armazena as informações de acesso a este objecto. O referido tuplo tem o seguinte formato: hPNS , container _id , key, hashi O valor do campo container_id diz respeito ao contentor onde o espaço de nomes pessoal é armazenado. Este identificador é único e é baseado no identificador do cliente junto do DepSpace, podendo ser calculado pelo serviço de directorias. O campo key é a chave simétrica que é utilizada pelo serviço de armazenamento para cifrar o espaço de nomes pessoal, impossibilitando outros clientes de obter os metadados dos ficheiros pessoais de um determinado cliente. Note-se que, caso não fosse utilizado este processo, um cliente poderia obter os metadados dos ficheiros pessoais de um outro cliente, e assim, obter as chaves usadas para encriptar os dados dos seus ficheiros. Desta forma, caso este conseguisse obter os dados dos ficheiros referentes aos metadados obtidos, conseguiria lêlos em claro. No campo hash é armazenado o resumo criptográfico do espaço de nomes privado. A utilidade deste é permitir ao serviço de armazenamento verificar a validade do objecto mantido em cache. Caso o hash do objecto mantido em cache não coincida com o hash mantido pelo serviço de directorias, uma nova versão do objecto tem de ser lida da cloud-of-clouds. Embora este acontecimento seja invulgar (dado nenhum outro cliente conseguir alterar este objecto), esta verificação necessita ser feita pois, visto os dados em cache serem guardados no disco local, pode acontecer que esta informação tenha sido apagada pelo utilizador ou que o sistema a tenha substituído por motivos de falta de espaço livre em disco. Na prática, um espaço de nomes pessoal fornece sensivelmente as mesmas operações que o serviço de directorias, no entanto, todas as operações são executadas localmente. A utilização desta técnica permite então, não só minimizar a limitação do DepSpace relacionada com o armazenamento dos tuplos na memória principal, mas também, aumentar o desempenho do manuseamento dos metadados de nós privados. Cada utilizador do sistema de ficheiros tem apenas um espaço de nomes pessoal, sendo este obtido do serviço de armazenamento sempre que o sistema de ficheiros é montado. 3.2.5 Serviço de Directorias sem Partilha de Ficheiros Para utilizadores que têm como objectivo utilizar o C2FS para armazenar ficheiros na cloud-of-clouds sem a necessidade de os partilhar com outros utilizadores, foi desenvolvido um serviço de directorias sem partilha de ficheiros. Este serviço de directorias é Capítulo 3. Metadados e Locks no C2FS 42 concretizado localmente e, à semelhança do espaço de nomes privado, é concretizado utilizando um objecto serializável que mantém várias estruturas de dados onde são guardados os metadados de todos os nós do sistema, objecto este que é armazenado nas clouds recorrendo ao serviço de armazenamento. Este serviço de directorias, à excepção das operações relacionados com o espaço de nomes pessoal, fornece as mesmas operações que o serviço de directorias com partilha de ficheiros, tendo um comportamento similar ao mesmo. Nesta versão do serviço de directorias, as operações relacionadas com o espaço de nomes pessoal deixam de fazer sentido pois, não havendo partilha de ficheiros, todos os ficheiros passam a ser pessoais. À imagem do objecto de espaço de nomes pessoal, também o objecto que mantém todos os metadados deste serviço é serializado e armazenado nas clouds sempre que existe uma alteração de metadados em algum nó deste serviço de directorias. Este serviço, para além de aumentar o desempenho do sistema, visto todos os metadados serem manuseados localmente, permite também diminuir os custos de utilização do C2FS pois, ao contrário do serviço de directorias apresentado anteriormente, não necessita ter nenhum serviço instalado em instâncias fornecidas por provedores de computação nas clouds, não havendo custos com a manutenção das mesmas. 3.3 Serviço de Locks Para coordenar o acesso concorrente por parte de processos escritores aos ficheiros do C2FS com o objectivo de manter a consistência dos mesmos, foi desenvolvido um serviço de locks. Como referido anteriormente, também este serviço foi desenvolvido tendo o DepSpace como base. No C2FS, antes de efectuar uma escrita num ficheiro, um cliente têm de reservar o contentor de dados desse ficheiro através da aquisição de um lock. Este lock é efectuado sobre o contentor de dados pois, devido ao facto do C2FS suportar ligações fortes (hard links) entre ficheiros, caso os locks fossem feitos sobre ficheiros, poderiam existir dois clientes com locks sobre diferentes ficheiros a escrever para o mesmo contentor de dados, o que poderia levar a escritas inconsistentes. Para isto, o serviço de locks exporta uma interface que permite aos clientes do serviço adquirir e libertar um lock sobre um dado contentor de dados através da disponibilização de três operações: tryAcquire, release e renew. No algoritmo 5 são apresentadas estas operações, assim como as chamadas feitas ao DepSpace aquando da sua execução. Relembro que é assumido que o DepSpace implementa políticas de controlo de acesso que protegem o espaço de tuplos [25] A primeira operação do algoritmo permite ao cliente tentar reservar um contentor para escrita, retornando true em caso de sucesso e false caso contrário. Assim, quando um cliente tenta adquirir o lock sobre um contentor de dados o serviço tenta inserir um tuplo Capítulo 3. Metadados e Locks no C2FS 43 Algorithm 5: Operações do serviço de locks. 1 procedimento tryAquire(contId, time) 2 início 3 retorna cas(hLOCK, contIdi, hLOCK, contIdi, time); fim 4 5 6 7 8 9 procedimento release(contId) início inp(hLOCK, contIdi); fim procedimento renew(contId, time) início renew(hLOCK, contIdi, time); fim de lock sobre o mesmo contentor no DepSpace. Esta aquisição, assim como a operação feita pelo cliente, só tem sucesso no caso de o serviço de locks obter true da operação cas efectuada no DepSpace. Para prevenir que outros clientes C2FS libertem locks que não lhes pertencem, através da remoção dos tuplos que representam locks, o serviço de locks configura o tuplo de lock inserido no espaço com permissões de escrita apenas para o seu criador. Desta forma, apenas quem cria o tuplo de lock pode removê-lo. Quando um cliente deste serviço, neste caso, o agente C2FS, não consegue obter o lock, espera um intervalo de tempo (de aproximadamente um segundo) e só depois volta a tentar reservar o mesmo contentor. A operação release permite ao cliente libertar um contentor de dados, caso este esteja reservado. Nesta operação o serviço, através da operação inp do DepSpace, remove o tuplo de lock do espaço. Assim, quando um outro utilizador tentar reservar o mesmo contentor de dados, o serviço de locks a correr na sua máquina irá obter sucesso quando efectua a chamada cas da operação tryAquire. Para tolerar a falha de um cliente detentor de um lock, são usados tuplos de lock com tempos de expiração (que desaparecem do espaço após um intervalo de tempo [41]), que garantem que os locks acabam por ser libertados se os seus detentores falharem. Esta garantia é indispensável pois, caso contrário, a falha de um cliente detentor de um lock poderia resultar na indisponibilidade permanente do contentor reservado. Assim, quando o cliente tenta adquirir um lock sobre um ficheiro, este tem de fornecer a quantidade de tempo na qual deseja que este lock se encontre válido (a variável time dada como argumento na operação de aquisição do lock). Note-se que o serviço de locks deixa para o cliente a responsabilidade de renovar este lock, através da chamada da operação renew. Esta operação executa a operação renew do DepSpace para aumentar o tempo de validade do tuplo por mais uma quantidade de tempo, sendo essa quantidade de tempo dada por Capítulo 3. Metadados e Locks no C2FS 44 time. No caso do C2FS, o responsável por revalidar os locks sobre os contentores de dados é o agente C2FS. Este módulo mantém uma lista de tarefas responsáveis por manter válidos todos os locks sobre os contentores de dados de todos os ficheiros abertos a cada instante. Aquando do fecho de um ficheiro, o agente C2FS acaba a execução da tarefa responsável por fazer as revalidações do lock sobre o contentor de dados desse ficheiro e liberta esse lock. Desta forma, o contentor de dados fica então livre para ser reservado por outro processo. O agente C2FS é também responsável por, aquando da abertura de um ficheiro, decidir se é ou não necessário reservar o respectivo contentor de dados. Sempre que o ficheiro a ser aberto é pessoal, não é necessário obter o lock sobre ele. Um ficheiro é considerado pessoal caso este pertença ao espaço de nomes pessoal ou caso o serviço de directorias em uso pelo sistema de ficheiros não permita a partilha de ficheiros. Como é fácil de perceber, se um ficheiro é pessoal, nenhum outro utilizador irá ter acesso a ele e, assim, não precisa ser considerado como escritor concorrente. No entanto, para controlar o acesso concorrente a um ficheiro pessoal por parte de diferentes processos escritores na mesma máquina, o agente C2FS mantém, a cada instante, uma lista dos contentores de dados dos ficheiros abertos para escrita, não permitindo a abertura de nenhum outro ficheiro com o mesmo contentor por parte de outro processo. A prova de que este algoritmo satisfaz as propriedades de um algoritmo de locks está no apêndice A. 3.4 Consistência no C2FS Visto os provedores de armazenamento nas clouds fornecerem apenas garantia de consistência eventual [51], um dos objectivos do C2FS é aumentar estas garantias, fornecendo aos seus clientes uma garantia de consistência forte. Neste contexto, um dos problemas é fornecer um serviço de armazenamento consistente a partir de clouds de armazenamento eventualmente consistentes. Para isso, é necessária a utilização de uma âncora de consistência, um serviço consistente que permite armazenar pequenas quantidades de informação. No C2FS, o serviço utilizado como âncora de consistência é o serviço de directorias. Note-se que as versões do serviço de directorias com partilha de ficheiros tiram partido do DepSpace [23] para tal. Em termos gerais, o mecanismo utilizado consiste em, aquando de uma escrita num ficheiro, o cliente actualiza em primeiro lugar os dados no serviço de armazenamento, e só depois os metadados no serviço de directorias. Assim, quando um outro cliente obtém os metadados com a nova versão dos metadados, este vai saber que, eventualmente, os dados irão estar disponíveis. Para a implementação deste mecanismo, foi necessário adicionar uma nova operação Capítulo 3. Metadados e Locks no C2FS 45 ao DepSky [24] chamada readMatching que, dado o identificador do contentor de dados e um resumo criptográfico referente aos dados que o cliente pretende obter, devolve os dados mais actualizados que correspondam ao resumo criptográfico fornecido [40]. Esta operação permite, caso o resumo criptográfico não corresponda à versão mais recente dos dados, obter uma versão antiga dos dados que corresponda ao mesmo. Esta última funcionalidade permite obter dados consistentes mesmo que, aquando de uma leitura concorrente com uma escrita e após a obtenção dos metadados (e assim, do resumo criptográfico), os dados a ler das clouds sejam mais recentes que os metadados obtidos. Isto pode acontecer pois, no processo de escrita, os dados são escritos antes de actualizar os metadados, ao passo que, no processo de leitura, os metadados são obtidos em primeiro lugar. Com esta abordagem temos a possibilidade de obter metadados referentes a uma versão antiga dos dados, problema este resolvido pela operação readMatching. Quando o resumo criptográfico fornecido a esta operação não diz respeito a nenhuma das versões dos dados armazenadas nas clouds significa que, devido às limitações de consistência dos provedores de armazenamento nas clouds, estes ainda não estão disponíveis, sabendo nós que, eventualmente o estarão. Neste caso, a operação readMatching do DepSky retorna um erro. Para tentar obter a nova versão dos dados, quando o serviço de armazenamento obtém um erro desta operação, este volta a tentar obter os dados após um tempo (normalmente 5 segundos), fazendo este processo três vezes. Caso após as três tentativas não consiga obter os dados referentes à versão pedida, é retornado um erro. No caso do C2FS, quando o agente C2FS obtém erro de uma leitura no serviço de armazenamento, também a operação de leitura do sistema de ficheiros retorna um erro. Neste contexto, a operação de escrita no C2FS segue os seguintes passos: 1. Escrever os dados com o resumo criptográfico h no DepSky, recorrendo ao serviço de armazenamento. 2. Escrever os metadados com o novo valor h no serviço de directorias. A operação de leitura, por sua vez, requer os seguintes passos: 1. Ler os metadados do ficheiro com o resumo criptográfico h, através do serviço de directorias. 2. Utilizar o serviço de armazenamento para ler a versão dos dados correspondentes a h através da operação readMatching do DepSky. Devido à utilização deste mecanismo, aliada com o facto do serviço de locks não permitir escritas concorrentes sobre o mesmo contentor de dados, o C2FS garante uma semântica de consistência regular [34] para o armazenamento de ficheiros assegurando que, aquando de uma operação de leitura concorrente a uma operação de escrita sobre os dados de um ficheiro, ou os dados obtidos são o valor anterior à escrita, ou são o valor que está a ser escrito. Capítulo 3. Metadados e Locks no C2FS 3.5 46 Considerações Finais Neste capítulo foi apresentado o C2FS em termos gerais, assim como os serviços de directorias e locks. Foram apresentadas várias versões do serviço de directorias, sendo descrito em cada uma o mecanismo utilizado para armazenar e manusear os metadados do C2FS. Sobre o serviço de locks, para além do modo de funcionamento, foram ainda apresentadas as garantias fornecidas pelo serviço. Foram também descritas as alterações necessárias no DepSpace para que fosse possível implementar os referidos serviços. Descrevemos ainda um mecanismo que permite melhorar as propriedades de consistência oferecidas pelas clouds de armazenamento utilizadas pelo C2FS. No próximo capítulo irá ser descrita a forma como estas ideias foram concretizadas. Capítulo 4 Concretização dos Serviços de Directorias e de Locks do C2FS Neste capítulo serão apresentados os detalhes de concretização do trabalho desenvolvido. Em primeiro lugar serão descritas as tecnologias utilizadas para a implementação dos módulos desenvolvidos. Em seguida será descrito o algoritmo utilizado para implementação da camada de suporte a triggers do DepSpace. Serão também apresentados alguns diagramas UML, nomeadamente o diagrama de classes e os diagramas de sequência das operações mais relevantes do serviço de directorias. 4.1 Considerações Gerais Todos os componentes dos serviços de directorias e de locks foram implementados na linguagem de programação JAVA. Esta escolha justifica-se com o facto de o DepSpace ter sido concretizado nesta linguagem de programação. Há ainda o facto de o serviço de armazenamento fazer uso do DepSky, também ele implementado em JAVA. Assim, esta escolha vai ao encontro de facilitar a integração de todos estes componentes. O primeiro serviço a ser concretizado foi o de locks. Após um estudo para encontrar um mecanismo que garantisse o acesso exclusivo a uma hipotética zona crítica por parte de vários processos concorrentes utilizando unicamente o DepSpace, foi então implementado este serviço já com a preocupação de fornecer uma interface que permitisse aos seus clientes reservar diferentes contentores de dados, sendo que um mesmo processo pode reservar mais que um contentor. Na prática, bastou apenas generalizar o mecanismo inicialmente estudado para este fornecer uma interface que permitisse o acesso exclusivo a várias zonas críticas (a reserva de vários contentores de dados). O segundo passo foi desenvolver o serviço de directorias sem cache. Aqui houve a preocupação de desenvolver uma interface genérica o suficiente para este serviço de tal forma que este pudesse ser utilizado para armazenar os metadados de outros sistemas de ficheiros que não o C2FS. 47 Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 48 Por questões de desempenho e de redução de custos, o passo seguinte foi desenvolver o serviço de directorias com cache. Para garantir eficiência no que diz respeito ao acesso aos metadados em cache, este serviço utiliza instâncias da classe HashMap do pacote java.util do JAVA para guardar estes metadados. No que diz respeito às tarefas de actualização, foi utilizado um objecto do tipo java.util.Timer que permite, de forma fácil, agendar a execução de cada tarefa de actualização para um momento no futuro. Por fim foram desenvolvidos o espaço de nomes pessoal e o serviço de directorias sem partilha de ficheiros. Tendo isto, podemos perceber que o serviço de directorias pode assumir vários modos de funcionamento, sendo eles: • NoCacheDirectoryService: O serviço de directorias não mantém metadados em cache permitindo, no entanto a partilha de ficheiros entre vários utilizadores. Neste caso, os metadados dos ficheiros pessoais de cada utilizador são mantidos no seu espaço de nomes pessoal. • DirectoryServiceWTempCache: O serviço mantém em cache os metadados recentemente utilizados, sendo possível configurar o tempo de validade dos mesmos (através do parâmetro ∆). Tal como no modo de funcionamento anterior, também neste caso é possível a partilha de ficheiros, sendo também os metadados dos ficheiros privados de cada cliente mantidos no espaço de nomes pessoal. Este modo de funcionamento tem um desempenho superior ao anterior. • NoShareDirectoryService: Neste caso, todos os metadados são mantidos em estruturas de dados locais, não fazendo uso do DepSpace [23], e assim, não permitindo a partilha de ficheiros. No entanto, este modo de funcionamento tem um desempenho significativamente superior quando comparado com os restantes. No que diz respeito à concretização, o serviço de directorias sem partilha de ficheiros e o espaço de nomes pessoal são muito similares. Ambos guardam todos os metadados em instâncias da classe HashMap, visto esta ser serializável e eficiente no que diz respeito ao tempo de acesso aos metadados, e disponibilizam sensivelmente os mesmos métodos (sendo que o serviço de directorias sem partilha de ficheiros respeita a interface do serviço de directorias). Na prática, a diferença essencial entre eles reside no facto de, enquanto que o armazenamento do espaço de nomes pessoal nas clouds é da responsabilidade do agente C2FS, no caso dos metadados do serviço de directorias sem partilha de ficheiros é o próprio serviço que serializa as suas estruturas e as armazena na cloud-of-clouds. Esta abordagem aparece com a necessidade de generalizar o código do agente C2FS pois, de acordo com a configuração do sistema de ficheiros, aquando da montagem do sistema de ficheiros é criada apenas uma instância de serviço de directorias, sendo apenas necessário garantir que não é usado o espaço de nomes pessoal quando não há partilha de ficheiros. Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS Classe LockService NoCacheDirectoryService DirectoryServiceWTempCache NoShareDirectoryService PrivareNamespace NodeMetadata FileStats PrivateNamespaceStats MetadataUpdaterTimerTask C2FSAgent Total 49 Núm. de Linhas de Código 39 234 264 228 36 279 221 30 77 988 2396 Tabela 4.1: Número de linhas de código dos módulos desenvolvidos. Assim, quando há partilha de ficheiros, o agente C2FS é responsável por, a cada alteração nos metadados do espaço de nomes pessoal, serializar todo o objecto e armazena-lo através do serviço de armazenamento, ao passo que, quando não há partilha de ficheiros, todos os metadados são armazenados no serviço de directorias, sendo este responsável por serializar e, recorrendo ao serviço de armazenamento, armazenar as suas estruturas de dados na cloud-of-clouds. A tabela 4.1 apresenta o número de linhas de código das várias classes dos referidos serviços assim como o número linhas da classe C2FSAgent, a classe onde é feita a integração dos serviços de armazenamento, locks e directorias do C2FS. Note-se que esta classe foi desenvolvida em parceria com o autor do serviço de armazenamento de dados do C2FS [40]. 4.2 Trigger de Substituição de Tuplos no DepSpace Como já referido anteriormente (secção 3.2.1), para permitir a atomicidade e aumentar o desempenho das operações de rename sobre nós do serviço de directorias do C2FS, foi necessária a adição de uma nova operação (replace) e de uma nova camada ao DepSpace, camada essa concretizada numa nova classe chamada ReplaceTriggerLayer. Basicamente, à excepção da operação replace, todas as operações do DepSpace são implementadas simplesmente reencaminhando a operação para as camadas superiores. No caso da operação replace, para alterar o campo “nó pai” de todos os filhos de uma directoria renomeada, é necessária a utilização de um procedimento recursivo. O algoritmo 6 apresenta o comportamento da operação replace na camada de Trigger. Neste algoritmo, são referidas as funções path, name e parent que, dado um tuplo de metadados devolvem o caminho do nó, o seu nome e o caminho do seu “nó pai”, respectivamente. Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 50 Há ainda a função setParent que permite alterar o valor do campo referente ao caminho do “nó pai” num tuplo de metadados. Algorithm 6: Concretização da operação replace na camada de trigger procedimento replace(template, tuple) 1 início 2 se (path(template) 6= path(tuple)) então 3 tupleT emplate ←− hN ODE, parent(tuple), name(tuple), ∗, ∗, ∗i; 4 inp(tupleT emplate); 5 retorna replaceN odeAndChildren(template, tuple); retorna upperLayer.replace(template, tuple); 6 fim 7 8 9 10 11 12 13 14 15 16 procedimento replaceNodeAndChildren(template, tuple) início result ←− upperLayer.replace(template, tuple); parent ←− path(template); childrenList ←− rdAll(hN ODE, parent, ∗, ∗, ∗, ∗i); para cada (child ∈ childrenList) faça templateN ew ←− hN ODE, parent, name(child), ∗, ∗, ∗i; parentN ew ←− parent(child); tupleN ew ←− child; tupleN ew.setP arent(parentN ew); replaceN odeAndChildren(templateN ew, tupleN ew); retorna result; 17 fim Como já referido, esta camada tem a função de permitir que, quando uma directoria é renomeada, o campo “nó pai” dos seus filhos seja actualizado com o seu novo caminho de forma atómica e eficiente. Para além disso, esta camada tem a função de, caso exista um nó no serviço de directorias com o mesmo caminho que o futuro caminho do nó renomeado, eliminar o seu tuplo de metadados do espaço de tuplos. Esta última particularidade pode ser vista nas linhas 3 e 4 do algoritmo. O procedimento replaceNodeAndChildren é responsável por actualizar os metadados dos “nós filhos” do nó renomeado. Em primeiro lugar, na linha 8 do algoritmo em descrição, é feita a substituição dos tuplos (através da chamada à operação replace da camada superior à ReplaceTriggerLayer no DepSpace). As seguintes linhas do algoritmo fazem a recursão deste procedimento, permitindo a actualização dos nós abaixo do nó renomeado na árvore de directorias. Para isso, são obtidos todos os nós filhos do nó renomeado (linha 10) através da chamada rdAll, e para cada um destes nós é construído um novo tuplo no qual o valor do campo “nó pai” é actualizado (linhas 14 e 15), sendo feita posteriormente a substituição destes tuplos e dos seus filhos através da chamada do corrente procedimento (linha 16). Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 4.3 51 Diagramas UML Nesta secção são apresentados alguns diagramas UML referentes ao trabalho desenvolvido. Serão apresentados um diagrama de classes dos componentes desenvolvidos e diagramas de sequência referentes às operações de obtenção, alteração e inserção de metadados no serviço de directorias com cache. 4.3.1 Diagrama de Classes A figura 4.1 apresenta o modelo de classes dos serviços de directorias e de locks. Neste diagrama podemos analisar em detalhe as várias ligações entre os componentes. A classe C2FSAgente concretiza o agente C2FS. Como podemos perceber, esta classe mantém uma instância de cada um dos seguintes componentes: DirectoryService, LockService, PrivateNamespace e PrivateNamespaceStats. No desenvolvimento deste componente houve a preocupação de permitir que, caso seja necessário desenvolver um novo serviço de directorias com um comportamento diferente, não seja necessário alterar todo o código do componente, bastando adequar o objecto instanciado no objecto do tipo DirectoryService de acordo com a configuração do sistema. Actualmente, como se pode perceber no diagrama, os objectos que podem ser instanciados são objectos do tipo NoCacheDirectoryService, DirectoryServiceWTempCache e NoShareDirectoryService. No caso do serviço de directorias com cache, concretizado na classe DirectoryServiceWTempCache, são mantidas duas Maps, uma com objectos do tipo MetadataCacheEntry, e outra com as tarefas de actualização a correr a cada instante, e ainda um objecto do tipo NoCacheDirectoryService. Na classe MetadataCacheEntry é mantido um objecto do tipo NodeMetadata e ainda um inteiro que indica o instante em que os metadados foram inseridos na cache. É na classe NodeMetadata que são mantidas todas as informações dos metadados de cada nó. Esta classe mantém um objecto do tipo FileStats com todos os valores dos metadados a ser utilizados localmente, ao passo que os restantes campos do objecto NodeMetadata são vocacionados a manter as informações relativas à partilha de ficheiros. A classe NodeMetadata fornece também o método getAsTuple que transforma o objecto de metadados num tuplo a guardar no DepSpace, respeitando o formato apresentado na secção 3.2.2. O campo node_metadata apresentado no referido formato é, na prática, uma instância da classe FileStats apresentada anteriormente. O facto de esta versão do serviço de directorias manter um objecto do serviço de directorias sem cache prende-se com o objectivo de delegar a responsabilidade da interacção com o DepSpace. Com esta decisão de desenho, a classe DirectoryServiceWTempCache é responsável apenas por gerir os metadados em cache, utilizando a classe NoCacheDirectoryService, para interagir com o DepSpace, manuseando os metadados no DepSpace. Uma outra coisa que se pode observar no diagrama é o facto de cada tarefa de actualização (classe MetadataUpdaterTimerTask) manter objectos do serviço de directorias com e Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 52 sem cache. Isto permite que a actualização dos metadados seja feita no DepSpace através da classe NoCacheDirectoryService e que, após isto, os metadados sejam removidos da cache na classe DirectoryServiceWTempCache (através da chamada do método removeFromCache desta classe). As classes PrivateNamespace e PrivateNamespaceStats concretizam o mecanismo de espaço de nomes pessoal. A classe PrivateNamespace é responsável de armazenar os metadados do espaço de nomes pessoal, enquanto que a classe PrivateNamespaceStats contém as informações relativas ao contentor de dados e resumo criptográfico do objecto PrivateNamespace armazenado na cloud-of-clouds. 4.3.2 Diagramas de Sequência As figuras 4.2, 4.3 e 4.4 representam diagramas de sequência que ilustram o fluxo de execução das operações de obtenção, inserção e alteração de metadados no serviço de directorias com cache. Nestes diagramas foi ignorado o lançamento de excepções com vista a simplificar a percepção da informação por eles representada. As excepções são lançadas sempre que, aquando de uma chamada ao DepSpace por parte do serviço de directorias sem cache, ocorre um problema de conexão com os servidores. Para além disto, é também lançada uma excepção quando o resultado obtido da execução de uma chamada ao DepSpace não cumpre a semântica dessa operação. Exemplos disso são a tentativa de inserir um tuplo de metadados referente um novo nó que não tem sucesso, o que significa que o nó já existe no serviço, ou no caso de não obter sucesso nas operações de busca e actualização de tuplos de metadados, o que significa que o nó não existe no sistema de ficheiros. Em seguida, serão descritos os referidos diagramas de sequência. Inserção de metadados. A figura 4.2 apresenta o diagrama de sequência da operação de inserção de metadados no serviço de directorias com cache. Nesta operação, o cliente é responsável por criar o objecto do tipo NodeMetada com os metadados a guardar. Em primeiro lugar, é utilizado o objecto do serviço de directorias sem cache para inserir os metadados no DepSpace. Embora o diagrama referido não apresente este nível de detalhe, para obter o tuplo de metadados referente ao objecto NodeMetadata a inserir, basta utilizar o método getAsTuple desta classe. Em seguida, o objecto NodeMetadata referente aos metadados inseridos, é guardado no Map de metadados em cache. É também criada e guardada no respectivo Map a tarefa de actualização referente aos metadados do nó inserido no serviço. Obtenção de metadados. Para obter os metadados de um nó, o agente C2FS chama a operação getMetadata do serviço de directorias fornecendo o caminho do nó desejado. A figura 4.3 ilustra o fluxo de execução desta operação. O primeiro passo a fazer é perceber se os metadados desse nó estão guardados em cache. Caso isto se verifique, os metadados em cache são utilizados, caso contrário, os Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS Figura 4.1: Diagrama de classes dos serviços de directorias e locks. 53 Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 54 Figura 4.2: Diagrama de sequência de uma operação inserção de metadados metadados são obtidos do DepSpace recorrendo ao objecto NoCacheDirectoryService. É neste ponto que é verificada a existência do nó cujos metadados são para obter. Caso a operação rdp feita ao DepSpace não retorne nenhum resultado, é lançada uma excepção. Caso o nó exista, é então construído o objecto NodeMetadata que representa os metadados obtidos. Os metadados obtidos são então guardados em cache através da inserção dos mesmos num Map que mantém todos os objectos NodeMetadata em cache. Por fim, é necessário verificar se existem modificações nos metadados guardados localmente (à espera de serem propagados para o DepSpace) referentes ao contentor de dados do nó em questão. Os valores do resumo criptográfico (hash) e o tamanho dos dados são então actualizados no objecto FileStats dos metadados a devolver com os valores guardados localmente. Actualização de metadados. O fluxo de execução aquando de uma operação de actualização de metadados é apresentado na figura 4.4. Nesta operação, o primeiro passo a ser feito pelo serviço de directorias com cache é certificar-se de que os metadados a serem alterados são mantidos em cache. A chamada da operação getMetadata (descrita acima) garante isso. Após a obtenção dos metadados, caso não exista ainda nenhuma tarefa de actualização para estes, é necessário lançar uma tarefa deste tipo. É então construída uma nova tarefa que é inserida na Map de tarefas em execução, sendo depois agendada para execução através do objecto do tipo Timer. Para facilitar a compreensão deste diagrama, este objecto foi ignorado, sendo o agendamento da tarefa representada com a chamada run(DELTA) sobre a instância upTask da classe UpdaterTask. Após isto, é necessário perceber se a operação em curso tem como objectivo renomear um nó. Caso isto se verifique, são feitas uma sequência de operações (já descritas na secção 3.2.3), nomeadamente a gestão das tarefas de actualização em curso e das actualizações dos metadados locais, para garantir o correcto funcionamento desta operação. Caso a operação em curso não tenha por objectivo a alteração do caminho de um nó, os metadados são alterados apenas na cache através da remoção dos antigos metadados e inserção dos novos no Map que mantém os metadados em cache. Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS Figura 4.3: Diagrama de sequência de uma operação de obtenção de metadados. 55 Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS Figura 4.4: Diagrama de sequência de uma operação de actualização de metadados. 56 Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 4.3.3 57 Considerações Finais Nesta secção foram descritos os detalhes de concretização dos serviços de directorias e de locks. Foram explicadas as decisões de desenho para a implementação destes serviços, tal como a interacção entre os vários componentes dos mesmos. Na próxima secção será apresentada uma avaliação experimental dos mesmos serviços, sendo avaliado desempenho de cada operação fornecida por estes. Capítulo 4. Concretização dos Serviços de Directorias e de Locks do C2FS 58 Capítulo 5 Avaliação Experimental Neste capítulo é apresentada uma avaliação do desempenho do serviço de locks e de diferentes versões do serviço de directorias, com e sem partilha de ficheiros. Em primeiro lugar será apresentado um estudo sobre o número de operações de metadados feitas pelos vários benchmarks. Em seguida serão mostradas medições feitas sobre as operações do DepSpace usadas pelos serviços desenvolvidos, de forma a perceber de que forma é que a latência destas operações condiciona o seu desempenho. É também feita uma comparação entre a latência média da operação de obtenção de metadados (getMetadata) e a operação rdp do DepSpace, utilizando o serviço de directoria com diferentes valores para o parâmetro ∆. Serão apresentados também o tempo de execução de alguns benchmarks aplicados ao C2FS e ainda o tempo de execução de algumas chamadas feitas ao sistema de ficheiros por esses benchmarks, tendo estes experimentos sido efectuados, novamente, com diferentes valores para o parâmetro ∆. Será por fim apresentado um estudo ao desempenho do sistema na presença de diferentes percentagens de ficheiros pessoais. 5.1 Metodologia As medições apresentadas neste capítulo foram obtidas através da execução de alguns benchmarks sobre o sistema de ficheiros. Os benchmarks utilizados foram: o PostMark [33], que simula um servidor de e-mail; e o Filebench [7], que permite exercitar vários workloads sobre um sistema de ficheiros. A escolha destes dois benchmarks devese ao facto de ambos serem adequados para testar o desempenho dos metadados de um sistema de ficheiros [49]. Na utilização do Filebench, foram utilizados três workloads para testar os metadados do sistema: o file server, o create files e o copy files. O file server simula um servidor de ficheiros, criando, eliminando e operando sobre vários ficheiros. Os workloads create files e copy files têm como função a criação de ficheiros no sistema de ficheiros. A escolha 59 Capítulo 5. Avaliação Experimental 60 destes workloads deve-se ao facto de as aplicações desktop dos dias de hoje fazerem um uso assinalável de ficheiros temporários [30], sendo, portanto, importante o desempenho do sistema de ficheiros na criação, cópia e eliminação de ficheiros. Os benchmarks utilizados foram configurados da seguinte forma: • O PostMark foi configurado para operar sobre 500 ficheiros, com tamanhos compreendidos entre os 500 bytes e os 9.77KB. • O workload file server, por sua vez, foi configurado para manter três tarefas a operar sobre 1000 ficheiros, com tamanho de aproximadamente 128KB, aleatoriamente organizados numa árvore de directorias com uma profundidade média de cinco nós. • No workload create files são utilizadas duas tarefas para criar 1000 ficheiros de aproximadamente 16KB cada, organizados numa árvores de directorias com uma profundidade de aproximadamente cinco nós. Por fim, o workload copy files cria uma cópia de uma árvore de directorias com uma profundidade aproximada de 20 nós, com 1000 ficheiros de aproximadamente 16KB no sistema de ficheiros. A utilização de ficheiros de tamanho tão baixo prende-se com o facto de o foco deste trabalho ser o desempenho do sistema para diferentes configurações do serviço utilizado para armazenar os seus metadados. Desta forma, foram utilizados ficheiros de pequenas dimensões de forma a minimizar o tempo gasto na execução dos benchmarks. Na execução destas experiências, as réplicas do DepSpace utilizadas pelo serviço de directorias estavam instaladas no Amazon EC2 em máquinas virtuais de configuração standard, instaladas na zona de disponibilidade da Europa (Irlanda). O sistema de ficheiros estava montado num computador portátil com aproximadamente 2 anos localizado em Lisboa, utilizando um serviço de internet com ligação de 24.66 Mbps de download e 5.16 Mbps de upload1 . Todos os resultados apresentados resultam da média dos valores obtidos de aproximadamente dez execuções dos experimentos. 5.2 Número de Operações sobre os Metadados A tabela 5.1 mostra o número de chamadas de sistema, que resultam na leitura, escrita ou actualização de metadados efectuadas por cada um dos benchmarks anteriormente descritos. Note-se que visto que os benchmarks utilizados simulam o comportamento de aplicações reais, podemos perceber que as chamadas feitas por estas serão da mesma ordem que as apresentadas. 1 Valores obtidos do site www.speedtest.net, medindo o débito da ligação entre a localização do cliente (Lisboa) e um servidor na Irlanda (localização onde as réplicas do DepSpace estavam instaladas) 61 Capítulo 5. Avaliação Experimental Operação stat flush mknod unlink mkdir Total PostMark FileServer CreateFiles CopyFiles 2896 50240 3804 8790 1264 15433 1000 3001 764 5683 1000 2000 764 0 0 0 0 226 226 113 5688 71582 6030 13904 Total 65730 20698 9447 764 565 97204 Percent. 67.6% 21.3% 9.7% 0.8% 0.6% 100% Tabela 5.1: Número de operações do sistema de ficheiros chamadas pelos benchmarks. Como podemos ver na tabela, a operação do sistema de ficheiros stat é a operação que mais vezes é chamada (com 67.6% da totalidade de operações). Como podemos perceber também, nos benchmarks executados, a operação flush é também uma operação muito chamada. Tal como anteriormente referido, é importante perceber qual o desempenho do sistema no que diz respeito à criação de ficheiros, visto esta ser uma operação muito comum nas aplicações desktop dos dias de hoje [30]. Como podemos ver na tabela 5.1, a operação mknod (operação que cria um novo ficheiro) é uma das operações mais chamadas pelos nossos benchmarks. 5.3 Desempenho dos Serviços de Directorias e Locks Na figura 5.1 são apresentadas as latências médias observadas para as várias operações do DepSpace utilizadas pelos serviços mencionados. Os dados apresentados foram obtidos a partir da medição do tempo de execução de cada uma das operações aquando da execução dos benchmarks ou, visto haver operações que são menos exercitadas que outras, as operações rdAll e replace foram também exercitadas explicitamente. No total, cada uma das operações foi executada aproximadamente 30000 vezes. Como podemos ver na figura, a latência mais baixa é a das operações rdp sendo estas da ordem dos 63 ms. As operações de inp e cas, utilizadas para remover e inserir tuplos de metadados, apresentam latências na ordem dos 66ms. Por sua vez a operação rdAll tem uma latência média de 75 ms enquanto que a operação replace demora em média 87 ms. Com isto podemos perceber que em média, as operações de leitura de metadados, mesmo não usando cache são as mais rápidas, enquanto que as operações de actualização de metadados, embora com uma diferença pouco assinalável, são as que mais tempo demoram. Note-se também que as operações cas e inp são utilizadas pelo serviço de locks para inserir e remover tuplos de lock, respectivamente. Segundo estes experimentos, a obtenção e destruição de um lock demora então, em média, 66 ms por operação. A razão que leva a operação rdp a ser a que menos latência apresenta prende-se com Capítulo 5. Avaliação Experimental 62 Figura 5.1: Latência das operações do DepSpace. o facto de, na maioria das vezes, não ser necessário executar o protocolo de consenso distribuído para a sua execução [23]. Como podemos ver na figura, as operações inp e cas tem uma latência comparável à operação rdp. Isto acontece pois, visto as réplicas do DepSpace estarem todas instaladas em máquinas virtuais de uma mesma zona de disponibilidade do Amazon EC2, a comunicação entre estas aquando do protocolo de consenso é feita usando a rede interna do provedor do serviço, não resultando a execução do protocolo num aumento significativo da latência das referidas operações. A latência média observada na operação rdAll justificam-se com o facto de, embora (na maioria das vezes) não seja também necessária a execução do protocolo de consenso, a quantidade de dados lidos nesta operação ser significativamente maior que na operação rdp. Por outro lado, o valor médio da latência observado na operação replace justifica-se com o facto de, para além ser sempre executado o protocolo de consenso para ordenar a sua execução nas réplicas do DepSpace, esta operação pode activar o Trigger de substituição de tuplos (ver secção 4.2). Latência das Operações rdp e getMetadata Na figura 5.2 é apresentada a diferença existente entre a latência média das operações rdp do DepSpace e getMetadata do serviço de directorias com cache. Aqui podemos perceber a eficiência da operação getMetadata para diferentes valores de ∆ e, assim, perceber de que forma é que este valor melhora o desempenho desta operação. Estes valores, ao contrário dos apresentados na figura 5.1, foram obtidos tendo em conta apenas valores de latência medidos na execução dos benchmarks anteriormente descritos sobre o sistema. Assim, os valores apresentados são a média dos valores obtidos de dez execuções de cada benchmarks, utilizando o serviço de directorias com cache com os valores 0, 100, 150 e 500 ms para o parâmetro ∆. O valor 0 foi escolhido para testar o comportamento Capítulo 5. Avaliação Experimental 63 do serviço sem a utilização de cache. A escolha dos valores 100 e 150 pretende testar o comportamento do serviço quando os metadados são mantidos em cache por um tempo aproximado à latência das operações do DepSpace no pior caso. O valor 500 foi escolhido com o objectivo de perceber até que ponto a subida de ∆ influencia o desempenho do serviço. Figura 5.2: Latência da obtenção de metadados. Como podemos observar na figura 5.2, quando o valor de ∆ é 0, não existem ganhos de latência da utilização do serviço, sendo a latência média das operações getMetadata igual à das operações rdp no DepSpace. Por outro lado, sempre que é utilizada cache no serviço de directorias, a latência na obtenção de metadados passa a cerca de metade da latência das operações rdp. Observa-se também que, com o aumento do valor de ∆ (e assim o aumento do tempo em que os metadados permanecem válidos em cache), existem pequenas melhorias no valor da latência média da operação getMetadata quando comparado com o mesmo valor para a operação de leitura do DepSpace. Através da análise da figura podemos também perceber que os ganhos de desempenho da operação getMetadata não são proporcionais à subida do valor de ∆. Isto é facilmente perceptível, por exemplo, verificando as latências médias desta operação com ∆ = 100 e ∆ = 500. Neste caso, sendo o valor de ∆ cinco vezes superior, enquanto que a latência média para ∆ = 100 é aproximadamente 50% menor que latência média da operação rdp, para ∆ = 500 existe um ganho de apenas 56.5%. Assim podemos concluir que, para obter importantes ganhos de desempenho, o valor do parâmetro ∆ deve ser maior que zero, mas não demasiado grande. Embora com a subida deste valor sejam observadas melhorias no desempenho da operação getMetadata, este aumento leva também a uma diminuição da coerência dos metadados mantidos no DepSpace. É então importante que este factor seja tido em conta na escolha do valor deste parâmetro. Capítulo 5. Avaliação Experimental 64 Latência das Operações do C2FS e Tempo de Execução dos Benchmarks As figuras 5.3 e 5.4 apresentam, respectivamente, a latência média de várias operações do sistema de ficheiros e o tempo de execução dos benchmarks para diferentes valores do parâmetro ∆. A figura 5.3 apresenta a latência média de algumas operações do sistema relacionadas com os metadados. Os valores apresentados nesta figura foram obtidos através da execução sobre o C2FS do workload do Filebench que simula um servidor de ficheiros. Cada valor resulta da média dos oito melhores valores obtidos de dez execuções. Note-se, antes de mais, que cada uma destas operações (com a excepção da operação close) inclui uma ou mais obtenções de metadados dos ficheiros operados, resultando a melhoria do desempenho da operação getMetadata numa melhoria das mesmas. Note-se ainda que a operação open, para além de obter os metadados do ficheiro a abrir, nos casos em que este é aberto para escrita, implica também a aquisição de um lock sobre o seu contentor de dados. É também necessário ter em conta que é na operação close que os dados são escritos para as clouds, logo, é necessário actualizar os metadados (através da chamada à operação updateLocalMetadata do serviço de directorias). Figura 5.3: Latência das operações do sistema de ficheiros. Como podemos ver, também para estes experimentos, o aumento do valor de ∆ representa sempre um aumento do desempenho. Em todas as operações, tal como anteriormente observado, a utilização de cache de metadados representa a diminuição da latência das mesmas para cerca de metade. Uma excepção é a operação close. Este comportamento justifica-se com o facto de, neste operação, não haver necessidade de obter os metadados do ficheiro que se pretende fechar. É também importante observar que, também neste experimento se verifica que a diminuição da latência não é proporcional ao aumento do valor do parâmetro ∆. Na figura 5.4 é apresentado o tempo de execução médio do PostMark e dos workloads Capítulo 5. Avaliação Experimental 65 copy files e create files do Filebench para diferentes valores de ∆. Tal como no caso da figura anterior, os resultado aqui apresentados resultam da média dos oito melhores valores obtidos de dez execuções. Figura 5.4: Tempo de execução de benchmarks. Tal como anteriormente, também nesta figura podemos verificar que a utilização de cache de metadados representa um aumento do desempenho do serviço de directorias, e assim, o desempenho global do C2FS. Em todas as execuções, o desempenho aumenta com o crescimento do valor do parâmetro ∆. Podemos ver que, com ∆ = 100, temos tempos de execução aproximadamente 50% menores que para ∆ = 0 (48% para o PostMark, 43% e 52% para os workloads create files e copy files, respectivamente). Com o aumento do valor de ∆ continuam a existir ganhos no desempenho do sistema, sendo estes, no entanto, mais modestos. As melhorias com o aumento do tempo de validade dos metadados em cache de 100 para 500, no caso dos tempos de execução do PostMark e do workload copy files são de apenas 10.1% e 13.2%, respectivamente. No caso do workload create files, para os mesmos valores de ∆, temos ganhos bastante nos tempos médios de execução (na ordem dos 25%). 5.4 Desempenho do Serviço de Directorias sem Partilha de Ficheiros A utilização do C2FS sem partilha de ficheiros permite aos utilizadores tirar partido da fiabilidade de armazenamento fornecida pelo DepSky [24] com uma interface de sistema de ficheiros, não prejudicando o desempenho do sistema com a necessidade de utilizar o DepSpace [23] para armazenar os metadados. Esta configuração assemelha-se ao modo de funcionamento do BlueSky [52] ou do S3QL [19], tendo no entanto melhores garantias de tolerância a faltas. 66 Capítulo 5. Avaliação Experimental A figura 5.5 apresenta o tempo de execução dos benchmarks já apresentados nas figuras anteriores e a latências das operações stat, create, delete, open e close sobre o sistema de ficheiros. Os valores apresentados resultam da média dos oito melhores resultados de dez execuções. (a) Tempo de execução de benchmarks sem partilha. (b) Latência das operações do C2FS sem partilha. Figura 5.5: Latências de operações sobre o C2FS e tempos de execução dos benchmarks usando o serviço de directorias sem partilha. Como podemos ver na figura 5.5(a), os tempos de execução dos benchmarks no C2FS utilizando o serviço de directorias são em muito inferiores ao melhor tempo observado no C2FS com partilha de ficheiros (figura 5.4). O tempo de execução do PostMark diminui de 242 para 9 segundos, enquanto que nos workloads create files e copy files diminui de 299 para 20 segundos e de 446 para 29 segundos, respectivamente. No que diz respeito à latência das operações do sistema de ficheiros, também são observadas melhorias de desempenho muito assinaláveis, diminuindo a latência média das operações stat, create, delete, open e close de 249, 629, 354, 286 e 100 ms/operação (no melhor caso) para 9, 26, 37, 17 e 8 ms/operação. 5.5 Desempenho com a utilização do Espaço de Nomes Pessoal A utilização de um espaço de nomes pessoal, armazenado na cloud-of-clouds, onde são mantidos os metadados de todos os ficheiros privados de cada cliente, para além de permitir a diminuição da quantidade de informação armazenada no DepSpace, permite também um aumento do desempenho do sistema. A figura 5.6 apresenta a latência de algumas operações do sistema e o tempo de execução do PostMark e dos workloads de criação e cópia de um conjunto de ficheiros, sendo efectuados experimentos com diferentes percentagens de ficheiros pessoais. Para Capítulo 5. Avaliação Experimental 67 armazenar os ficheiros partilhados, em todos os experimentos foi utilizado o serviço de directorias com cache (com ∆ = 150). Tal como nos experimentos anteriormente apresentados, os resultados presentes nesta figura resultam da média aritmética dos oito melhores resultados obtidos de dez execuções. (a) Tempo de execução de benchmarks com ficheiros pessoais. (b) Latência das operações do C2FS com ficheiros pessoais. Figura 5.6: Latências de operações sobre o C2FS e tempos de execução dos benchmarks com ficheiros pessoais. Em ambos os gráficos da figura podemos perceber que basta que uma pequena parte dos ficheiros sejam pessoais para que o desempenho do sistema aumente significativamente. Podemos perceber também que, embora com o crescimento da percentagem de ficheiros pessoais o desempenho do sistema também aumente, este crescimento não é proporcional. À primeira vista, se imaginarmos uma utilização em que todos os ficheiros do sistema são pessoais, poderíamos pensar que o desempenho deste seria equivalente à utilização do sistema sem partilha de ficheiros, o que não acontece na realidade. Isto deve-se ao facto de, por exemplo, na criação de ficheiros, mesmo sendo estes privados, ser necessário, em primeiro lugar, efectuar uma operação getMetadata no serviço de directorias para garantir que não existe nenhum ficheiro no sistema com o nome do novo ficheiro. Esta diferença pode ser observada comparando os resultados de latência e tempo de execução com 100% de ficheiros pessoais presentes nas figuras 5.6(a) e 5.6(b) com os resultados apresentados nas figuras 5.5(a) e 5.5(b). Podemos então observar que, no caso do tempo de execução dos benchmarks, o C2FS sem partilha de ficheiros apresenta valores cerca de seis vezes inferiores no caso das execuçoes do workload create files e do PostMark, e cerca de três vezes inferiores no caso do workload copy files. No caso das operações do C2FS, podemos perceber que, com a excepção da operação open (que tem um desempenho claramente superior no C2FS sem partilha de ficheiros), todas as restantes operações, têm um desempenho similar. Capítulo 5. Avaliação Experimental 5.6 68 Considerações Finais Neste capítulo foi apresentada a avaliação experimental feita às versões com e sem partilha de ficheiros do serviço de directorias e à utilização do espaço de nomes pessoal. Aqui, foram estudadas as latências médias das várias operações do DepSpace utilizadas pelos serviços de directorias e de locks, o desempenho de algumas operações do sistema de ficheiros que operam sobre os metadados e ainda o tempo de execução de alguns benchmarks, para diferentes configurações do sistema. Neste capítulo demonstrou-se que a utilização de uma cache de metadados temporária permite obter ganhos bastante assinaláveis de desempenho, não sendo o aumento do desempenho proporcional ao aumento do tempo de validade dos metadados em cache. Verificou-se também que, para além de diminuir a quantidade de informação armazenada no DepSpace, a utilização do espaço de nomes pessoal permite ainda grandes ganhos de desempenho. Capítulo 6 Conclusão O C2FS é um sistema de ficheiros multi-utilizador com uma interface estilo-POSIX, que permite o armazenamento de dados em várias clouds, e ainda tolera falhas por parte dos clientes e provedores de armazenamento nas clouds. Neste trabalho, para além da arquitectura geral do C2FS, foram apresentadas em detalhe as várias versões do serviço de directorias, utilizadas para gerir os metadados e efectuar controlo de acesso aos ficheiros. A primeira versão apresentada permite a partilha de ficheiros entre vários utilizadores, não fazendo, no entanto, uso de cache para aumentar o desempenho do serviço. Em seguida foi apresentado o serviço de directorias que, para além de permitir a partilha de ficheiros, faz uso da cache para aumentar o desempenho do serviço (em especial das leituras de metadados). Foi também descrito o serviço de directorias sem partilha de ficheiros, uma versão que permite tirar partido das vantagens inerentes ao armazenamento dos dados na cloud-of-clouds sem que o desempenho do serviço de directorias seja prejudicado com a latência da rede. Para aumentar o desempenho das versões do serviço de directorias com partilha de ficheiros, foi apresentado o conceito de espaço de nomes pessoal, um mecanismo que permite, ao mesmo tempo, aumentar o desempenho do manuseamento de metadados de ficheiros não partilhados e reduzir a quantidade de informação armazenada pelo serviço. Todas as versões do serviço de directorias descritas acima fornecem garantias de integridade e confidencialidade para os metadados. As versões deste serviço que permitem a partilha de ficheiros, para além das garantias já referidas, garantem ainda a disponibilidade dos metadados armazenados, através da utilização de um serviço de coordenação tolerante a faltas bizantinas [23]. Foi ainda apresentado um serviço de trincos, utilizado para coordenar o acesso concorrente aos contentores de dados dos ficheiros por parte de diferentes processos escritores. Por fim, foi apresentado um mecanismo que, através da interacção entre os serviços de directorias e armazenamento [40] do C2FS, permite ao sistema garantir consistência forte dos dados armazenados na cloud-of-clouds. Os resultados reportados numa avaliação experimental aos serviços de directorias e 69 Capítulo 6. Conclusão 70 trincos do C2FS mostram que os referidos serviços têm um desempenho aceitável para certos workloads comuns como servidores de ficheiros ou servidores de e-mail. 6.1 Trabalho futuro Actualmente, todos os utilizadores do C2FS têm de partilhar as contas de utilizador dos provedores de armazenamento utilizados para armazenar os dados dos ficheiros do sistema. Neste cenário, cada utilizador do sistema está apto a obter qualquer contentor de dados a partir do DepSky, sendo da responsabilidade do serviço de directorias manter privada aos utilizadores não autorizados a chave necessária para decifrar os dados. Esta abordagem é apenas útil, e.g., num modelo empresarial no qual a organização fica encarregue dos encargos relacionados com o armazenamento dos dados partilhados entre os seus colaboradores. No entanto, esta abordagem deixa de fazer sentido quando o sistema é utilizado por vários utilizadores comuns pois, neste caso, os custos inerentes à utilização dos vários provedores de armazenamento nas clouds por parte dos vários utilizadores ficariam ao encargo de apenas uma pessoa. Para resolver este problema, uma das tarefas futuras é desenvolver uma nova versão do serviço de directorias que permita a partilha de ficheiros armazenados em diferentes contas de utilizador nas clouds de armazenamento, desenvolvendo também um novo mecanismo de controlo de acesso aos ficheiros para esta versão. Há ainda a necessidade de avaliar o desempenho do sistema na presença de faltas ou ainda o desempenho do mecanismo que permite ao C2FS fornecer uma semântica de consistência forte, aquando da presença de dados inconsistentes nas clouds. Apêndice A Prova Informal do Serviço de Trincos O serviço de trinco apresentado deve garantir certas propriedades de correcção. Desta forma, as seguintes garantias devem ser fornecidas: Safety 1 (S1) Existe no máximo um processo com um trinco sobre um contentor de dados. Safety 2 (S2) A menos que o detentor de um trinco o queira, nenhum trinco fica inválido antes do seu tempo de validade expirar. Liveness 1 (L1) Quando nenhum processo detém o trinco sobre um contentor, se um processo tentar adquirir esse trinco, este consegue. Liveness 2 (L2) Quando um processo detentor de um trinco falha, eventualmente, o contentor reservado por esse trinco é libertado. A propriedade S1 tem por objectivo garantir que o serviço faz uma correcta gestão das reservas de contentores de dados. Por outro lado, sem a propriedade L1, uma forma de garantir que nunca existem dois processos com o trinco sobre o mesmo contentor seria, por exemplo, não permitir que nenhum processo obtivesse trincos sobre quaisquer contentores, deixando o serviço de ter qualquer utilidade. Estas duas propriedades são as propriedades fundamentais de um serviço de trincos. A segunda propriedade de safety permite garantir que, após a obtenção de um trinco por parte de um cliente e antes do seu tempo de validade expirar, o cliente mantém acesso exclusivo de escrita a um contentor. Por outro lado, a segunda propriedade de liveness tem por objectivo garantir que, na presença de faltas por parte dos clientes, nunca existirão contentores reservados eternamente, impossíveis de usar por clientes correctos. Assumindo um conjunto de processos que falham apenas por paragem (ver secção 3.1.2), pretende-se então provar de forma informal que o serviço de trinco do C2FS cumpre estas propriedades de correcção: 71 Apêndice A. Prova Informal do Serviço de Trincos 72 S1. Como já referido anteriormente, a operação do serviço de trinco que permite aos clientes adquirir um trinco sobre um dado contentor de dados é a operação tryAquire, representando o sucesso desta operação a obtenção de um trinco por parte do cliente invocador da operação. Esta operação tenta inserir um tuplo no espaço de tuplos através da chamada cas do DepSpace. Como podemos ver no algoritmo 5, o template fornecido nesta chamada é igual ao tuplo a inserir, contendo ambos um identificador estático referente ao tipo de tuplo (LOCK) e o identificador do contentor a reservar. Tendo em conta que a operação de aquisição de um trinco só tem sucesso se o serviço conseguir inserir o tuplo de trinco no espaço, aliado com o facto de a semântica da operação cas do DepSpace só inserir o tuplo caso não haja nenhum tuplo no espaço que faça correspondência com o template dado, podemos comprovar que a operação só tem sucesso se não existir nenhum outro tuplo no espaço com os mesmos campos, ou seja, com o mesmo identificador do contentor de dados. Assim, prova-se que, caso um cliente queira adquirir um trinco sobre um contentor de dados já reservado por um outro cliente (que conseguiu inserir o tuplo de trinco referente a esse contentor), a operação não irá ter sucesso, pois o seu tuplo não conseguirá ser inserido, garantindo que nunca existirão dois processos com um trinco sobre o mesmo contentor. S2. O tuplo de trinco que é inserido no DepSpace, e que é utilizado para reservar um contentor de dados, é um tuplo temporário. Aquando da chamada da operação tryAquire por parte de um cliente, é fornecido o parâmetro time, que específica a quantidade de tempo que o tuplo de trinco deve permanecer no espaço. Este tuplo é também configurado com permissões de escrita apenas para o seu dono, ou seja, para o serviço de trinco que o insere. Tendo em conta que o DepSpace garante que este tuplo não desaparece do espaço de tuplos antes do seu tempo de validade (time) expirar, aliado com o facto de nenhum cliente malicioso estar apto a remover o mesmo tuplo, podemos garantir que, enquanto o tuplo for válido, ele é mantido no espaço. Assim, estando um determinado trinco válido apenas se o seu tuplo de trinco se encontra no espaço de tuplos, podemos provar que um trinco nunca fica inválido antes do seu tempo de validade expirar, a menos que o ser detentor o queira. L1. Como explicado na prova anterior, os tuplos de trinco inseridos no DepSpace são tuplos temporários. Assim, em caso de falha no cliente que detém o trinco (não permitindo que este possa renovar o tempo de validade deste tuplo), o tuplo irá desaparecer do espaço de tuplos após time ms. Desta forma, prova-se que, caso o cliente detentor de um trinco falhe, o contentor de dados associado a este trinco acaba por ser libertado pois o tuplo de trinco utilizado para reservar esse contentor desaparece do espaço após um determinado tempo, deixando o contentor livre para ser acedido por outro cliente. Apêndice A. Prova Informal do Serviço de Trincos 73 L2. Como anteriormente explicado, para um cliente obter um trinco sobre um determinado contentor de dados basta ter sucesso na execução da operação tryAquire do serviço de trinco, dando como argumento o identificador desse contentor. Assim, visto que o sucesso desta operação depende da inserção do tuplo de trinco no espaço, caso não exista um tuplo de trinco para o referido contentor (o que significa que este pode ser acedido), a inserção deste tuplo tem sucesso. Prova-se portanto que, se for feita uma operação de aquisição de trinco sobre um dado contentor não reservado por parte de um cliente, este tem sucesso na operação cas e, consequentemente, na obtenção do trinco. Bibliografia [1] Amazon Elastic Block Store. http://aws.amazon.com/ebs/. [2] Amazon Elastic Compute Cloud. http://aws.amazon.com/pt/ec2/. [3] Amazon ElastiCache. http://aws.amazon.com/elasticache/. [4] Amazon Simple Storage Service. http://aws.amazon.com/s3/. [5] Apple iCloud. http://www.apple.com/icloud/. [6] DropBox. https://dropbox.com. [7] Filebench. http://sourceforge.net/apps/mediawiki/filebench. [8] FUSE. http://fuse.sourceforge.net/. [9] FUSE-J. http://fuse-j.sourceforge.net/. [10] Google App Engine. https://appengine.google.com. [11] Google Cloud Storage. https://developers.google.com/storage/. [12] GoogleDrive. https://drive.google.com/. [13] Microsoft Windows Azure. http://www.windowsazure.com/. [14] OpenStack Storage. http://www.openstack.org/software/openstack-storage/. [15] PlanetLab Europe web site. http://www.planet-lab.eu/. [16] POSIX. http://en.wikipedia.org/wiki/POSIX. [17] Project TCLOUDS - trustworthy clouds - privacy and resilience for internet-scale critical infrastructure. http://www.tclouds-project.eu/. [18] S3FS. http://code.google.com/p/s3fs/. [19] S3QL. http://code.google.com/p/s3ql/. [20] Tuple space. http://en.wikipedia.org/wiki/Tuple_space. 75 Bibliografia 76 [21] Hussam Abu-Libdeh, Lonnie Princehouse, and Hakim Weatherspoon. RACS: Redundant Array of Cloud Storage. In ACM Symposium on Cloud Computing (SOCC), June 2010. [22] A. Adya, W. J. Bolosky, M. Castro, R. Chaiken, G. Cermak, J. R. Douceur, J. Howell, J. R. Lorch, M. Theimer, and R. P. Warrenhofer. Farsite: Federated, available, and reliable storage for an incompletely trusted environment. In 5th OSDI. Dec 2002. [23] Alysson N. Bessani, Eduardo P. Alchieri, Miguel Correia, and Joni S. Fraga. DepSpace: a Byzantine fault-tolerant coordination service. In Proc. of the 3rd ACM European Systems Conference – EuroSys’08, pages 163–176, April 2008. [24] Alysson N. Bessani, Miguel Correia, Bruno Quaresma, Fernando Andre, and Paulo Sousa. DepSky: Dependable and Secure Storage in cloud-of-clouds. In Proc. of the 3rd ACM European Systems Conference – EuroSys’11, April 2011. [25] Alysson Neves Bessani, Miguel Correia, Joni da Silva Fraga, and Lau Cheuk Lung. Sharing Memory between Byzantine Processes using Policy-Enforced Tuple Spaces. In IEEE Transactions on Parallel and Distributed Systems. Vol. 20 no. 3. pages 41943, IEEE Computer Society, March 2009. [26] Mike Burrows. The Chubby Lock Service. In Proceedings of 7th Symposium on Operating Systems Design and Implementation – OSDI 2006, November 2006. [27] John R. Douceur, Atul Adya, Josh Benaloh, William J. Bolosky, and Gideon Yuval. A Secure Directory Service based on Exclusive Encryption. In Proceedings of the 18th Annual Computer Security Applications Conference (ACSAC), December 2002. [28] Jonh R. Douceur and Jon Howell. Distributed directory service in farsite file system. In Proceedings of the 7th USENIX Symposium on Operating Systems Design and Implementation. OSDI’06, pages 321-333, 2006. USENIX Association. [29] S. Ghemawat, H. Gobioff, and S. Leung. The Google file system. In 19th SOSP. pages 29-43, December, 2003. [30] Tyler Harter, Chris Dragga, Michael Vaughn, Andrea C. Arpaci-Dusseau, and Remzi H. Arpaci-Dusseau. A File is Not a File: Understanding the I/O Behavior of apple desktop applications. In Proceedings of the 23rd ACM Symposium on Operating Systems Principles – SOSP’11, October 2011. [31] J. H. Howard, M. L. Kazar, Menees S. G., D. N. Nichols, M. Satyanarayanan, R. N. Sidebotham, and M. J. West. Scale and performance in a distributed file system. In ACM Trans. Comput. Syst. vol. 6, no. I, February 1988. Bibliografia 77 [32] Patrick Hunt, Mahadev Konar, Flavio Junqueira, and Benjamin Reed. Zookeeper: Wait-free Coordination for Internet-scale Services. In Proc. of the USENIX Annual Technical Conference – ATC 2010, pages 145–158, June 2010. [33] Jeffrey Katcher. PostMark: A New File System Benchmark. Technical report, August 1997. [34] Leslie Lamport. On interprocess communication (part II). Distributed Computing, 1(1):203–213, January 1986. [35] Leslie Lamport. The part-time parliament. ACM Transactions Computer Systems, 16(2):133–169, May 1998. [36] Leslie Lamport, Robert Shostak, and Marshall Pease. The Byzantine generals problem. ACM Transactions on Programing Languages and Systems, 4(3):382–401, July 1982. [37] Edward L. Lee and Chandramohan A. Thekkath. Petal: Distributed Virtual Disks. In In the Proceedings of the 7th Intl. Conf. on Architectural Support for Programming Langauges and Operating Systems. pages 84-92, October 1996. [38] Ricardo Mendes, Tiago Oliveira, Alysson Bessani, and Marcelo Pasin. C2FS: um Sistema de Ficheiros Seguro e Fiável para Cloud-of-clouds. In INForum12, September 2012. [39] Hugo Miranda, Alexandre Pinto, and Luís Rodrigues. Appia communication framework. http://appia.di.fc.ul.pt/. [40] T. Oliveira. Substrato de Armazenamento para Sistemas de Ficheiros para cloudof-clouds. Relatório do Projecto de Engenharia Informática. DI/FCUL, September 2012. [41] R. Posse. Serviço de Coordenação para Bases de Dados Replicadas. Relatório do Projecto de Engenharia Informática. DI/FCUL, Setembro 2011. [42] Krishna P. N. Puttaswamy, Thyaga Nandagopal, and Murali Kodialam. Frugal Storage for Cloud File Systems. In Proc. of the 3rd ACM European Systems Conference – EuroSys’12, April 2012. [43] B. Reed and F. P. Junqueira. A simple totally ordered broadcast protocol. In LADIS ’08: Proceedings of the 2nd Workshop on Large-Scale Distributed Systems and Middleware. pages 1–6, New York, NY, USA, 2008. ACM. Bibliografia 78 [44] M. Satyanarayanan, J. H. Howard, D. N. Nichols, R. N. Sidebotham, A. Z. Spector, and M. J. West. The ITC distributed file system: principles and design. In Proceedings of the 10th ACM Symposium Oper. Syst. Principles. Orcas Island, December 1985. [45] M. Satyanarayanan, P. Kumar, M. Okasaki, E. Siegel, and D. Steere. Coda: A highly available file system for a distributed workstation environment. In IEEE Trans. on Comp. 4. 39 (Apr 1990), 447-459. [46] B. Schoenmakers. A simple publicly verifiable secret sharing scheme and its application to electronic voting. In Proceedings of the 19th International Cryptology Conference on Advances in Cryptology - CRYPTO’99. Aug. 1999. [47] J. Sousa and A. Bessani. From byzantine consensus to bft state machine replication: A latency-optimal transformation. In In the Proc. of the 9th European Dependable Computing Conference, 2012. [48] Jeremy Stribling, Yair Sovran, Irene Zhang, Xavid Pretzer, Jinyang Li, M.Frans Kaashoek, and Robert Morris. Flexible, Wide-Area Storage for Distributed System with WheelFS. In In the Proceedings of the 6th USENIX Symposium on Networked Systems Design and Implementation (NSDI ’09). Boston, MA, April 2009. [49] Vasily Tarasov, Saumitra Bhanage, Erez Zadok, and Margo Seltzer. Benchmarking File System Benchmarking: It *IS* Rocket Science. In 13th USENIX Workshop in Hot Topics in Operating Systems (HotOS XIII). May 2011. [50] C. Thekkath and E. L. T. Mann. Frangipani: A scalable distributed file system. In In the Proceedings of the 16th SOSP. [51] W. Vogels. Eventually Consistent. In Communications of the ACM, October 2008. [52] Michael Vrable, Stefan Savage, and Geoffrey M. Voelker. BlueSky: A cloud-backed file system for the enterprise. In Proc. of the 10th USENIX Conference on File and Storage Technologies – FAST’12, 2012. [53] S. A. Weil, S. A. Brandt, E. L. Miller, and C. Maltzahn. CRUSH: Controlled, scalable, decentralized placement of replicated data. In Proceedings of the 2006 ACM/IEEE Conference on Superomputing (SC ’04). Tampa, FL, Nov, 2006, ACM. [54] Sage A. Weil, Scott A. Brandt, Ethan L. Miller, Darrell D. E. Long, and Carlos Maltzahn. Ceph: A Scalable, High-Performance Distributed File System. In Proc. of the 7th USENIX Symposium on Operating Systems Design and Implementation – OSDI 2006, pages 307–320, 2006.