Añadir almacenamiento para HDFS – Crear Partición en Linux

Como dijimos en el post «Montando un Cluster Big Data desde la a a la z«, es conveniente que los datos guardados en HDFS acaben en una partición de disco localizada en una unidad de almacenamiento externa a donde tenemos el sistema y las herramientas en cada datanode. Es por tanto que en este post, veremos como crear una partición y montarla en Linux para su posterior asignación a HDFS.

Una vez que tenemos la unidad de almacenamiento conectada al sistema, veremos que se ha añadido como sd<x> donde x toma letras a,b,c … según el número de discos que el sistema nos reconoce. Y de momento sin ninguna partición creada. Las particiones aparecen como sd<x><n> donde n es el número de la partición. Toda esta información la obtenemos como sigue:

lsblk

Esta estructura que vemos en la imagen, no es la ideal para un sistema Big Data, pues tenemos el disco sda particionado únicamente en dos particiones: sda1 para el boot lo cual está bien y sda2 para todo el resto desde la raiz /.
Es más conveniente disponer de particiones propias para los logs, y para /root. Pero dejamos ese tema para otro post donde hablemos de qué particionado es más conveniente para un datanode.

Para formatear el disco sdb y crear una partición en éste, que llamaremos /data/hdfs, usaremos la herramienta fdisk

fdisk /dev/sdb

Una vez tecleamos la opción n, nos preguntará si la partición es primary (p) o extended (e). tecleamos p para indicar que es partición primaria.

Nos preguntará número de la partición, de 1 a 4 pues máximo podemos tener 4 particiones primarias en un disco. Tecleamos 1.

Nos preguntará en qué sector queremos que comienze la partición, aquí lo sencillo es dejar el valor por defecto. Le damos intro.

Nos preguntará último sector, como queremos que la totalidad del disco se dedique a dicha partición, dejamos el valor por defecto que es hasta el máximo sector disponible. Le damos intro.

Partition 1 of type Linux and of size 8 GiB is set

Este mensaje nos indica que la partición se ha creado. Tecleamos w (write table to disk and exit) para guardar la tabla de particiones.

Ahora ya nos ha creado la partición sdb1 con la totalidad del espacio del disco sdb pero aún no esta formateada ni asignada a la ruta /data/hdfs.
Para ello, formateamos la partición con formato ext4 más conveniente para hadoop.

mkfs.ext4 /dev/sdb1

En este punto ya tenemos la partición formateada y un UUID asignado, que obtenemos con

blkid

Ahora creamos la ruta que asignaremos a la partición sdb1

cd /
mkdir /data
cd /data
mkdir hdfs

Finalmente para persistir los cambios y asignar la partición de forma permanente, modificamos el fichero /etc/fstab añadiendo:

echo UUID=f85d29e8-997f-45b6-908b-76d9cc9345d6 /data/hdfs ext4 defaults,noatime,nofail 0 2 >> /etc/fstab

noatime, nofail son opciones de montado de particiones que ayudan a mejorar el rendimiento de I/O y evitar errores. noatime evita guardar información relativa a cuándo se ha creado un fichero y cual es la última fecha de modificación. nofail va mejor combinada con x-systemd.device-timeout=5ms, pues dicha opción lo que hace es que en el inicio del sistema, si la unidad de almacenamiento falla, el sistema se inicia sin error, ya posteriormente podremos investigar el porqué ha fallado.

Para montar las paticiones:

mount -av
lsblk

Y esto seria todo, ya sería configuración de HDFS indicarle como ruta de data directory la ruta /data/hdfs.

Management_sesión04: Big Data Processing

En esta sesión veremos:

  • Escalabilidad, elasticidad y sus límites – Universal Scalability Law y como modela/mide la escalabilidad.
  • Desafíos en los procesamientos distribuidos – aspectos principales que se tienen en cuenta en las implementaciones de bases NoSQL.
  • Fases de una query distribuida – global query optimizer y local query optimizer
  • Data shipping, Query shipping – dos maneras de asignar query processing
  • Tipos de paralelismo – intra-query y inter-query parallelism
  • Criterios para escoger un acces plan

Management_sesión03: Hadoop Distributed File System (HDFS)

En esta sesión veremos:

  • Qué es HDFS – capacidades y utilidad
  • Arquitectura HDFS – cómo se organiza internamente Hadoop
    • Fragmentación, Réplicas y balanceamiento
  • File Formats en HDFS – diseños de particionado
    • Diseño Horizontal: SequenceFile
    • Diseño Horizontal: Avro
    • Diseño Híbrido: Parquet
    • Comparación
    • Compresión de datos en Hadoop
    • Cómo escoger file format y tipo de compresión

Esta sesión contiene asociada 3 sesiones prácticas:

  1. Management_sesion03_hands-on01: Comencemos con Hadoop-parte01
  2. Management_sesión03_Hands-on01: Comencemos con Hadoop_parte02
  3. Management_sesión03_Hands-on02: Block size & balanceamiento
  4. Management_sesion03_Hands-on03: FileFormats & Compresión

Management_sesion03_Hands-on03: FileFormats & Compresión

En esta sesión el objetivo es escribir y leer ficheros en distintos formatos (PlainText, SequenceFile, Avro y Parquet) y distintos algoritmos de compresión y ver como se comporta cada tipo en cuanto a tiempos y memoria guiándose por las cuestiones que adjunto aquí abajo.

Los ficheros los generamos usando un programa Java que han de descargar e importar como proyecto Maven a vuestro IDE y posteriormente compilar.
Se os pedirá completar el código añadiendo dos clases que faltan y adaptar la clase Main:

  • En el Package org.adilazh1.hdfs.reader añadir las clases
    • MyHDFSavroReader: que implemente la interfaz MyReader para poder leer ficheros con formato Avro.
      Como pista investiguen las clases DataFileReader y GenericDatumReader.
    • MyHDFSparquetReader: que implemente la interfaz MyReader para poder leer ficheros con formato Parquet.
      Como pista investiguen las clases ParquetReader y GenericRecord.
  • Adaptar la clase Main para que podamos llamar a las clases creadas y deserializar los ficheros Avro y Parquet para que sean legibles para nosotros.

Descargue el proyecto aquí HDFS-1.0.


Nota: Hay un error en el código, en la clase Main, en la parte de read, para -plainText usen un objeto de la clase MyHDFSPlainFileReader en lugar de MyHDFSSequenceFileReader.


Una vez completado el proyecto (puede hallar una posible solución aquí) y compilado, úselo para responder a las cuestiones:

A qué conclusiones ha llegado?

Habrá notado que una de las características diferenciales a simple vista entre los diversos formatos es la legibilidad. Debido a los metadatos, únicamente el formato de plainText es legible para nosotros, todos los demás necesitan ser deserializados. Pero dicha característica no es la que nos hará escoger un formato u otro, nos interesara según los intereses que tengamos, ahorrar espacio o explotar paralelismo para escoger un formato u otro.

Hemos notado también que al definir SequenceFile, de estructura key-value, hemos tenido que implementar la clave. No es algo automático. Lo que nos permite concluir que un fichero puede ser almacenado en diversos formatos pero somos nosotros los que, conociendo su estructura, adaptamos el fichero al formato si es preciso.

En cuanto a los tamaños de los ficheros comparados con plainText, observamos que SequenceFile para ficheros grandes tiende a ocupar lo mismo que plainText pues sólo añade cierta metadata y clave que relativamente no supone mucho espacio. Avro, de diseño horizontal, guarda el esquema del fichero en formato JSON adjunta al fichero y eso aumenta ligeramente el espacio ocupado. Parquet en cambio observamos que el espacio ocupado es mucho menor que plainText aún que añada header y footer por cada bloque y se debe a que Parquet compacta las columnas aprovechando su diseño híbrido, así se queda con datos menos repetetivos. También representa los valores numéricos del fichero en formato numérico minimal.

En cuanto a tiempos de lectura, si no deserializamos, las conclusiones son propias de la práctica anterior, depende del tamaño y número de bloques. En cambio, si se desea deserializar y hacer el contenido legible, ahí notamos que Avro y Parquet toman más tiempo que plainText y SequenceFile dado que se necesita mayor cómputo.

La compresión nos permite ahorrar espacio, y si es de tipo splittable nos permitirá reducir el shuffling por la red en nuestros jobs distribuidos. Aquí solo hemos hecho pruebas a modo de ejemplo con SequenceFile y los tres (dos) niveles de compresión que permite: RECORD, compresión a nivel de registros (values) y BLOCK, compresión a nivel de bloques. Una compresión a nivel de bloques reduce el tamaño dado que aplica sobre más cantidad de datos, reduciendo así número de bloques y tiempo de inserción. En cuanto a tiempo de lectura, la compresión introduce cierta sobrecarga que es mayor en el nivel RECORD debido a más «partes» a descomprimir que el nivel BLOCK.

En definitiva, no existe una regla definitiva de cómo escoger un formato u otro, una compresión u otra. Depende del problema, forma de datos, utilidad de los datos, son más del tipo Hot Data o Cloud Data,… Pero lo que hemos podido observar es que Parquet ahorra bastante en espacio sin aplicar una compresión específica, pues aprovecha compactación de columnas y la manera de guardad los valores numéricos. Añadiendo una compresión, deberíamos saber si nuestros datos están más enfocados a almacenarse con poca consulta o más bien a ser explotados por algoritmos en paralelo. Para el primer caso una compresión Snappy (no splittable) sería útil. En cambio, para aprovechar al máximo el paralelismo en jobs distribuidos y usando compresión, un algoritmo a considerar sería LZO.

Management_sesion01:Introducción

En está sesión introductoria al Big Data veremos:

  • Big Data, una manera de gestionar datos? – Introducción a las necesidad que surgen en Big Data.
  • Business Intelligence – «El workflow» entre los datos y departamentos en un ecosistema Big Data.
  • Qué es el Big Data – posible definición de esté área de conocimiento.
  • Challenges – algunos problemas en el ecosistema Big Data y como se intentan resolver.
  • Paradigma – paradigma Big Data: distribución, paralelismo, NoSQL …
  • Cloud & On premise – ventajas vs inconvenientes. Big Data y Cloud
  • Salidas profesionales – comentamos ciertos perfiles Big Data y sus roles principales.

Management_sesion03_hands-on01: Comencemos con Hadoop-parte01

En esta sesión práctica el objetivo es descargar y configurar Hadoop por una parte y por otra, practicar ciertos comándos básicos como insertar y leer datos hacia y desde HDFS.
También tendremos que desarrollar un proyecto Maven con programa escrito en JAVA que nos permita escribir y leer ficheros interaccionando con HDFS desde JAVA.

Vamos a necesitar:

  • Tener en mente la arquitectura de nuestro Cluster virtual y la teoría sobre HDFS vista en la sesión03.
  • Un cliente ssh: Putty o mobaXterm
  • Un IDE de desarrollo: Eclipse o IntelliJ IDEA

Comencemos:

Parte 1: instalar y configurar Hadoop.
Iniciamos las tres máquinas virtuales y nos logeamos

usuario: adilazh1
password: azh1

Nos conectamos al master via ssh y una vez dentro creamos un directorio «Descargas»

ssh adilazh1@127.0.0.1
cd
mkdir Descargas

Y ahora descargamos Hadoop 2.10.0 y Java 8 dentro de dicha carpeta

cd Descargas
wget http://apache.uvigo.es/hadoop/common/hadoop-2.10.0/hadoop-2.10.0.tar.gz
tar xf hadoop-2.10.0.tar.gz -C ~/
wget https://www.dropbox.com/s/x1kyrrhmdiwaiyv/jdk-8u241-linux-x64.tar.gz?dl=1
mv jdk-8u241-linux-x64.tar.gz?dl=1 jdk-8u241-linux-x64.tar.gz
tar xf jdk-8u241-linux-x64.tar.gz -C ~/

Inciso: hemos usado jdk-8u241 de Oracle que para descargarlo se necesita logearse, para saltarnos esté paso, he dejado el link en Dropbox. Existen diversos openjdk que pueden usar como por ejemplo amazon corretto.
También los enlaces pueden romperse y dejar de funcionar, en ese caso consultando las webs oficiales podremos obtener nuevos links de descarga.


Ahora pasamos a la verdadera configuración:
1. En el fichero ~/hadoop-2.10.0/etc/hadoop/slaves incluimos los hostnames de los DataNodes, como ya están sus IPs de Red NAT incluidos en el fichero hosts del máster, incluimos únicamente sus nombres. Suprimiendo localhosts que viene por defecto. Quedando el contenido del fichero como sigue:

slave1
slave2

2. Modificamos el fichero ~/hadoop/etc/hadoop/core-site.xml (fichero que permite configurar hadoop) añadiedo dos propiedades. La primera para definir la URL HDFS para el NameNode. La segunda indicaremos donde HDFS guardará los datos:

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://master:27000</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/home/adilazh1/data</value>
    </property>
</configuration>

3. HDFS contiene algunas configuraciones por defecto, que podemos consultar en la documentación. Vemos que define el tamaño mínimo de bloque y también el porcentaje mínimo de bloques que deben satisfacer el requisito mínimo de replicación para no entrar en savemode al iniciarse. Para evitar estas configuraciones y poder probar diferentes valores de block size y replicación, desactivamos dichos límites. Para ello modificamos el fichero ~/hadoop-2.10.0/etc/hadoop/hdfs-site.xml añadiendo las siguientes propiedades:

<configuration>
    <property>
        <name>dfs.namenode.fs-limits.min-block-size</name>
        <value>0</value>
    </property>
    <property>
        <name>dfs.namenode.safemode.threshold-pct</name>
        <value>0</value>
    </property>
</configuration>

4. Indicamos a Hadoop donde hemos descargado JAVA, modificando el fichero ~/hadoop-2.10.0/etc/hadoop/hadoop-env.sh modificando los valores de JAVA_HOME.
En dicho fichero también hallamos la variable HADOOP_HEAPSIZE que por defecto está en 1000MB que define JVM heap size. Si posen una computadora más potente con 16GB de RAM, y podéis dedicar más RAM a las VM, podéis indicar un valor superior a la variable HADOOP_HEAPSIZE y así los procesos que corren en JVM tomarán más memoria.

export JAVA_HOME=/home/adilazh1/jdk1.8.0_241

5. Copiamos la configuración a los slaves usando scp

scp -r hadoop-2.10.0 jdk1.8.0_241 adilazh1@slave1:.
scp -r hadoop-2.10.0 jdk1.8.0_241 adilazh1@slave2:.

Parte2: iniciar y apagar cluster hadoop
Ahora que ya hemos configurado hadoop y hemos copiado la configuración a los slaves, podemos iniciar el cluster hadoop y comprobar que todo funcione correctamente:

  1. Formateamos NameNode al tratarse de la primera vez
hadoop-2.10.0/bin/hdfs namenode -format
  1. Iniciamos hadoop!!!
hadoop-2.10.0/sbin/start-dfs.sh

Nos pedirá introducir contraseñas del usuario adilazh1.

Creamos nuestro primer directorio en HDFS

hadoop-2.10.0/bin/hdfs dfs -mkdir /user
hadoop-2.10.0/bin/hdfs dfs -mkdir /user/adilazh1

Hadoop crea una interfaz WEB en el puerto 50070 por defecto, pero esto en el máster que tenemos en versión minimal sin navegadores. Al estar usando una máquina virtual, vamos a poder redirigir puertos a nuestra máquina host y así acceder a la interfaz WEB con el navegador de nuestra máquina. Para ello creamos una regla en virtualbox:

  1. Sobre la máquina «master» –> «configuración» –>»red» –> «Adaptador 1″ –>»avanzados» –> «reenvío de puertos» –>»añadir regla como la imagen y aceptar»

Y recordemos que el adaptador que instala VirtualBox en nuestra máquina host, por defecto tiene como IP 192.168.56.1 (consultar en cmd con el comando ipconfig /all), así que podemos acceder con nuestro navegador usando la URL 192.168.56.1:50070

  1. Parar el Cluster de hadoop
hadoop-2.10.0/sbin/stop-dfs.sh

Para no hacer está práctica muy extensa, dejamos el resto que nos queda «comándos básicos de escritura y lectura desde consola y desde JAVA» para una segunda parte: Management_sesion03_hands-on01: Comencemos con Hadoop-parte02