Esercitazione su HDFS: Archiarchitettura, leggere e scrivere Operaproduzione

⚡ Riepilogo intelligente

HDFS è il livello di archiviazione distribuito di Hadoop, che suddivide i file molto grandi in blocchi replicati su macchine standard in modo che un singolo NameNode tracmetadati ks mentre molti DataNode gestiscono le richieste di lettura e scrittura in modo affidabile.

  • 🔘 Architecnologia: Il NameNode contiene l'immagine dello spazio dei nomi e il registro delle modifiche, mentre i DataNode memorizzano le repliche effettive dei blocchi.
  • ☑️ Dimensionamento dei blocchi: Hadoop 1.x utilizzava blocchi da 64 MB come valore predefinito; Hadoop 2.x e 3.x utilizzano invece blocchi da 128 MB.
  • Replica: Tre repliche per blocco sono l'impostazione predefinita, distribuite su più rack in modo che un guasto hardware non comporti mai la perdita di dati.
  • 🧪 Percorso di lettura: FSDataInputStream e DFSInputStream recuperano le posizioni dei blocchi dal NameNode, quindi trasmettono i byte direttamente dai DataNode.
  • Scrivi il percorso: DFSOutputStream mette in coda i pacchetti, DataStreamer crea una pipeline DataNode e una coda di conferma (Ack Queue) protegge dalla perdita di pacchetti.
  • 🧭 Opzioni di accesso: Il file org.apache.hadoop.fs Java Sia l'API che la shell dfs di hdfs coprono le operazioni di apertura, lettura, scrittura e chiusura.

Esercitazione su HDFS

Cos'è HDFS?

HDFS è un file system distribuito per l'archiviazione di file di dati di grandi dimensioni, che funziona su cluster di hardware standard. È tollerante ai guasti, scalabile ed estremamente semplice da espandere. Hadoop include HDFS (Hadoop Distributed File System).

Quando i dati superano la capacità di archiviazione su una singola macchina fisica, diventa essenziale suddividerli su più macchine separate. Un file system che gestisce operazioni specifiche di archiviazione su una rete di macchine è chiamato file system distribuito. HDFS è uno di questi software.

HDFS Architectura

Un cluster HDFS è costituito principalmente da un NomeNodo che gestisce i metadati del file system e DataNode che memorizzano i dati effettivi.

  • NomeNodo: Il NameNode può essere considerato il master del sistema. Gestisce la struttura ad albero del file system e i metadati di tutti i file e le directory presenti nel sistema. Due file, l'"immagine dello spazio dei nomi" e il "registro delle modifiche", vengono utilizzati per memorizzare le informazioni sui metadati. Il NameNode conosce tutti i DataNode contenenti i blocchi di dati di un determinato file, tuttavia non memorizza in modo permanente le posizioni dei blocchi. Queste informazioni vengono ricostruite dai DataNode ogni volta che il sistema viene avviato.
  • Nodo dati: I DataNode sono nodi slave che risiedono su ciascuna macchina di un cluster e forniscono lo spazio di archiviazione effettivo. Sono responsabili dell'elaborazione delle richieste di lettura e scrittura provenienti dai client.

Poiché un singolo NameNode rappresenterebbe un singolo punto di guasto, i cluster attuali utilizzano un NameNode attivo affiancato a un NameNode di standby che condivide il registro delle modifiche tramite un quorum di JournalNode, con failover automatico tra i due.

Le operazioni di lettura e scrittura in HDFS operano a livello di blocco. I file di dati in HDFS sono suddivisi in blocchi di dimensioni pari a 64 MB, che vengono memorizzati come unità indipendenti. La dimensione predefinita del blocco è di 64 MB in Hadoop 1.x. Da Hadoop 2.x in poi, la dimensione predefinita del blocco è di 64 MB. dfs.blocksize è di 128 MB.

HDFS opera su un concetto di replica dei dati in cui vengono create più repliche dei blocchi di dati e sono distribuite sui nodi in tutto un cluster per consentire un'elevata disponibilità dei dati in caso di guasto di un nodo. Il fattore di replica predefinito è tre (dfs.replication), e quando un DataNode smette di inviare heartbeat, il NameNode replica automaticamente i suoi blocchi altrove.

Lo sai? Un file in HDFS, che è più piccolo di un singolo blocco, non occupa l'intera memoria di un blocco.

Leggi Operazione in HDFS

Una richiesta di lettura dati viene gestita da HDFS, dal NameNode e dai DataNode. Chiamiamo il lettore "client". Il diagramma seguente illustra l'operazione di lettura del file in Hadoop.

Flusso di dati delle operazioni di lettura HDFS tra client, NameNode e DataNode.

  1. Un client avvia una richiesta di lettura chiamando il metodo 'open()' dell'oggetto FileSystem; si tratta di un oggetto di tipo DistributedFileSystem.
  2. Questo oggetto si connette al NameNode tramite RPC e ottiene informazioni sui metadati, come ad esempio la posizione dei blocchi del file. Si noti che questi indirizzi si riferiscono ai primi blocchi di un file.
  3. In risposta a questa richiesta di metadati, vengono restituiti gli indirizzi dei DataNode che possiedono una copia di quel blocco.
  4. Una volta ricevuti gli indirizzi dei DataNode, viene restituito al client un oggetto di tipo FSDataInputStream. FSDataInputStream contiene DFSInputStream, che si occupa delle interazioni con il DataNode e il NameNode. Nel passaggio 4 mostrato nel diagramma precedente, un client invoca il metodo 'read()', che fa sì che DFSInputStream stabilisca una connessione con il primo DataNode che contiene il primo blocco di un file.
  5. I dati vengono letti sotto forma di flussi, nei quali il client invoca ripetutamente il metodo 'read()'. Questo processo di operazione read() continua fino al raggiungimento della fine del blocco.
  6. Una volta raggiunta la fine di un blocco, DFSInputStream chiude la connessione e passa a individuare il DataNode successivo per il blocco seguente.
  7. Una volta che il client ha terminato la lettura, chiama il metodo close().

Scrivi Operazione in HDFS

In questa sezione, capiremo come i dati vengono scritti in HDFS tramite file. Il diagramma seguente trace che scrivono il percorso.

Pipeline di operazioni di scrittura HDFS con DataQueue, DataStreamer e AckQueue

  1. Un client avvia un'operazione di scrittura chiamando il metodo 'create()' dell'oggetto DistributedFileSystem, che crea un nuovo file – Fase n. 1 nel diagramma precedente.
  2. L'oggetto DistributedFileSystem si connette al NameNode tramite una chiamata RPC e avvia la creazione di un nuovo file. Tuttavia, questa operazione di creazione non associa alcun blocco al file. È responsabilità del NameNode verificare che il file (che si sta creando) non esista già e che il client disponga delle autorizzazioni corrette per crearne uno nuovo. Se un file esiste già o il client non dispone di autorizzazioni sufficienti per crearne uno nuovo, viene generata un'eccezione IOException. In caso contrario, l'operazione ha esito positivo e il NameNode crea un nuovo record per il file.
  3. Una volta creato un nuovo record nel NameNode, al client viene restituito un oggetto di tipo FSDataOutputStream. Il client lo utilizza per scrivere dati in HDFS. Viene richiamato il metodo di scrittura dei dati (passaggio 3 nel diagramma).
  4. FSDataOutputStream contiene un oggetto DFSOutputStream che gestisce la comunicazione con i DataNode e il NameNode. Mentre il client continua a scrivere dati, DFSOutputStream continua a creare pacchetti con questi dati. Questi pacchetti vengono accodati in una coda chiamata DataQueue.
  5. Esiste un ulteriore componente chiamato DataStreamer che utilizza questa DataQueue. DataStreamer richiede inoltre al NameNode l'allocazione di nuovi blocchi, selezionando così i DataNode più adatti da utilizzare per la replica.
  6. Ora, il processo di replica inizia creando una pipeline utilizzando DataNodes. Nel nostro caso abbiamo scelto un livello di replica pari a 3 e quindi ci sono 3 DataNode in pipeline.
  7. Il DataStreamer versa i pacchetti nel primo DataNode nella pipeline.
  8. Ogni DataNode in una pipeline memorizza il pacchetto ricevuto e lo inoltra al secondo DataNode della pipeline.
  9. Un'altra coda, la "Ack Queue", viene gestita da DFSOutputStream per memorizzare i pacchetti in attesa di conferma da parte dei DataNode.
  10. Una volta ricevuto il riconoscimento per un pacchetto in coda da tutti i DataNode nella pipeline, questo viene rimosso dalla 'Ack Queue'. In caso di guasto del DataNode, i pacchetti di questa coda vengono utilizzati per riavviare l'operazione.
  11. Una volta che il client ha terminato di scrivere i dati, chiama il metodo close() (passaggio 9 nel diagramma). La chiamata a close() comporta l'invio dei pacchetti di dati rimanenti alla pipeline, seguito dall'attesa della conferma.
  12. Una volta ricevuta la conferma finale, il NameNode viene contattato per informarlo che l'operazione di scrittura del file è stata completata.

Accedere a HDFS utilizzando il Java API

In questa sezione, cerchiamo di capire il Java interfaccia utilizzata per accedere al file system di Hadoop.

Per interagire programmaticamente con il filesystem di Hadoop, Hadoop fornisce più Java classi. Il pacchetto denominato org.apache.hadoop.fs contiene classi utili per la manipolazione di un file nel filesystem di Hadoop. Queste operazioni includono apertura, lettura, scrittura e chiusura. L'API dei file di Hadoop è generica e può essere estesa per interagire con filesystem diversi da HDFS.

Lettura di un file da HDFS, a livello di codice

Oggetto java.net.URL viene utilizzato per leggere il contenuto di un file. Per cominciare, dobbiamo fare Java riconoscere l'HDFS di Hadoop URL schema. Ciò viene fatto chiamando il setURLMetodo StreamHandlerFactory su URL oggetto e passandogli un'istanza di FsUrlStreamHandlerFactory. Questo metodo deve essere eseguito solo una volta per JVM, quindi è racchiuso in un blocco statico.

Un codice di esempio è-

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);
        }
    }
}

Questo codice apre un file e ne legge il contenuto. Il percorso del file su HDFS viene passato al programma come argomento da riga di comando.

Accedere a HDFS tramite l'interfaccia a riga di comando

Questo è uno dei modi più semplici per interagire con HDFS. L'interfaccia a riga di comando supporta operazioni sul filesystem come la lettura di file, la creazione di directory, lo spostamento di file, l'eliminazione di dati e l'elenco delle directory.

Possiamo correre '$HADOOP_HOME/bin/hdfs dfs -help' per ottenere aiuto dettagliato su ogni comando. Qui, 'dfs' è un comando shell di HDFS che supporta più sottocomandi. Nelle versioni attuali di Hadoop hdfs dfs è la forma preferita, mentre la più vecchia hadoop fs Il comando esegue la stessa operazione per qualsiasi file system supportato.

Di seguito sono elencati alcuni dei comandi più utilizzati, insieme ad alcuni dettagli su ciascuno di essi.

1. Copia un file dal file system locale a HDFS

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

Questo comando copia il file temp.txt dal filesystem locale a HDFS, come mostrato nell'output seguente.

Comando hdfs dfs -copyFromLocal per copiare temp.txt in HDFS

2. Possiamo elencare i file presenti in una directory usando -ls

$HADOOP_HOME/bin/hdfs dfs -ls /

Nell'elenco seguente possiamo vedere il file 'temp.txt' (copiato in precedenza) nella directory '/'.

Il comando `hdfs dfs -ls` restituisce l'output contenente il file temp.txt nella directory radice di HDFS.

3. Comando per copiare un file nel filesystem locale da HDFS

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

Questo comando è analogo a -get e accetta un percorso di destinazione locale esplicito come secondo argomento. L'output seguente mostra il file temp.txt copiato nel filesystem locale.

L'output del comando hdfs dfs -copyToLocal mostra il file temp.txt copiato nel filesystem locale.

4. Comando per creare una nuova directory

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

Il comando viene completato senza alcun messaggio di errore, come mostrato nel prompt sottostante.

Il comando hdfs dfs -mkdir crea la cartella /mydirectory in HDFS

Controlla se la directory è stata creata o meno. Ora dovresti sapere come fare 😉

DOMANDE FREQUENTI

I blocchi di grandi dimensioni mantengono i metadati del NameNode di dimensioni ridotte e consentono al mapper di leggere una lunga sequenza di byte prima di effettuare una nuova ricerca. Il tempo di accesso al disco diventa quindi una frazione minima del tempo di trasferimento, il che rende veloci le scansioni complete dei file.

Il NameNode smette di ricevere heartbeat, contrassegna il nodo come non funzionante e pianifica la ri-replicazione di ogni blocco che è sceso al di sotto del suo fattore di replica sui DataNode funzionanti. Le scritture in corso vengono recuperate dalla coda di conferma (Ack Queue), in modo che il client non perda pacchetti.

Non in un cluster configurato correttamente. HDFS High Availability esegue un NameNode attivo e uno di standby che condividono le modifiche tramite i JournalNode, e i controller di failover di ZooKeeper promuovono automaticamente lo standby quando il nodo attivo smette di rispondere.

Entrambi i metodi caricano i dati in HDFS. L'opzione -copyFromLocal limita l'origine al file system locale, mentre -put accetta qualsiasi origine supportata, inclusi altri percorsi HDFS o l'input standard (stdin). Il comportamento è altrimenti identico, quindi -copyFromLocal si limita a indicare l'intento.

Ogni file, directory e blocco occupa memoria nel NameNode, quindi milioni di piccoli file esauriscono la memoria heap molto prima che i dischi si riempiano. Combinandoli in file di sequenza, Avro, ORC, Parquet o archivi HAR, i metadati rimangono gestibili.

La replica mantiene tre copie complete, con un costo di archiviazione superiore del 200%. La codifica di cancellazione, introdotta in Hadoop 3, memorizza invece celle di parità e raggiunge una durabilità simile con un overhead di circa il 50%, scambiando un'archiviazione più economica con costi di CPU e rete più elevati durante il ripristino.

I modelli di machine learning addestrati sui log di audit dei NameNode e sulle metriche dei DataNode possono prevedere l'esaurimento della capacità, segnalare i blocchi critici e rilevare i dischi in avaria prima che smettano di funzionare. Anche il rilevamento delle anomalie nei modelli di accesso permette di individuare tempestivamente i processi che stanno andando fuori controllo.

Copilot completa rapidamente il codice standard di org.apache.hadoop.fs, come FileSystem.get, i cicli FSDataInputStream e le chiamate IOUtils.copyBytes. Verifica sempre il codice generato rispetto alla versione di Hadoop in uso, poiché i nomi delle API e i metodi deprecati differiscono notevolmente tra Hadoop 2.x e 3.x.

Riassumi questo post con: