# Hadoop Distributed File System

HDFS es el sistema de ficheros distribuido de Hadoop. El calificativo «distribuido» expresa la característica más significativa de este sistema de ficheros, la cual es su capacidad para almacenar los archivos en un clúster de varias máquinas.
Esta característica es imperante cuando se pretenden almacenar grandes cantidades de datos, puesto que en general no es posible almacenar cientos de terabytes o petabytes en una única máquina.

## Historia

En el año 2003, Google publica un artículo científico en el que detalla el Google File System (GFS), un sistema de ficheros distribuido que ellos mismos diseñan e implementan, para satisfacer sus necesidades de almacenar grandes cantidades de datos, para posteriormente ejecutar sobre ellos aplicaciones con una carga intensiva de procesado de datos. GFS asienta la arquitectura en la que posteriormente se basaría HDFS, que se liberaría como un proyecto de software libre en la Apache Software Foundation.

## Características

* HDFS, es un sistema de ficheros que está especialmente diseñado para funcionar bien cuando se almacenan archivos grandes, que posteriormente se leerán de forma secuencial.
* HDFS no se comporta especialmente bien cuando lo que se pretende es realizar accesos aleatorios a los archivos, ni cuando estos se actualizan frecuentemente.
* Como se ha comentado, el hecho de que el sistema de ficheros sea distribuido proporciona ventajas, pues se pueden almacenar muchos más datos que los que se podrían almacenar en una sola máquina. Además, en general la cantidad de datos que se puede almacenar puede escalar con facilidad, ya que basta con añadir nuevos nodos al clúster para aumentar su capacidad de almacenamiento.
* HDFS proporciona redundancia, es decir, almacena los ficheros varias veces y en varios equipos distintos, para evitar que si uno de ellos falla, los datos se pierdan. Esto además, permite que se pueda emplear hardware relativamente económico para desplegar Hadoop, puesto que el sistema es tolerante de fallos.

## Almacenamiento de datos en HDFS

Hadoop proporciona una interfaz para leer y escribir en HDFS a través de comandos de consola. Estos comandos pueden ejecutarse en cualquier máquina que tenga instalada Hadoop, indistintamente de que sea máster o esclavo, siempre que ejecute el servicio de HDFS.
El punto de partida principal para interactuar con HDFS es el comando hadoop fs. Ejecutando esta instrucción podemos ver en pantalla las diferentes operaciones que podemos realizar. Esta sección enumera algunas de las principales.

### Listar ficheros

Se pueden listar ficheros y directorios en HDFS de forma similar a como se hace en Unix. Para ello, basta con ejecutar el siguiente comando:
hadoop fs –ls <ruta>
Ejecutar este comando es similar al ls –l de Unix, ya que lista información sobre los ficheros, tal como los permisos, el tamaño y la fecha de modificación. Al igual que en Unix, el directorio raíz de HDFS es ‘/’.

### Crear directorios

Se pueden crear directorios en HDFS empleando el siguiente comando:
hadoop fs –mkdir <ruta>
Este comando creará un nuevo directorio vacío en la ruta especificada, dentro del sistema de ficheros HDFS.

### Copiar ficheros desde o hacia el sistema de ficheros local

Una de las operaciones que frecuentemente querremos realizar consiste en copiar ficheros desde el sistema de ficheros local hacia HDFS, o viceversa. Para ello, se pueden ejecutar los siguientes comandos:
hadoop fs –copyFromLocal <origen_local> <destino>
hadoop fs –copyToLocal <origen> <destino_local>
El primero copiará la ruta local indicada como primer atributo, en la ruta HDFS indicada en el segundo atributo.
El segundo comando realiza la operación inversa, ya que copia la ruta en el sistema HDFS indicada como primer atributo en la ruta local indicada como segundo atributo.

### Imprimir el contenido de ficheros

HDFS proporciona comandos que permiten imprimir total o parcialmente el contenido de un fichero en HDFS. En concreto, se pueden emplear los siguientes comandos:
hadoop fs –cat <fichero>
hadoop fs –tail <ffichero>
El primer comando imprimirá el contenido del fichero íntegro, mientras que el segundo comando únicamente imprimirá el último kilobyte (esto puede ser útil si queremos consultar operaciones recientes en un log o ver cómo es la estructura del fichero). Es importante notar que esta salida puede introducirse como entrada a otro comando de Unix, por ejemplo, podría usarse grep para buscar coincidencias con una determinada expresión regular dentro del fichero.

### Copiar, mover y eliminar rutas en HDFS

Al igual que en Unix, se pueden ejecutar comandos para copiar, mover y eliminar ficheros y directorios en HDFS. En concreto, se pueden emplear los siguientes comandos:
hadoop fs –cp <origen> <destino>
hadoop fs –rm [‐r] <ruta>
Los dos primeros comandos se encargan de copiar y mover respectivamente una ruta a otra distinta dentro del sistema de ficheros HDFS. El tercer comando permite borrar una o más rutas, pudiéndose indicar la opción –r para que se borren directorios de forma recursiva.

### Otros comandos

Hadoop soporta otros comandos que tienen como finalidad gestionar los permisos, comprobar el espacio ocupado por un directorio o el espacio disponible, etc. Todos ellos, así como los parámetros que acepta cada uno, se pueden consultar ejecutando el siguiente comando:
hadoop fs –help

## Arquitectura interna de HDFS

Dentro de esta sección se explica el funcionamiento interno de HDFS, y qué mecanismos son los que lo convierten en un sistema adecuado para el almacenamiento de grandes cantidades de datos. Si bien es cierto que los desarrolladores pueden emplear HDFS sin necesidad de conocer los detalles de su funcionamiento (pues la interfaz que proporciona abstrae de estos detalles), es importante tener una idea del funcionamiento de HDFS a bajo nivel, para poder comprender mejor las operaciones que se realizan cada vez que se leen o escriben ficheros.

### Almacenamiento en bloques

El primer concepto que hay que entender es que HDFS almacena los archivos como bloques, que es la unidad mínima que puede leer o escribir. Todos los ficheros están divididos en bloques, que por defecto tienen un tamaño de 128 MB.
Además, no es necesario que todos los bloques de un fichero se almacenen en la misma máquina del clúster (de hecho, habitualmente esto no ocurrirá). Esto da lugar a dos ventajas a la hora de trabajar con ficheros grandes:
* Se pueden escribir ficheros que sean mayores que la capacidad de almacenamiento de cada una de las máquinas por separado.
* Se puede leer un fichero de forma paralela, puesto que cada máquina puede leer un fragmento distinto al mismo tiempo. Este es uno de los principios fundamentales del paradigma de programación MapReduce.
Como se comentó anteriormente, HDFS proporciona un almacenamiento redundante con el fin de proporcionar tolerancia a fallos, en el caso de que alguna máquina deje de estar disponible. Esta redundancia se realiza a nivel de bloque, es decir, cada bloque se almacena varias veces en máquinas distintas, siendo por defecto el factor de replicación de 3 (es decir, cada bloque se almacena tres veces).

### Namenode y Datanode

Si bien hasta ahora hemos hablado de que los ficheros se dividen en bloques, lo cierto es que es necesario información adicional que indique qué bloques componen cada fichero, en qué orden, y en qué máquinas están almacenados.
En HDFS se distinguen dos tipos de máquinas:
* Namenode: Actúa como máster y almacena todos los metadatos necesarios para construir el sistema de ficheros a partir de los datos que almacenan los datanodes, es decir, almacena la estructura de directorios y de ficheros y los metadatos necesarios para componer cada fichero a partir de sus bloques. La localización de los bloques en el clúster la almacena en memoria RAM, a partir de la información que le proporcionan los datanodes al arrancar el sistema de archivos.
* Datanode: Se pueden considerar esclavos, se limitan casi prácticamente a almacenar los bloques que componen cada fichero, así como, a proporcionarlos al namenode o a los clientes que lo solicitan.
Además, el namenode se encarga de distribuir los bloques entre los diferentes datanodes procurando que estos estén balanceados, es decir, que no haya diferencias sustanciales en la cantidad de datos que almacena cada uno.
Para garantizar la tolerancia a fallos, si un datanode deja de estar disponible, el namenode lo detecta mediante un proceso de heartbeat y vuelve a replicar los bloques perdidos en otras máquinas que sí estén disponibles.
Como se puede observar, el namenode es una pieza fundamental del sistema de archivos HDFS. De hecho, si esta máquina deja de estar disponible, el sistema no puede funcionar (es decir, el namenode es un SPOF o punto único de fallo). No obstante, una clave importante que permite solventar este posible fallo, consiste en configurar un segundo namenode que toma el control en caso de que el namenode primario deje de responder.
El NameNode y el DataNode son piezas de software diseñadas para ejecutarse en máquinas de uso común. Estas máquinas suelen ejecutar un sistema operativo (SO) GNU/Linux. HDFS está construido utilizando el lenguaje Java; cualquier máquina que soporte Java puede ejecutar el software NameNode o DataNode. El uso del lenguaje Java, altamente portable, significa que HDFS puede ser desplegado en una amplia gama de máquinas. Un despliegue típico tiene una máquina dedicada que ejecuta únicamente el software NameNode.
Cada una de las otras máquinas del clúster ejecuta una instancia del software DataNode. La arquitectura no impide que se ejecuten varios DataNodes en la misma máquina, pero en un despliegue real ese es raramente el caso.

### El espacio de nombres del sistema de archivos

HDFS soporta una organización de archivos jerárquica tradicional. Un usuario o una aplicación puede crear directorios y almacenar archivos dentro de estos directorios. La jerarquía del espacio de nombres del sistema de archivos es similar a la de la mayoría de los sistemas de archivos existentes; se pueden crear y eliminar archivos, mover un archivo de un directorio a otro o renombrar un archivo. HDFS soporta cuotas de usuarios y permisos de acceso.
El NameNode mantiene el espacio de nombres del sistema de archivos. Cualquier cambio en el espacio de nombres del sistema de archivos o en sus propiedades es registrado por el NameNode. Una aplicación puede especificar el número de réplicas de un archivo que debe mantener HDFS. El número de copias de un archivo se denomina factor de replicación de ese archivo. Esta información es almacenada por el NameNode.

### Replicación de datos

HDFS está diseñado para almacenar de forma fiable archivos muy grandes en las máquinas de un gran clúster. Almacena cada archivo como una secuencia de bloques. Los bloques de un archivo se replican para la tolerancia a fallos. El tamaño de los bloques y el factor de replicación son configurables por archivo.
Una aplicación puede especificar el número de réplicas de un archivo. El factor de replicación puede ser especificado en el momento de la creación del archivo y puede ser cambiado posteriormente. Los archivos en HDFS son de una sola escritura y tienen estrictamente un escritor en cualquier momento.
El NameNode toma todas las decisiones relativas a la replicación de bloques. Recibe periódicamente un Heartbeat y un Blockreport de cada uno de los DataNodes del cluster. La recepción de un Heartbeat implica que el DataNode está funcionando correctamente. Un Blockreport contiene una lista de todos los bloques de un DataNode.

### Proceso de lectura

El proceso que se lleva a cabo cuando un cliente desea obtener un archivo de HDFS se lleva a cabo siguiendo los pasos que se detallan a continuación:
* El cliente solicita al namenode que le proporcione un fichero.
* El namenode consulta en la tabla de metadatos los bloques que componen el fichero y su localización en el clúster.
* El namenode devuelve al cliente una lista de bloques, así como los equipos en los que puede encontrar cada uno de ellos.
* El cliente contacta con un equipo para obtener cada bloque.
* El cliente compone el archivo.

### Proceso de escritura

De forma similar al caso anterior, el proceso que se lleva a cabo cuando un cliente desea escribir un archivo en HDFS, es de la siguiente manera:
* El cliente solicita al namenode realizar una escritura de un archivo.
* El namenode realiza algunas comprobaciones previas, para comprobar que se puede escribir el fichero y que el cliente tiene permisos para hacerlo.
* El cliente particiona el fichero en bloques, que escribirá de forma secuencial. Para cada bloque, el namenode le proporciona una lista de datanodes en los que se escribirá.
* El cliente contacta con el primer datanode para pedirle que escriba el bloque. Este datanode se encargará de propagar el bloque al segundo, etc.
* El último datanode en escribir el bloque devolverá una confirmación (ACK) hacia atrás, hasta que el primer datanode mandará la confirmación al cliente.
* Una vez que el cliente ha escrito todos los bloques, manda una confirmación al namenode de que el proceso se ha completado.