Está en la página 1de 13

Cluster Hadoop Spark

Por Prof. Oscar H. Mondragón


1. Objetivos

• Desplegar una aplicación de visión computacional en un cluster Hadoop Spark


• Procesar la aplicación de forma distribuida y verificar sus resultados

2. Herramientas a utilizar

• Vagrant
• VirtualBox
• Apache Spark

3. Introducción

En la era de los datos masivos, el procesamiento distribuido se ha convertido en


una necesidad para muchas aplicaciones que requieren analizar grandes
conjuntos de datos. La visión computacional no es una excepción, ya que el
procesamiento de imágenes y videos puede requerir un gran poder de cómputo
y una gran cantidad de almacenamiento. Es por eso que el uso de herramientas
de procesamiento distribuido como Hadoop Spark se ha vuelto cada vez más
popular en esta área.

En esta práctica, se busca desplegar una aplicación de visión computacional en


un cluster Hadoop Spark y procesarla de forma distribuida. Se verificarán los
resultados obtenidos para comprobar la eficacia del procesamiento distribuido.

Para lograr estos objetivos, se utilizarán diversas herramientas y técnicas de


programación, incluyendo el lenguaje de programación Python y las librerías de
procesamiento de imágenes y videos. Además, se explorará cómo configurar un
cluster Hadoop Spark para procesamiento distribuido y cómo aprovechar su
capacidad de procesamiento para mejorar el rendimiento de la aplicación.

En resumen, esta práctica proporcionará una valiosa experiencia en el


despliegue y procesamiento de aplicaciones de visión computacional en un
entorno de procesamiento distribuido, lo que permitirá aprovechar al máximo los
recursos informáticos disponibles y obtener resultados más rápidos y precisos.
4. Preparación de la Práctica (Es posible que haya realizado
estos pasos en la práctica anterior)

1. Configuración de entorno Vagrant

Para esta práctica crearemos un box de Vagrant y le instalaremos Hadoop. Para


clonar repositorio con archivos de ejecute:

git clone https://github.com/omondragon/hadoop_spark

2. Scripts de configuración

Estudie los scripts de configuración del cluster localizados en el directorio


scripts.

3. Inicie la Maquina virtual

cd hadoop_spark
vagrant up

El clúster tardará en arrancar aproximadamente 30 minutos.

5. Desarrollo de la Práctica

Ingrese al master

vagrant ssh nodemaster

En nodemaster, inicie sesión con el usuario hadoop (password: hadoop)

vagrant@nodemaster:~$ su hadoop
Password:
hadoop@nodemaster:/home/vagrant$ cd /home/hadoop/

Iniciar HDFS y Yarn del Cluster (esto lo debe hacer cada vez que reinicie la
maquina)

hadoop@nodemaster:~$ start-dfs.sh
hadoop@nodemaster:~$ start-yarn.sh
Verifique el dashboard de Hadoop en http://192.168.200.3:8088/cluster

Verifique los nodeos activos usando yarn node -list.

Debe obtener una salida como:

hadoop@nodemaster:~$ yarn node -list


2023-01-13 15:23:52,862 INFO client.DefaultNoHARMFailoverProxyProvider:
Connecting to ResourceManager at nodemaster/192.168.200.3:8032
Total Nodes:2
Node-Id Node-State Node-Http-Address Number-of-Running-
Containers
node1:46471 RUNNING node1:8042 0
node2:44645 RUNNING node2:8042 0

6. Aprovisionando una aplicación en el cluster

Aprovisionaremos una aplicación que implementa algoritmos de visión


computacional para conteo de vehículos. Dicho algoritmo está escrito en python
y usa OpenCV. El cluster está conformado por dos máquinas virtuales que
corresponden a un node maestro (nodemaster) y dos nodos de datos (node1,
node2) hadoop.

Esta aplicación se encuentra en el directorio src.

src/conteoVehicular.py

import cv2
import numpy as np

import time
import uuid
import math
import os

import hdfs
from hdfs.client import InsecureClient
import pyspark
from pyspark import SparkContext
conf = pyspark.SparkConf()

master_url = 'http://192.168.200.3:9870'

min_contour_width = 40
min_contour_height = 40
offset = 2
line_height = 240
matches = []

def remove_files():
dir_name= "/tmp/"
extensions = [".mov", ".avi"]

test = os.listdir(dir_name)

for e in extensions:
for item in test:
if item.endswith(e):
os.remove(os.path.join(dir_name,item))

def get_centrolid(x, y, w, h):


x1 = int(w / 2)
y1 = int(h / 2)

cx = x + x1
cy = y + y1
return cx, cy

# process_image function based on code available at:


# https://python.plainenglish.io/vehicle-detection-and-counting-project-opencv-
python-4f8a17f1aa30
def process_image(path):

cars = 0

print("Process image")
client = InsecureClient(master_url, user='hadoop')
random_ = str(uuid.uuid1())
random = '/tmp/ori-{}.mov'.format(random_)
client.download(path, random)

save = '/tmp/rs-{}.avi'.format(random_)

print("****** PRINTING RANDOM ******")


print(random)
print(save)

# Set up image source


cap = cv2.VideoCapture(random)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter(save, fourcc, 30.0, (640,480))

cap.set(3, 1920)
cap.set(4, 1080)

if cap.isOpened():
ret, frame1 = cap.read()
else:
ret = False
ret, frame1 = cap.read()
ret, frame2 = cap.read()

while ret:
d = cv2.absdiff(frame1, frame2)
grey = cv2.cvtColor(d, cv2.COLOR_BGR2GRAY)

blur = cv2.GaussianBlur(grey, (5, 5), 0)

ret, th = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)


dilated = cv2.dilate(th, np.ones((3, 3)))
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))

closing = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel)


contours, h = cv2.findContours(
closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for(i, c) in enumerate(contours):
(x, y, w, h) = cv2.boundingRect(c)
contour_valid = (w >= min_contour_width) and (
h >= min_contour_height)

if not contour_valid:
continue
cv2.rectangle(frame1, (x-10, y-10), (x+w+10, y+h+10), (255, 0, 0),
2)

cv2.line(frame1, (0, line_height), (1200, line_height), (0, 255,


0), 2)
centrolid = get_centrolid(x, y, w, h)
matches.append(centrolid)
cv2.circle(frame1, centrolid, 5, (0, 255, 0), -1)
cx, cy = get_centrolid(x, y, w, h)
for (x, y) in matches:
if y < (line_height+offset) and y > (line_height-offset):
cars = cars+1
matches.remove((x, y))
print(cars)

cv2.putText(frame1, "Total Cars Detected: " + str(cars), (10, 90),


cv2.FONT_HERSHEY_SIMPLEX, 1,
(0, 170, 0), 2)

out.write(frame1)
out.write(th)
if cv2.waitKey(1) == 27:
break
frame1 = frame2
ret, frame2 = cap.read()
cv2.destroyAllWindows()
cap.release()

#Remove video files from /tmp


#remove_files()

return cars

def main():

# To run local on one of the working nodes: (spark-submit in client mode)


#sc = SparkContext('local', appName="hadoop")

sc = SparkContext(appName="hadoop")
client = InsecureClient(master_url, user='hadoop')
paths = client.list('vids')
filepaths = ['vids/{}'.format(x) for x in paths]

print("filepaths", filepaths)
results = sc.parallelize(filepaths, 2).map(process_image).sum()

print(results, type(results))

if __name__ == "__main__":
main()

Este código utiliza la programación distribuida de Spark para procesar y contar


vehículos en múltiples videos de manera eficiente utilizando la librería de
detección de objetos OpenCV.

Primero, se importan los módulos necesarios: cv2 para OpenCV, numpy para
matrices y operaciones matemáticas, time para el temporizador, uuid para
generar identificadores únicos, math para funciones matemáticas, os para
operaciones del sistema de archivos, hdfs para acceder a archivos en HDFS y
pyspark para la programación de Spark.

Luego se definen algunas variables, como los umbrales mínimos de ancho y


altura de los contornos, la altura de la línea de detección, una lista para
almacenar los emparejamientos y un desplazamiento de línea.

La función process_image es el núcleo del programa. Descarga un archivo de


video desde HDFS, crea un objeto de VideoCapture para procesar el video y
establece algunos parámetros de video. La función continúa leyendo el video y
aplicando operaciones de detección de contornos y seguimiento de objetos a
cada cuadro hasta que finaliza el video.

La función principal main se conecta a HDFS, obtiene una lista de archivos de


video, y los distribuye a través de los nodos de Spark utilizando el método map.
Cada archivo de video se procesa en paralelo utilizando la función
process_image, y los resultados se agregan y se imprimen.

Ejecutar la aplicación

Para ejecutar la aplicación, seguir los siguientes pasos:

1. Subir video de prueba al sistema de archivos distribuido (HDFS)

hadoop@nodemaster:~$ cd /vagrant/media/

Verificar los archivos subios al HDFS

hadoop@nodemaster:/vagrant/media$ hdfs dfs -ls


Found 2 items
drwxr-xr-x - hadoop supergroup 0 2023-03-03 17:33 books
drwxr-xr-x - hadoop supergroup 0 2023-03-03 16:55 vids

Subir los videos de prueba

hadoop@nodemaster:/vagrant/media$ hdfs dfs -put corto10s1.mov vids


hadoop@nodemaster:/vagrant/media$ hdfs dfs -put corto10s2.mov vids

Vericar que los archivos estén en HDFS

hadoop@nodemaster:/vagrant/media$ hdfs dfs -ls vids


Found 2 items
-rw-r--r-- 3 hadoop supergroup 14230448 2023-03-06 17:09 vids/corto10s1.mov
-rw-r--r-- 3 hadoop supergroup 14157206 2023-03-06 17:09 vids/corto10s2.mov

2. Ejecutar aplicacion de conteo vehicular

Para ejecutar la aplicación utilizaremos un script ubicado en src llamado


run_traffic.sh

#!/bin/bash

# Run on the cluster


time spark-submit --master yarn --deploy-mode cluster --executor-memory 512m --
driver-memory 512m --num-executors 2 --executor-cores 1 conteoVehicular.py
Este archivo se ejecuta en un entorno de shell de Bash. El comando "spark-
submit" se ejecuta en un clúster de Spark. Los parámetros que se pasan a
spark-submit son los siguientes:

--master yarn: indica que el clúster de Spark está en modo "yarn".

“YARN" significa "Yet Another Resource Negotiator" y es un administrador de


recursos en clústeres de Hadoop. En el contexto de Spark, "YARN" es uno de
los modos de ejecución disponibles para desplegar aplicaciones Spark en un
clúster.

Cuando se utiliza "YARN" como el administrador de recursos en un clúster de


Spark, la aplicación Spark se ejecuta en un conjunto de recursos que se han
asignado para ella, como memoria y núcleos de CPU. El administrador de
recursos "YARN" es responsable de asignar y supervisar estos recursos.

--deploy-mode cluster: indica que la aplicación se va a desplegar en modo


clúster.

El modo "cluster" es un modo de ejecución en el cual una aplicación Spark se


ejecuta en el clúster de Spark, en lugar de en la máquina desde donde se lanza
el comando.

En el modo cluster, el driver de la aplicación Spark se ejecuta en uno de los


nodos del clúster, mientras que los ejecutores se distribuyen en otros nodos.
Esto permite aprovechar la capacidad de procesamiento distribuido del clúster
de Spark, lo que puede mejorar significativamente el rendimiento de la
aplicación.

El modo "cluster" es diferente al modo "client", en el cual el driver de la


aplicación Spark se ejecuta en la máquina desde donde se lanza el comando.
En este modo, los ejecutores también se distribuyen en los nodos del clúster de
Spark, pero el driver es responsable de coordinar la ejecución y recibir los
resultados.

--executor-memory 512m: indica que se asignarán 512 megabytes de memoria


a cada executor.
--driver-memory 512m: indica que se asignarán 512 megabytes de memoria al
driver.
--num-executors 2: indica que se van a utilizar dos executors en el clúster.
--executor-cores 1: indica que cada executor tendrá un core.

Por último, el archivo que se va a ejecutar es "conteoVehicular.py" y el comando


"time" se utiliza para medir el tiempo que tarda la aplicación en ejecutarse.
Ejecutar la aplicación:

hadoop@nodemaster:~$ cd /vagrant/src
hadoop@nodemaster:/vagrant/src$ ./run_traffic.sh

3/03/06 19:30:09 INFO Client:
client token: N/A
diagnostics: N/A
ApplicationMaster host: node1
ApplicationMaster RPC port: 38143
queue: default
start time: 1678130942685
final status: SUCCEEDED
tracking URL:
http://nodemaster:8088/proxy/application_1678119627375_0002/
user: hadoop
23/03/06 19:30:09 INFO ShutdownHookManager: Shutdown hook called
23/03/06 19:30:09 INFO ShutdownHookManager: Deleting directory /tmp/spark-
82fab796-aa63-47f5-b63e-0c15fbcb4403
23/03/06 19:30:09 INFO ShutdownHookManager: Deleting directory /tmp/spark-
a52affff-7ef1-4982-886c-e5225a7989f6

real 1m42.391s
user 0m17.292s
sys 0m9.308s

3. Los videos resultantes estaran en la carpeta /tmp de uno de los nodos.


Puede verificar el nodo asignado en el dashboard de Hadoop
en http://192.168.200.3:8088/cluster
Para verificar, iniciar sesión ssh en el nodo 1, ejecutar:

ssh node1
vagrant@node1:~$ cd /tmp/
vagrant@node1:/tmp$ ls
hadoop-hadoop
hadoop-hadoop-datanode.pid
hadoop-hadoop-nodemanager.pid
hsperfdata_hadoop
jetty-0_0_0_0-8042-hadoop-yarn-common-3_3_4_jar-_-any-4596329207355425483
jetty-localhost-39917-datanode-_-any-9221542983047067273
ori-94cae7c4-bc5c-11ed-9de6-3df2bbc1dd7b.mov
ori-97772cee-bc5c-11ed-9de6-3df2bbc1dd7b.mov
rs-94cae7c4-bc5c-11ed-9de6-3df2bbc1dd7b.avi
rs-97772cee-bc5c-11ed-9de6-3df2bbc1dd7b.avi
snap-private-tmp
systemd-private-0417b82a05344612868b05e0f41e1d1c-ModemManager.service-iHxBrI
systemd-private-0417b82a05344612868b05e0f41e1d1c-systemd-logind.service-Cyc8DF
systemd-private-0417b82a05344612868b05e0f41e1d1c-systemd-resolved.service-
kl9QFA

El nombre del video original tendra un prefijo "ori" y el del resultante un prefijo
"rs".

Por ejemplo,

ori-94cae7c4-bc5c-11ed-9de6-3df2bbc1dd7b.mov
ori-97772cee-bc5c-11ed-9de6-3df2bbc1dd7b.mov
rs-94cae7c4-bc5c-11ed-9de6-3df2bbc1dd7b.avi
rs-97772cee-bc5c-11ed-9de6-3df2bbc1dd7b.avi

Para extraer estos videos los puede copiar al directorio sincronizado de Vagrant

Por ejemplo:

vagrant@node1:/tmp$ sudo cp /tmp/*.mov /vagrant/


vagrant@node1:/tmp$ sudo cp /tmp/*.avi /vagrant/

De esta manera los videos quedaran disponibles en el directorio raiz del


proyecto en la maquina anfitriona y los podrá visualizar con su reproductor de
video de preferencia.

Ejemplo:
7. Ejercicio

1. Reproduzca los pasos de la sección 6.

2. Modifique src/conteoVehicular.py para que el resultado final, es decir


el conteo de vehículos, sea almacenado en una base de datos MySQL
sencilla de una única tabla, registrando la fecha hora y conteo de
vehículos.

8. Entregables y Evaluación

- Sustentación de la práctica

9. Bonificación

1. Busque una aplicación similar y despliéguela en el cluster


10. Bibliografía

1. Hadoop Internals. http://ercoppa.github.io/HadoopInternals/


2. Hadoop Configuration Parámeters.
http://ercoppa.github.io/HadoopInternals/HadoopConfigurationParameters.ht
ml

También podría gustarte