Un registro que no cabe en un disco
Una cadena de supermercados guarda una línea por cada pasada por caja. En dos años el registro llega a 6 TB. No cabe en ningún disco de la oficina central. Un solo ordenador necesitaría una jornada de trabajo entera solo para leerlo una vez.
Las herramientas de datos masivos parten el archivo, reparten los trozos entre muchas máquinas y hacen que cada máquina trabaje con su trozo.
Al final de esta lección
Nota
Puedo explicar cómo se parte un archivo y cómo se procesa en paralelo.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Bloque | un trozo de tamaño fijo de un archivo grande | 128 MB |
| NameNode | la máquina que sabe dónde está cada bloque | |
| DataNode | una máquina que guarda bloques | |
| Réplica | una copia de un bloque en otra máquina | |
| Map | el paso que convierte cada dato en pares | |
| Reduce | el paso que suma los pares que comparten clave |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
HDFS parte un archivo en bloques
HDFS es el sistema de archivos de Hadoop. Parte cada archivo en bloques de tamaño fijo, de 128 MB por defecto. El último bloque coge lo que sobra.
Cada bloque se guarda en un DataNode y se copia en otros: si una máquina falla, no se pierde nada. Un único NameNode lleva la lista de bloques de cada archivo y dónde está cada uno.
Una nota sobre el código
En el código, los nombres de variables y funciones van en inglés, como en casi todo el software real. Los comentarios y los textos que se imprimen van en español.
Así aprendes los nombres que verás en cualquier equipo de trabajo.
Ejemplo: un archivo de 520 MB
| Bloque | Tamaño | Copias guardadas | Guardado en |
|---|---|---|---|
| 1 a 4 | 128 MB cada uno | 3 cada uno | tres DataNodes distintos |
| 5 | 8 MB | 3 | tres DataNodes distintos |
| Total | 520 MB | 15 copias | El NameNode solo guarda la lista |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Contar los bloques de un archivo
# Un archivo se parte en bloques de tamaño fijo.
size_mb = 520
block_mb = 128
full_blocks = size_mb // block_mb
rest = size_mb % block_mb
blocks = full_blocks
if rest > 0:
blocks = blocks + 1
print("bloques:", blocks)
print("tamaño del último bloque:", rest, "MB")
copies = blocks * 3
print("copias guardadas en disco:", copies)
# Cambia 520 por 900 y vuelve a ejecutar.
Tu laboratorio es más pequeño
El laboratorio tiene un solo DataNode. Por eso guarda una única copia de cada bloque, no tres. Las ideas son las mismas: un clúster real añade máquinas.
El terminal del laboratorio no tiene el comando hadoop. Preguntas al clúster con curl, por la dirección web del NameNode.
Listar la carpeta de entrada
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input?op=LISTSTATUS' | grep -o '"pathSuffix":"[^"]*"'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Pedir su tamaño de bloque y su longitud
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input/sentence.txt?op=GETFILESTATUS' | grep -o '"blockSize":[0-9]*\|"length":[0-9]*'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Preguntar cuántas copias guarda HDFS
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input/sentence.txt?op=GETFILESTATUS' | grep -o '"replication":[0-9]*'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Preguntar cuánto disco ocupa la carpeta
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input?op=GETCONTENTSUMMARY' | grep -o '"spaceConsumed":[0-9]*'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error muy común
Advertencia
Mucha gente cree que el NameNode guarda el archivo. No lo guarda: solo tiene la lista de bloques y dónde están. Los bytes están en los DataNodes. Si preguntas «¿quién tiene los bytes?», la respuesta es un DataNode.
MapReduce lleva el trabajo a los datos
Copiar 6 TB por la red es lento. Por eso Hadoop envía el programa pequeño a las máquinas que ya tienen los bloques.
Cada máquina ejecuta el paso map con su bloque, sin hablar con las demás. Luego los pares se agrupan por clave: es la fase de mezcla (shuffle). El paso reduce suma cada grupo.
Ejemplo: contar palabras de tickets
| Paso | Bloque uno | Bloque dos |
|---|---|---|
| Entrada | pan leche / leche arroz | pan arroz / pan leche |
| Map | pan 1, leche 1, leche 1, arroz 1 | pan 1, arroz 1, pan 1, leche 1 |
| Mezcla (agrupado por palabra) | pan: 1, 1, 1 / leche: 1, 1, 1 / arroz: 1, 1 | Aquí se juntan los pares de los dos bloques |
| Reduce (suma) | pan 3, leche 3, arroz 2 | Un solo total por palabra |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Map y reduce en Python sencillo
# Dos bloques del registro de tickets de una tienda.
block_one = ["pan leche", "leche arroz"]
block_two = ["pan arroz", "pan leche"]
def apply_map(lines):
# Paso map: cada palabra se convierte en un par [palabra, 1].
pairs = []
for line in lines:
for word in line.split():
pairs.append([word, 1])
return pairs
def apply_reduce(pairs):
# Paso reduce: se suman los 1 de cada palabra.
totals = {}
for pair in pairs:
word = pair[0]
if word in totals:
totals[word] = totals[word] + pair[1]
else:
totals[word] = pair[1]
return totals
all_pairs = apply_map(block_one) + apply_map(block_two)
print(apply_reduce(all_pairs))
# Añade la línea "arroz tomillo" a block_two y vuelve a ejecutar.
Un trabajo deja su resultado en HDFS
Una ejecución de MapReduce se llama trabajo (en inglés, job). El ResourceManager reparte la tarea y el resultado se escribe en HDFS, en archivos.
Cada reducer escribe un archivo que se llama part-r- seguido de un número. Un archivo vacío llamado _SUCCESS indica que el trabajo ha terminado.
Listar la carpeta de salida del trabajo
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/wordcount-out?op=LISTSTATUS' | grep -o '"pathSuffix":"[^"]*"'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Leer el total de la palabra fox
curl -s -L 'http://namenode:9870/webhdfs/v1/user/lab/wordcount-out/part-r-00000?op=OPEN' | grep '^fox'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Preguntar cómo terminó el trabajo
curl -s http://resourcemanager:8088/ws/v1/cluster/apps | grep -o '"finalStatus":"[A-Z]*"'Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Para ir más lejos: sumar antes de enviar
El bloque dos envía cuatro pares a la mezcla, y dos de ellos son «pan 1». Un trabajo real puede sumar antes, dentro de cada bloque. Ese paso se llama combinador (combiner).
Cambia apply_map en el código de MapReduce para que devuelva, en pares, los totales de su propio bloque. Ejecútalo. ¿Cuántos pares salen ahora del bloque dos? ¿Cambia el resultado final?