antonio leandro

sistemas distribuídos

The Google File System

paper · núcleo · Sanjay Ghemawat, Howard Gobioff, Shun-Tak Leung ·

a tese

falha de hardware é o regime normal, não o acidente: se o sistema assume isso e a aplicação aceita um append "pelo menos uma vez" no lugar de consistência forte, um master único e discos baratos aguentam centenas de terabytes.

o que fica

  1. O chunk de 64 MB não é escolha de throughput, é escolha de metadado: com menos de 64 bytes de metadado por chunk, o estado inteiro do file system cabe na memória do master, e é isso que permite ele varrer tudo em background.
  2. Um master único não vira gargalo desde que nenhum byte de dado passe por ele — o cliente pergunta a localização, cacheia, e conversa direto com o chunkserver; nos clusters medidos o master recebia de 200 a 500 operações por segundo.
  3. O master não guarda em disco onde cada chunk está: ele pergunta aos chunkservers no boot. quem tem a palavra final sobre o conteúdo do disco é o disco, e tentar manter uma cópia consistente disso no coordenador só cria divergência.
  4. Record append garante que o dado foi escrito pelo menos uma vez, não exatamente uma vez: as réplicas de um mesmo chunk não são bytewise idênticas, e a aplicação precisa carregar checksum e id no próprio registro para descartar padding e duplicata.
  5. Checksum de 32 bits a cada 64 KB existe porque o disco mente — drives IDE que diziam falar uma versão do protocolo e falavam outra corromperam dados silenciosamente, e comparar réplicas entre si não resolveria, já que réplicas divergentes são legais no modelo do GFS.
  6. A escrita de um único cliente ficou em 6,3 MB/s, metade do limite teórico, e os autores atribuem isso à pilha de rede interagindo mal com o pipeline de replicação; o desenho otimiza vazão agregada, não latência individual.

o problema

Os sistemas de arquivos distribuídos que existiam antes — AFS, xFS, Frangipani, GPFS, Lustre — foram desenhados para um mundo em que a máquina é confiável, o arquivo é pequeno, o cliente relê o que acabou de ler e a interface é POSIX. O Google tinha o contrário disso em todos os eixos. Milhares de máquinas de peça barata: alguma coisa está quebrada agora, e alguma coisa não vai voltar. Arquivos de vários GB contendo milhões de documentos web, onde gerenciar bilhões de arquivinhos de KB seria inviável mesmo que o file system aguentasse. Mutação quase sempre por append, leitura quase sempre sequencial em streaming — cache de bloco no cliente não paga o próprio custo de coerência quando o working set não cabe em lugar nenhum.

Havia ainda um padrão que nenhum file system da época atendia: centenas de produtores, um por máquina, escrevendo simultaneamente no mesmo arquivo, que serve de fila produtor-consumidor ou de merge de resultados. Com write tradicional em offset, isso exige um lock manager distribuído. Pagar esse preço em cada job de processamento de dados era caro demais.

a ideia

Em vez de implementar a semântica que as aplicações teoricamente poderiam querer, os autores olharam para o que as aplicações de fato faziam e cortaram tudo que não era usado. Duas concessões da aplicação compram toda a simplicidade do sistema: a interface não é POSIX (ganha uma operação de append atômico onde quem escolhe o offset é o file system) e o modelo de consistência é relaxado (região concorrente fica consistente mas indefinida, e o append pode deixar padding e duplicata pelo caminho).

Com isso na mão, dá para fazer o que a literatura mandava não fazer: um master único, centralizado, com todo o estado em memória. Ele decide colocação e replicação com conhecimento global, e nunca toca em dado de usuário.

como funciona

Cada arquivo é fatiado em chunks fixos de 64 MB, cada um com um handle de 64 bits imutável, gravado como arquivo Linux comum em três chunkservers por padrão, espalhados por racks diferentes.

O master guarda três coisas: namespace, mapeamento arquivo→chunks e localização das réplicas. Tudo em memória. As duas primeiras persistem num operation log replicado em máquinas remotas — a resposta ao cliente só sai depois do flush local e remoto — com checkpoint em formato B-tree que é mapeado direto para a memória, sem parsing. A terceira não persiste: o master pergunta aos chunkservers no startup e se mantém atualizado pelos HeartBeats.

Leitura: o cliente converte offset em índice de chunk, pede ao master, recebe handle e localizações (mais as dos chunks seguintes, de brinde), cacheia e fala direto com a réplica mais próxima.

Escrita: o master dá um lease de 60 segundos a uma réplica, a primary, que serializa as mutações; todas as réplicas aplicam na mesma ordem. O fluxo de dados é desacoplado do de controle — o cliente empurra os bytes por uma cadeia linear de chunkservers escolhida por proximidade de IP, em pipeline sobre TCP, cada máquina usando toda a banda de saída e repassando assim que recebe. Só depois vai o comando à primary.

No record append, o cliente manda só o dado. Se ele não couber no chunk atual, a primary preenche o resto com padding e manda tentar no próximo — por isso o append é limitado a um quarto do chunk. Se falhar em alguma réplica, o cliente repete, e é daí que nascem as duplicatas. Réplica atrasada é detectada por número de versão do chunk e coletada como lixo; corrupção em disco, por checksum de 32 bits a cada bloco de 64 KB.

o que isso custou

A complexidade não sumiu, mudou de lugar: foi para a aplicação. Todo leitor precisa de registros auto-identificáveis, com checksum para descartar fragmento e padding, e id único para deduplicar quando a operação não é idempotente. O GFS não promete réplicas idênticas, só que o dado foi escrito ao menos uma vez.

O master é um ponto único para mutação. Reinicia em segundos, mas fica capenga por 30 a 60 segundos até coletar as localizações dos chunkservers, e os shadow masters só servem leitura, com metadado possivelmente atrasado. Como o cliente cacheia localização, ele pode ler de uma réplica velha dentro da janela do timeout.

A escrita individual é fraca — 6,3 MB/s para um cliente, metade do limite, e os autores escrevem que “writes are slower than we would like”. O append agregado cai de 6,0 para 4,8 MB/s de 1 para 16 clientes, porque o gargalo é a banda dos chunkservers que guardam o último chunk. Arquivo pequeno e muito lido vira hot spot: aconteceu com um executável de um chunk só, lançado em centenas de máquinas ao mesmo tempo. A coleta de lixo preguiçosa atrapalha quando o disco está apertado. E três réplicas gastam mais espaço bruto que RAID — o próprio paper diz que está explorando paridade e erasure codes. Os autores também avisam para não generalizar as medições: o GFS foi ajustado às aplicações do Google e vice-versa.

onde isso aparece hoje

O HDFS é essencialmente uma reimplementação aberta deste desenho: coordenador único de metadados, bloco grande, três réplicas, otimização para append e leitura sequencial. O MapReduce, publicado no ano seguinte, assume um armazenamento com exatamente estas propriedades embaixo. E a linha do “explorando erasure codes” virou o padrão de armazenamento frio na década seguinte, inclusive no próprio HDFS.

lido na íntegra por pipeline de llm, revisado por antonio leandro antes de publicar ·