Tutorial HDFS: Archiarquitetura, leitura e escrita Operação

⚡ Resumo Inteligente

O HDFS é a camada de armazenamento distribuído do Hadoop, que divide arquivos muito grandes em blocos replicados em máquinas comuns, de forma que um único NameNode tracOs metadados do ks são armazenados enquanto muitos DataNodes atendem solicitações de leitura e gravação de forma confiável.

  • 🔘 Architextura: O NameNode armazena a imagem do namespace e o log de edições, enquanto os DataNodes armazenam as réplicas reais dos blocos.
  • ☑️ Dimensionamento de blocos: O Hadoop 1.x utilizava blocos de 64 MB por padrão; o Hadoop 2.x e 3.x utilizam blocos de 128 MB por padrão.
  • ✅ Replicação: O padrão é de três réplicas por bloco, distribuídas pelos racks para que falhas de hardware nunca resultem em perda de dados.
  • 🧪 Caminho de leitura: FSDataInputStream e DFSInputStream obtêm as localizações dos blocos do NameNode e, em seguida, transmitem bytes diretamente dos DataNodes.
  • 🛠️ Escreva o caminho: O DFSOutputStream enfileira pacotes, o DataStreamer constrói um pipeline DataNode e uma fila de reconhecimento (Ack Queue) protege contra a perda de pacotes.
  • 🧭 Opções de acesso: O org.apache.hadoop.fs Java A API e o shell DFS do HDFS abrangem as operações de abrir, ler, escrever e fechar.

Tutorial HDFS

O que é HDFS?

O HDFS é um sistema de arquivos distribuído para armazenar arquivos de dados muito grandes, executado em clusters de hardware comum. É tolerante a falhas, escalável e extremamente simples de expandir. O Hadoop vem incluído com o HDFS (Hadoop Distributed File System).

Quando os dados excedem a capacidade de armazenamento de uma única máquina física, torna-se essencial dividi-los em várias máquinas separadas. Um sistema de arquivos que gerencia operações específicas de armazenamento em uma rede de máquinas é chamado de sistema de arquivos distribuído. HDFS é um desses softwares.

HDFS Archiarquitetura

Um cluster HDFS consiste principalmente em um NomeNode que gerencia os metadados do sistema de arquivos e Nós de dados que armazenam os dados reais.

  • NomeNode: O NameNode pode ser considerado o mestre do sistema. Ele mantém a árvore do sistema de arquivos e os metadados de todos os arquivos e diretórios presentes no sistema. Dois arquivos, a 'imagem do namespace' e o 'log de edições', são usados ​​para armazenar informações de metadados. O NameNode tem conhecimento de todos os DataNodes que contêm blocos de dados para um determinado arquivo; no entanto, ele não armazena as localizações dos blocos de forma persistente. Essas informações são reconstruídas a cada inicialização do sistema a partir dos DataNodes.
  • Nó de dados: Os DataNodes são nós escravos que residem em cada máquina de um cluster e fornecem o armazenamento propriamente dito. Eles são responsáveis ​​por atender às solicitações de leitura e gravação dos clientes.

Como um NameNode isolado representaria um ponto único de falha, os clusters atuais executam um NameNode ativo juntamente com um NameNode em espera que compartilha o log de edições por meio de um quorum de JournalNodes, com failover automático entre os dois.

As operações de leitura e gravação no HDFS operam em nível de bloco. Os arquivos de dados no HDFS são divididos em partes do tamanho de blocos, que são armazenadas como unidades independentes. O tamanho de bloco padrão é de 64 MB no Hadoop 1.x. A partir do Hadoop 2.x, o padrão é de 64 MB. dfs.blocksize tem 128 MB.

O HDFS opera com base no conceito de replicação de dados, em que múltiplas réplicas de blocos de dados são criadas e distribuídas em nós por todo o cluster para permitir alta disponibilidade dos dados em caso de falha de um nó. O fator de replicação padrão é três (dfs.replicação), e quando um DataNode para de enviar sinais de pulsação, o NameNode replica automaticamente seus blocos em outro local.

Você sabe? Um arquivo no HDFS menor que um único bloco não ocupa o armazenamento total de um bloco.

Leia Operação em HDFS

Uma solicitação de leitura de dados é atendida pelo HDFS, pelo NameNode e pelos DataNodes. Vamos chamar o leitor de "cliente". O diagrama abaixo ilustra a operação de leitura de arquivo no Hadoop.

Fluxo de dados de operação de leitura do HDFS entre o cliente, o NameNode e os DataNodes.

  1. Um cliente inicia uma solicitação de leitura chamando o método 'open()' do objeto FileSystem; trata-se de um objeto do tipo DistributedFileSystem.
  2. Este objeto se conecta ao NameNode usando RPC e obtém informações de metadados, como a localização dos blocos do arquivo. Observe que esses endereços correspondem aos primeiros blocos do arquivo.
  3. Em resposta a essa solicitação de metadados, são retornados os endereços dos DataNodes que possuem uma cópia desse bloco.
  4. Assim que os endereços dos DataNodes são recebidos, um objeto do tipo FSDataInputStream é retornado ao cliente. O FSDataInputStream contém o DFSInputStream, que cuida das interações com o DataNode e o NameNode. Na etapa 4 mostrada no diagrama acima, um cliente invoca o método 'read()', que faz com que o DFSInputStream estabeleça uma conexão com o primeiro DataNode que contém o primeiro bloco de um arquivo.
  5. Os dados são lidos na forma de fluxos, nos quais o cliente invoca repetidamente o método 'read()'. Esse processo da operação read() continua até atingir o final do bloco.
  6. Ao atingir o final de um bloco, o DFSInputStream fecha a conexão e passa a localizar o próximo DataNode para o próximo bloco.
  7. Assim que o cliente terminar de ler, ele chama o método close().

Escreva Operação em HDFS

Nesta seção, vamos entender como os dados são gravados no HDFS por meio de arquivos. O diagrama abaixo traces que escrevem o caminho.

Pipeline de operação de gravação HDFS com DataQueue, DataStreamer e fila de reconhecimento (Ack Queue).

  1. Um cliente inicia uma operação de escrita chamando o método 'create()' do objeto DistributedFileSystem, que cria um novo arquivo – Etapa nº 1 no diagrama acima.
  2. O objeto DistributedFileSystem se conecta ao NameNode por meio de uma chamada RPC e inicia a criação de um novo arquivo. No entanto, essa operação de criação de arquivo não associa nenhum bloco ao arquivo. É responsabilidade do NameNode verificar se o arquivo (que está sendo criado) já existe e se o cliente possui as permissões corretas para criar um novo arquivo. Se um arquivo já existir ou se o cliente não tiver permissão suficiente para criar um novo arquivo, uma exceção IOException será lançada para o cliente. Caso contrário, a operação é bem-sucedida e um novo registro para o arquivo é criado pelo NameNode.
  3. Assim que um novo registro é criado no NameNode, um objeto do tipo FSDataOutputStream é retornado ao cliente. O cliente o utiliza para gravar dados no HDFS. O método de gravação de dados é invocado (etapa 3 no diagrama).
  4. O FSDataOutputStream contém um objeto DFSOutputStream que gerencia a comunicação com os DataNodes e o NameNode. Enquanto o cliente continua gravando dados, o DFSOutputStream continua criando pacotes com esses dados. Esses pacotes são enfileirados em uma fila chamada DataQueue.
  5. Existe ainda um outro componente chamado DataStreamer que consome essa DataQueue. O DataStreamer também solicita ao NameNode a alocação de novos blocos, selecionando assim os DataNodes adequados para serem usados ​​na replicação.
  6. Agora, o processo de replicação começa com a criação de um pipeline usando DataNodes. No nosso caso, escolhemos um nível de replicação 3 e, portanto, existem 3 DataNodes no pipeline.
  7. O DataStreamer envia pacotes para o primeiro DataNode do pipeline.
  8. Cada DataNode em um pipeline armazena o pacote recebido e o encaminha para o segundo DataNode no pipeline.
  9. Outra fila, a 'Fila de Confirmação', é mantida pelo DFSOutputStream para armazenar pacotes que estão aguardando confirmação dos DataNodes.
  10. Depois que a confirmação de um pacote na fila é recebida de todos os DataNodes no pipeline, ele é removido da 'Fila de confirmação'. No caso de alguma falha do DataNode, os pacotes desta fila são usados ​​para reiniciar a operação.
  11. Após um cliente terminar de escrever dados, ele chama o método close() (Etapa 9 no diagrama). A chamada a close() resulta no envio dos pacotes de dados restantes para o pipeline, seguido pela espera por uma confirmação.
  12. Após o recebimento da confirmação final, o NameNode é contatado para ser informado de que a operação de gravação do arquivo foi concluída.

Acesse o HDFS usando o Java API

Nesta seção, tentamos compreender o Java interface usada para acessar o sistema de arquivos do Hadoop.

Para interagir programaticamente com o sistema de arquivos do Hadoop, o Hadoop fornece múltiplas opções. Java O pacote org.apache.hadoop.fs contém classes úteis para a manipulação de arquivos no sistema de arquivos do Hadoop. Essas operações incluem abrir, ler, escrever e fechar. A API de arquivos do Hadoop é genérica e pode ser estendida para interagir com sistemas de arquivos diferentes do HDFS.

Lendo um arquivo do HDFS, programaticamente

Objeto java.net.URL é usado para ler o conteúdo de um arquivo. Para começar, precisamos fazer Java reconhecer hdfs do Hadoop URL esquema. Isso é feito chamando o conjuntoURLMétodo StreamHandlerFactory no URL objeto e passando uma instância de FsUrlStreamHandlerFactory para ele. Este método precisa ser executado apenas uma vez por JVM, portanto, está incluído em um bloco estático.

Um exemplo de código é-

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

Este código abre e lê o conteúdo de um arquivo. O caminho desse arquivo no HDFS é passado para o programa como um argumento de linha de comando.

Acessando o HDFS usando a interface de linha de comando

Esta é uma das maneiras mais simples de interagir com o HDFS. A interface de linha de comando oferece suporte a operações do sistema de arquivos, como leitura de arquivos, criação de diretórios, movimentação de arquivos, exclusão de dados e listagem de diretórios.

Podemos correr '$HADOOP_HOME/bin/hdfs dfs -ajuda' Para obter ajuda detalhada sobre cada comando. Aqui, 'dfs' é um comando do shell do HDFS que suporta vários subcomandos. Nas versões atuais do Hadoop hdfs dfs é a forma preferida, enquanto a mais antiga hadoop fs O comando executa a mesma tarefa para qualquer sistema de arquivos compatível.

Alguns dos comandos amplamente utilizados estão listados abaixo, juntamente com alguns detalhes de cada um.

1. Copie um arquivo do sistema de arquivos local para HDFS

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

Este comando copia o arquivo temp.txt do sistema de arquivos local para o HDFS, conforme mostra a saída abaixo.

O comando hdfs dfs -copyFromLocal está copiando o arquivo temp.txt para o HDFS.

2. Podemos listar os arquivos presentes em um diretório usando -ls

$HADOOP_HOME/bin/hdfs dfs -ls /

Na listagem abaixo podemos ver o arquivo 'temp.txt' (copiado anteriormente) no diretório '/'.

O comando `hdfs dfs -ls` lista o conteúdo do arquivo `temp.txt` no diretório raiz do HDFS.

3. Comando para copiar um arquivo para o sistema de arquivos local do HDFS

$HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

Este comando espelha o comando -get e aceita um caminho de destino local explícito como segundo argumento. A saída abaixo mostra o arquivo temp.txt copiado para o sistema de arquivos local.

O comando `hdfs dfs -copyToLocal` mostra a saída do arquivo `temp.txt` copiado para o sistema de arquivos local.

4. Comando para criar um novo diretório

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

O comando é concluído silenciosamente, como mostra a mensagem abaixo.

O comando `hdfs dfs -mkdir` cria a pasta `/mydirectory` no HDFS.

Verifique se o diretório foi criado ou não. Agora você já deve saber como fazer isso 😉

Perguntas Frequentes

Blocos grandes mantêm os metadados do NameNode pequenos e permitem que um mapeador leia uma longa sequência de bytes antes de buscar novamente. O tempo de busca no disco, portanto, torna-se uma fração minúscula do tempo de transferência, o que torna as varreduras de arquivo completo rápidas.

O NameNode para de receber sinais de pulsação, marca o nó como inativo e agenda a replicação de todos os blocos que ficaram abaixo do seu fator de replicação em DataNodes íntegros. As gravações em andamento são recuperadas da fila de confirmações (Ack Queue), para que o cliente não perca pacotes.

Não em um cluster configurado corretamente. O HDFS High Availability executa um NameNode ativo e um NameNode em espera que compartilham edições por meio de JournalNodes, e os controladores de failover do ZooKeeper promovem o nó em espera automaticamente quando o nó ativo para de responder.

Ambas as opções carregam dados para o HDFS. A opção `-copyFromLocal` restringe a origem ao sistema de arquivos local, enquanto `-put` aceita qualquer origem compatível, incluindo outro caminho do HDFS ou a entrada padrão (stdin). O comportamento é idêntico em todos os outros aspectos, portanto, `-copyFromLocal` apenas documenta a intenção.

Cada arquivo, diretório e bloco ocupa memória no NameNode, portanto, milhões de arquivos pequenos esgotam a memória heap muito antes que os discos fiquem cheios. Combiná-los em arquivos sequenciais, arquivos Avro, ORC, Parquet ou HAR mantém os metadados gerenciáveis.

A replicação mantém três cópias completas, o que custa 200% a mais de armazenamento. A codificação de apagamento, adicionada no Hadoop 3, armazena células de paridade e atinge durabilidade semelhante com uma sobrecarga de aproximadamente 50%, trocando armazenamento mais barato por maior custo de CPU e rede durante a recuperação.

Modelos de aprendizado de máquina treinados com logs de auditoria do NameNode e métricas do DataNode podem prever o esgotamento da capacidade, sinalizar blocos críticos e detectar falhas em discos antes que eles parem de funcionar. A detecção de anomalias em padrões de acesso também identifica tarefas descontroladas precocemente.

O Copilot executa rapidamente tarefas padrão do org.apache.hadoop.fs, como FileSystem.get, loops FSDataInputStream e chamadas IOUtils.copyBytes. Sempre verifique o código gerado em relação à versão do Hadoop em uso, pois os nomes da API e os métodos obsoletos diferem consideravelmente entre o Hadoop 2.x e o 3.x.

Resuma esta postagem com: