1. pág. 1
“An Open Source Data Distribution and Processing
System”
Resumen – La idea central de este pequeño monográfico1
sobre Apache NiFi será tratar de entender tanto sus bases
teoricas como pragmáticas. En una primera parte
desarrollaremos sus aspectos teóricos desde el punto de vista
de la programación basada en flujos y describiremos sus
diferentes componentes. En una segunda parte nos
centraremos en una serie de ejemplos sencillos que nos
permitirán hacernos una idea del funcionamiento de Apache
NiFi. Y en la parte final veremos algunos proyectos como
NiFi registry y MiNiFi que proporcionaran capacidades muy
interesantes al ecosistema de NiFi.
Resaltar la idea de que NiFi es una herramienta que
quedaría englobada dentro de la familia de los controladores
de flujo de información y como tal, nos puede ser de gran
utilidad para mover información entre nuestros diferentes
stacks tecnológicos. Su integración con sistemas como
Apache kafka, HDFS, ElasticShearch y numerosas bases de
datos le hace candidato para resolver gran número de
problematicas que podemos encontrar en nuestras
arquitecturas empresariales.
I. INTRODUCCIÓN.
Hoy en día, uno de los principales problemas que
tenemos dentro de las organizaciones, es controlar los flujos
de información dentro de nuestros procesos para conseguir
que dicha información llegue a donde tiene que llegar, con el
formato óptimo y aportando el máximo valor posible.
Siguiendo esta idea vamos a presentar Apache NiFi, una
herramienta pensada y diseñada para la automatización de
flujos de datos entre los diferentes sistemas software. Esta
herramienta está basada en el software “NiagaraFile”
desarrollado por la NSA y paso a ser de código abierto en
2014, año en que paso a ser parte de la fundación Apache.
Antes de continuar con la explicación de los conceptos y
partes de NiFi, vamos a enumerar algunos posibles casos de
1
Interesante remarcar que es un monográfico al que le he aportado
estructura, forma y tiempo. El conocimiento estaba en Internet :)
2
https://en.wikipedia.org/wiki/Flow-based_programming#Concepts
uso de esta tecnología dentro de nuestras arquitecturas
empresariales:
• Modelado de flujos de trabajo mediante data flows.
• Conexión sencilla de los flujos de datos entre nuestros
diferentes grupos de tecnologías.
• Procesamiento masivo de datos (enriquecimiento,
filtrado, procesamiento…).
• Centralización de flujos de datos complejos.
• Control de flujos permisionado.
• ETL’s tradicionales.
Si tenemos alguna de estas necesidades, o simplemente nos
interesa ver una posible solución a ellas, NiFi puede ser un
buen aliado y este documento nos servira de ayuda para
entenderlo.
Los conceptos de diseño fundamentales de NiFi están
estrechamente relacionados con las ideas principales de la
programación basada en flujos (
fbp)2
. Este paradigma de la
programación se basa en definir las aplicaciones como redes
de procesos de “caja negra”, que intercambian datos a través
de conexiones predefinidas mediante el paso de mensajes,
donde las conexiones se especifican externamente a los
procesos. Estos procesos pueden reconectarse sin fin para
formar diferentes aplicaciones sin tener que cambiarlos
internamente.
Desde este punto de vista se ve a una aplicación no como un
solo proceso secuencial, que comienza en un punto en el
tiempo, y luego hace una cosa a la vez hasta que finaliza, sino
como una red de procesos asíncronos que se comunican por
medio de flujos de fragmentos de datos estructurados,
llamados “paquetes de información”. Siguiendo esta idea, el
enfoque de esta herramienta estará centrado en los datos y las
transformaciones aplicadas para producir los resultados
deseados.
Este tipo de paradigma presenta un acoplamiento de datos del
tipo “loosely coupled” o acoplamiento flexible en el que
cada uno de los componentes tiene, o utiliza, poco o ningún
conocimiento de las definiciones de otros componentes
separados. Este tipo de acoplamiento nos será muy útil para
los diseños de los flujos de datos.
Sabiendo que Apache NiFi se basa en la programación de
flujos, vamos a ver cómo trata los diferentes conceptos de
este tipo de programación y cómo se acoplan en su contexto.
Algunos de los binomios principales son3
:
FlowFile (Information Packet)4
. Un FlowFile representa
cada objeto que se mueve a través del sistema y, para cada
3
https://nifi.apache.org/docs.html
4
Binomio: Concepto (Termino de referencia FBP).
2. pág. 2
uno, NiFi realiza un seguimiento de un mapa de las cadenas
de atributos de pares clave/valor y su contenido asociado de
cero o más bytes. Los FlowFiles pueden ser clonados,
combinados, partidos, modificados, transferidos y borrados.
Algunos de los atributos comunes que podemos encontrar en
este componente son:
• Filename. Un nombre de archivo que se puede utilizar
al almacenar datos localmente o en un sistema remoto.
• Path. Directorio que podemos usar para guardar los
datos.
• Uuid. Identificador universal que nos permitirá
identificar de forma inequívoca a un FlowFile.
• Entydate. Fecha y hora de entra del FlowFile en el
sistema.
• lineageStarDate. La fecha y hora en que el antecesor
más antiguo del archivo de flujo ingresó al sistema.
• fileSize. Representa el número de bytes ocupado por el
contenido del archivo de flujo.
Ilustración 1 Componentes básicos de un FlowFile.
FlowFile Processor (Black Box). Este componente es el que
realiza el trabajo. En términos de patrones de integración, un
procesador realizaría una combinación de enrutamiento,
transformación o mediación de datos entre sistemas. Los
procesadores tienen acceso a los atributos de un FlowFile
dado y a su flujo de contenido. Pueden operar en cero o más
archivos de flujo en una unidad de trabajo determinada y
pueden confirmar ese trabajo o revertirlo. Algunos ejemplos
típicos de FlowFile Processor pueden ser los siguientes:
• Ingestion.
o GetFile. Extraer contenido del disco local y
borrar el fichero original.
o GetSFTP. Extraer contenido vía ftp de un
servidor remoto y borrar el original.
• Routing.
o RouteOnAttribute. Redirigir los FlowFiles en
base a algún atributo específico.
• Data transformation.
o CompressContent. Comprimir o descomprimir
el contenido.
o ReplaceText. Uso de expresiones regulares para
modificar el texto del contenido.
• Data Egress.
o PutFile. Escribir contenido del FlowFile en un
directorio local.
o PutSFTP. Copiar contenido del FlowFile en un
servidor remoto vía SFTP.
• Attribute Extraction.
o UpdateAttribute. Añadir o actualizar atrabutos
usando valores definidos estáticamente o
dinámicamente mediante del uso del Expression
Lenguaje de NiFi’s.
o ExtractText. Creación de atributos basados en
las expresiones regulares definidas por los
usuarios.
• Splitting and Aggregation.
o Unpackcontent. Descomprir archivos como
TAR y ZIP y mandar cada uno de los ficheros
por separado al flujo de datos.
Cuando un procesador trata de procesar un FlowFile suele
tener definidas tres posibles salidas o terminaciones:
• Failure. Si un FlowFile no se puede procesar
correctamente, el FlowFile original se enrutará a esta
salida.
• Original. Una vez que se ha procesado el FlowFile
entrante, el FlowFile original se enruta a esta salida.
• Success. Los FlowFiles que se procesan correctamente
se enrutarán a esta relación.
Connection (Bounded Buffer). Las conexiones
proporcionarán el enlace real entre los procesadores. Estos
actúan como las colas y permiten que varios procesos
interactúen a diferentes velocidades. Estas colas se pueden
priorizar dinámicamente y pueden tener límites superiores en
la carga, lo que permite controlar el back pressure.
Ilustración 2 Ejemplo de dos procesadores conectados por una
conexión.
Connection
Processor
Processor
ATRIBUTOS
• Mapa de pares key/value.
• Muy utilizados para tomar decisiones de
enrutado.
• Estos valores pueden ser accedidos por el
Expression lenguaje de NiFi.
CONTENIDO
• Los datos reales que se enrutan a través
del flujo de datos.
• Puede ser manipulado múltiples veces a
lo largo del flujo de datos.
3. pág. 3
Si el procesador anterior se vuelve lento o se bloquea por
algún motivo, los archivos de flujo generados por el
procesador anterior se irán acumulando en la cola hasta llegar
al límite de back pressure configurado. En ese momento se
pausará el procesador anterior hasta que el contenido de la
cola este por debajo del umbral configurado.
Flow Controller (Scheduler). El controlador de flujo
mantiene el conocimiento de cómo se conectan los procesos
y administra los subprocesos y las asignaciones de estos que
utilizan todos los procesos. El controlador de flujo actúa
como el agente que facilita el intercambio de archivos de
flujo entre los procesadores.
Process Group (Subnet). Un grupo de procesos es un
conjunto específico de procesos y sus conexiones, que
pueden recibir datos a través de puertos de entrada y enviar
datos a través de puertos de salida. De esta manera, los grupos
de procesos permiten la creación de componentes
completamente nuevos simplemente por la composición de
otros componentes.
Este modelo de diseño es muy parecido a SEDA5
y ayuda a
Apache NiFi a ser una plataforma muy eficaz para crear
flujos de datos potentes y escalables. Algunos de estos
beneficios incluyen:
• Potente gestión visual de los grafos dirigidos de
procesadores de flujo de datos.
• Es inherentemente asíncrono, lo que permite un
rendimiento muy alto y un buffer natural incluso cuando
el procesamiento y los caudales fluctúan.
• Proporciona un modelo altamente concurrente sin que
un desarrollador tenga que preocuparse por las
complejidades típicas de la concurrencia.
• Promueve el desarrollo de componentes cohesivos y
poco acoplados que luego pueden reutilizarse en otros
contextos y promueve unidades comprobables.
• Las conexiones de recursos limitados hacen que las
funciones críticas como la contrapresión y la liberación
de presión sean muy naturales e intuitivas.
• El manejo de errores es sencillo y ágil.
• Los puntos en los que los datos entran y salen del
sistema, así como la forma en que fluyen a través de él,
se entienden bien y se pueden rastrear fácilmente.
Continuemos enumerando algunas de las principales
características que presenta Apache NiFi son:
• La filosofía central de Apache NiFi es garantizar la
entrega en entornos de alto rendimiento. Esto lo logra
mediante el uso efectivo de un registro de escritura
anticipada persistente y un repositorio de contenido.
• Modelado de flujos mediante una potente UI que nos
ayudarán a identificar y reducir la complejidad inerente a
los flujos de datos. Nos permitirá también realizar
cambios parciales.
5
Matt Welsh. Berkeley. SEDA: An Architecture for Well-Conditioned,
Scalable Internet Services [online]. Retrieved: 18 Jan 2018,
from: http://www.mdw.la/papers/seda-sosp01.pdf
• Alta trazabilidad de los datos mediante el repositorio de
procedencia.
• Baja latencia con un alto rendimiento en la ejecución de
los procesados.
• Gestión eficiente de colas con QoS (Data buffering and
Backpressure).
• Escalado horizontalmente y verticalmente simple.
• Dispone de transaccionalidad.
• Seguridad incorporada (Roles, SSL/TLS,etc..).
• Integración con una gran cantidad de aplicativos: HDFS,
Elastic, MongoDB, BD SQL, FTP, Kafka, Flume.
• Ejecución paralela mediante Zookeeper.
• Funcionalidad ampliable mediante plugins y templates.
• Seguridad multi-tenant.
A nivel de arquitectura, Apache NiFi es un sistema basado en
JAVA que presenta los siguientes componentes estructurales:
Ilustración 3 Arquitectura Apache NiFi.
Esta sería la arquitectura más sencilla, pero tenemos la
posibilidad de levantar un clúster de NiFi basado en
ZooKeeper, presentando la siguiente arquitectura
característica:
Ilustración 4 Arquitectura Apache NiFi cluster.
NiFi emplea un paradigma de clusterización Zero-Master.
Cada nodo en el clúster realiza las mismas tareas en los datos,
pero cada uno opera en un conjunto diferente de datos. Uno
de los nodos se elige automáticamente (a través de Apache
ZooKeeper) como el Coordinador de Clúster. Todos los
nodos del clúster enviarán información de heartbeat, y este
nodo es responsable de desconectar los nodos que no
reportan ningún estado de heartbeat durante un período de
tiempo. Además, cuando un nuevo nodo elige unirse al
clúster, el nuevo nodo, primero debe conectarse al
4. pág. 4
Coordinador de clúster elegido actualmente para obtener el
flujo más actualizado. Si el Coordinador de clústeres
determina que el nodo tiene permiso para unirse, el flujo
actual se proporciona a ese nodo, y ese nodo puede unirse al
clúster, suponiendo que la copia del flujo del nodo coincida
con la copia proporcionada por el Coordinador de clústeres.
Si la versión del nodo de la configuración de flujo difiere de
la del Coordinador de Clúster, el nodo no se unirá al clúster.
El protocolo de comunicación entre los nodos del clúster
suele ser NiFi Site-to-Site (S2S)6
Protocol. Un protocolo que
permite una transferencia de datos sencilla, eficiente y
segura.
Vamos a describir por encima algunos de los componentes
principales. En primer lugar, encontramos el servidor web
cuyo propósito principal es servir el UI y el API de Apache
NiFi.
Luego encontramos el Flow Controller que está considerado
como el centro de operaciones de la aplicación. Nos
proporciona subprocesos para que se ejecuten las extensiones
y además gestiona la planificación de ejecución.
Los FlowFiles que están siendo procesados por NiFi se
guardan en un mapa has en la memoria de la JVM haciendo
que sea muy eficiente su procesamiento, pero haciendo
necesario un mecanismo secundario para asegurar los datos.
Ante esta contingencia nace el Flow File Repository. Este
será el lugar donde se persista el seguimiento del estado de lo
que sabemos sobre un FlowFile dado que actualmente está en
activo en el flujo de datos. Desde el punto de vista técnico el
repositorio de FlowFile es un "Registro de escritura
anticipada" (o registro de datos) de los metadatos de cada
uno de los FlowFiles que existen actualmente en el sistema.
Estos metadatos de FlowFile incluyen todos los atributos
asociados con FlowFile, un puntero al contenido real del
FlowFile (que existe en el Content Repo) y el estado del
FlowFile, como a qué conexión/cola pertenece el FlowFile.
Esta escritura Ahead Log proporciona a NiFi la resistencia
que necesita para manejar reinicios y fallos inesperados del
sistema.
Al funcionar el Repositorio de FlowFile como un registro de
escritura anticipada, va registrando todos los cambios en el
repositorio antes de que suceda como una unidad de trabajo
transaccional. Esto permite que el sistema sepa exactamente
en qué paso se encuentra el nodo al procesar parte de los
datos. Si el nodo se apagará mientras procesa los datos, puede
restaurarse desde donde se detuvo7
.
El Content Repository será donde se almacenan los bytes de
contenido real de un FlowFile dado. El enfoque de diseño
predeterminado de este componente es sencillo. Almacena
los bloques de datos en el sistema de archivos. Debido a este
modo de funcionamiento, este componente puede presentar
una gran demanda de IO por lo tiene la posibilidad de
dividirse en varios volúmenes. Este repositorio utiliza los
paradigmas de inmutabilidad y de copia en escritura para
maximizar la velocidad y la seguridad de subprocesos. La
decisión de diseño central que influye en el Repo de
6
https://community.hortonworks.com/articles/88473/site-to-site-
communication-between-secured-https-a.html
7
El sistema toma automáticamente una instantánea, que crea una nueva
instantánea para cada FlowFile. El sistema calcula un nuevo punto de control
base al serializar cada FlowFile en el mapa hash y escribirlo en el disco con
el nombre de archivo ".partial". A medida que avanza el punto de control,
las nuevas líneas de base de FlowFile se escriben en el archivo ".partial".
Contenido es mantener el contenido del FlowFile en el disco
y leerlo solo en la memoria JVM cuando sea necesario. Esto
permite a NiFi manejar objetos de tamaño pequeño y masivo
sin requerir que los procesadores productores y
consumidores mantengan los objetos completos en la
memoria. Como resultado, acciones como dividir, agregar y
transformar objetos muy grandes son bastante fáciles de
hacer sin dañar la memoria.
Para terminar esta breve descripción encontramos el
Provenance Repository que es donde se almacenan todos los
datos de procedencia, de forma que nos permitirá analizar la
trazabilidad de un Flowfile. La implementación de este
componente es muy parecida a la del anterior, con la única
diferencia de que se le añaden las facultades de indexación8
y búsqueda.
Como curiosidad podemos decir que cada evento de
procedencia tiene dos mapas, uno para los atributos antes del
evento y otro para los valores de atributos actualizados. En
general, los eventos de procedencia no almacenan los valores
actualizados de los atributos como existían cuando se emitió
el evento, sino los valores de los atributos cuando se confirma
la sesión. Los elementos se almacenan en caché y se guardan
hasta que la sesión se confirma. Una vez que se confirma se
graban en disco de forma encriptada mediante AES G/CM.
Por último, enumeramos algunos subproyectos de Apache
NiFi que serán muy interesantes para las diferentes
implementaciones:
• Apache NiFi Registry. Una aplicación central
complementaría que proporciona una ubicación central
para el almacenamiento y la gestión de recursos
compartidos en una o más instancias de NiFi, como las
plantillas.
http://nifi.apache.org/registry.html
• MiNiFi. Un enfoque complementario de recopilación
de datos que completa los principio básicos de NiFi en
la gestión del flujo de datos, y se centra en la
recopilación de datos en la fuente de su creación.
http://nifi.apache.org/minifi/index.html
• Flow Design System (FDS). Una plataforma atómica
reutilizable para proporcionar un conjunto común de
componentes UI/UX para Apache NiFi, Apache
Registry, Apache NiFi minifi y cualquier otra
aplicación web de código abierto para consumir.
http://nifi.apache.org/fds.html
Una vez que se realiza el punto de control, el archivo "snapshot" anterior se
elimina y el archivo ".partial" cambia de nombre por "snapshot".
8
Tecnicamente el Provenance Repo es un índice de Lucene que se divide en
varios fragmentos ya que el número máximo de documentos adminitdos por
Lucene sin fragmentación es limitado.
5. pág. 5
II. INSTALACIÓN.
Podemos realizar la instalación de Apache NiFi de
diferentes formas. Directamente desde las fuentes,
descargándonos los binarios o mediante entornos
dockerizados. Encuadrándonos con el propósito de este
documento sólo me centraré en la instalación básica en un
entorno Linux estándar y la ejecución mediante un entorno
Docker.
A. Instalación en sistemas Linux.
Para llevar a cabo la instalación de Apache NiFi
necesitamos cumplir como requisito inicial, la instalación de
Java. En mi caso he optado por instalar esta paquetería:
~/nifi/$ sudo apt install default-jre
~/nifi/$ java --version
openjdk 10.0.2 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-
1ubuntu0.18.04.4)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-
1ubuntu0.18.04.4, mixed mode)
sudo apt install default-jdk
~/nifi$ java --version
openjdk 10.0.2 2018-07-17
Una vez instalado este requisito nos descargaremos la versión
de NiFi que queremos instalar desde la siguiente página:
https://nifi.apache.org/download.html
En mi caso: nifi-1.8.0
~/nifi$ wget http://apache.rediris.es/nifi/1.8.0/nifi-1.8.0-
bin.tar.gz
~/nifi$ tar xvf nifi-1.8.0-bin.tar.gz
~/nifi$ cd nifi-1.8.0/
Una vez dentro de la carpeta que acabamos de descomprimir,
entramos en la carpeta bin y ejecutamos el script:
~/nifi/nifi-1.8.0/bin$ ./nifi.sh --help
Usage nifi {start|stop|run|restart|status|dump|install}
Para arrancar la instancia:
~/nifi/nifi-1.8.0/bin$ ./nifi.sh start
Comprobamos el estado del arranque:
~/nifi/nifi-1.8.0/bin$ ./nifi.sh status
nifi.sh: JAVA_HOME not set; results may vary
Java home:
NiFi home: /home/gauss/nifi/nifi-1.8.0
Bootstrap Config File: /home/gauss/nifi/nifi-
1.8.0/conf/bootstrap.conf
2019-01-07 16:56:33,519 INFO [main]
org.apache.nifi.bootstrap.Command Apache NiFi is currently
running, listening to Bootstrap on port 33979, PID=11172
También podemos comprobar que el proceso está en máquina
mediante $ ps -ef|grep nifi
9
En este caso amplio los límites para todos los usuarios pero lo normal sería
crear un usuario específico para levantar NiFi y aumentarle los límites sólo
a él.
Si todo está arrancado correctamente podemos comprobar
que NiFi está ejecutándose mediante el navegador,
accediendo a:
http://${IP_SERVER}:8080/nifi/
Ilustración 5 Pantalla Inicial de Apache NiFi.
De esta forma estamos levantando el servicio de forma
manual, si queremos instalar NiFi en nuestro sistema de
forma que nos implemente los servicios deberemos ejecutar
la siguiente opción:
~/nifi/nifi-1.8.0/bin$ ./nifi.sh install
Llegado a este punto tendríamos instalado NiFi, pero nos
faltaría optimizar algunos parámetros del sistema operativo
ya que no viene configurado para aplicaciones con un uso
intensivo de I/O como es el caso de Apache NiFi. Algunos
de los parámetros que debemos modificar son:
• Maximum File Hadles. NiFi puede necesitar abrir un
gran número de ficheros por los que necesitamos
incrementar los límites establecidos para los usuarios9
.
Para ello deberemos editar el “/etc/security/limits.conf” y
añadirle las siguientes líneas:
* hard nofile 50000
* soft nofile 50000
• Maximum Forked Processes. Tenemos que configurar
NiFi para que pueda generar un número elevado de
procesos. Para incrementar este límite, volvemos a
modificamos el fichero: “/etc/security/limits.conf”
* hard nproc 10000
* soft nproc 10000
En algunas distribuciones deberemos editar también el
fichero: “/etc/security/limits.d/90-nproc.conf “ en el que
deberemos añadir:
6. pág. 6
* soft nproc 10000
• Increase the number of TCP socket ports available. Esto
es particularmente importante si nuestro flujo de trabajo
abre y cierra muchos sockets en periodos cortos de
tiempo. Lo podemos modificar de la siguiente forma:
$ sudo sysctl -w net.ipv4.ip_local_port_range=”10000 65000”
O añadirlo de forma permanente en el /etc/sysctl.conf
• Set how long sockets stay in a TIMED_WAIT state
when closed. Si lo que queremos, es tener velocidad a la
hora de abrir y cerrar los sockets debemos modificar el
siguiente parámetro:
$ sudo sysctl -w
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait="1"
O añadirlo de forma permanente en el /etc/sysctl.conf
• Deshabilitar el uso de la swap. Para ello añadimos la
siguiente línea en el ‘/etc/sysctl.conf’:
vm.swappiness = 0
• Disable partition atime. En todas aquellas particiones en
las que funcione Apache Nifi, debemos deshabilitar
características como ‘atime10
’. Para ello deberemos editar
el fichero /etc/fstab y añadir ‘noatime’ en todas aquellas
particiones que se vean afectadas.
No me voy a extender más con los parámetros, pero en una
instalación real seguramente deberíamos optimizar alguno
más.
B. Ejecución desde Docker.
Para usar la imagen de Docker11
oficial bastará con ejecutar:
$ docker pull apache/nifi
Using default tag: latest
latest: Pulling from apache/nifi
Digest:
sha256:7a7586766ab9848d6b91f061b081748c9519075c3e41bcab7f501b8
bf4367cdf
Status: Image is up to date for apache/nifi:latest
Esto nos descargará a nuestro repositorio local la imagen de
apache NiFi. Lo podemos comprobar con:
$ docker images|grep nifi
apache/nifi latest 6c3cb8a4ae0e
2 months ago 1.83GB
Podemos encontrar el Dockerfile original y la documentación
en:
https://hub.docker.com/r/apache/nifi
10
“atime” es una propiedad del sistema de ficheros por la cual guarda el
“access time” cada vez que accedemos o leemos un fichero. Para evitar esto,
lo deshabilitamos mediante el uso de “noatime” optimizando
considerablemente el rendimiento del filesystem en determinados
escenarios.
Tenemos la opción de descargarnos el repo
(https://github.com/apache/nifi/tree/master/nifi-docker) con
el Dockerfile y crear la imagen mediante:
$ docker build -t apache/nifi:latest .
Esta imagen lleva incluido el toolkit de NiFi en la ruta
/opt/nifi/nifi-toolkit-current y la instalación del producto se
realiza en /opt/nifi/nifi-current . Podemos comprobar estas
rutas mediante:
$ docker run --rm --entrypoint /bin/bash apache/nifi -c
'env|grep NIFI'
NIFI_HOME=/opt/nifi/nifi-current
NIFI_LOG_DIR=/opt/nifi/nifi-current/logs
NIFI_TOOLKIT_HOME=/opt/nifi/nifi-toolkit-current
NIFI_PID_DIR=/opt/nifi/nifi-current/run
NIFI_BASE_DIR=/opt/nifi
Esta imagen la podemos ejecutar en modo standalone y
mediante dos métodos de autenticación12
:
• Two-Way SSL with Client Certificates.
• Lightweight Directory Access Protocol (LDAP)
Para levantar NiFi desde el docker bastará con ejecutar lo
siguiente:
$ docker run --name nifi -p 8080:8080 -d apache/nifi:latest
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
b35fad6a1380 apache/nifi:latest "../scripts/start.sh"
51 seconds ago Up 50 seconds 8443/tcp, 0.0.0.0:8080-
>8080/tcp, 10000/tcp nifi
Comprobamos que todo esta funcionando correctamente en
la url del producto: http://localhost:8080/nifi
Si queremos modificar alguna de las variables de arranque
podemos pasar variables a la imagen de la siguiente forma:
$ docker run --name nifi -p 9090:9090 -d -e
NIFI_WEB_HTTP_PORT='9090' apache/nifi:latest
39adbe525bdbed8ebc277e18910e31b3254758876c8a5c593940c55568cfb2
2f
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS
NAMES
39adbe525bdb apache/nifi:latest "../scripts/start.sh"
4 seconds ago Up 3 seconds 8080/tcp, 8443/tcp,
10000/tcp, 0.0.0.0:9090->9090/tcp nifi
Podemos ver las variables disponibles e incluso añadir o
modificar en el fichero:
https://github.com/apache/nifi/blob/master/nifi-
docker/dockerhub/sh/start.sh
Si queremos usar sólo la parte de las Toolkit lo podemos
hacer mediante:
$ docker run -d --name nifi apache/nifi
$ docker exec -ti nifi /opt/nifi/nifi-toolkit-
current/bin/cli.sh nifi current-user
anonymous
11
Necesitamos tener instalado Docker en nuestra distribución.
12
https://hub.docker.com/r/apache/nifi
7. pág. 7
$ docker exec -ti nifi /opt/nifi/nifi-toolkit-current/bin/cli.sh
_ ___ _
Apache (_) .' ..](_) ,
_ .--. __ _| |_ __ )
[ `.-. | [ |'-| |-'[ | /
| | | | | | | | | | ' '
[___||__][___][___] [___]', ,'
`'
CLI v1.8.0
Type 'help' to see a list of available commands, use tab to auto-
complete.
Session loaded from /home/nifi/.nifi-cli.config
#> exit
C. Archivos de configuración.
Llegado este punto ya podríamos tener levantado un
Apache NiFi así ahora nos vamos a centrar en examinar más
detenidamente sus ficheros de configuración.
Ilustración 6 Apache Nifi y sus ficheros de configuración. Basado
en: https://www.slideshare.net/IsheetaSanghi/apache-nifi-minifi-
meetup-slides?next_slideshow=1
1. conf/nifi.properties
Este es el archivo principal de configuración y se encuentra
dividido en diferentes secciones que contienen numerosas
variables pre-configuradas por defecto.
Se que es muy aburrido ver todas las variables de
configuración, pero me ha parecido interesante poner la
mayoría de las secciones para por lo menos verlas una vez.
# Core Properties #
nifi.flow.configuration.file=./conf/flow.xml.gz
nifi.flow.configuration.archive.enabled=true
nifi.flow.configuration.archive.dir=./conf/archive/
nifi.flow.configuration.archive.max.time=30 days
nifi.flow.configuration.archive.max.storage=500 MB
nifi.flow.configuration.archive.max.count=
nifi.flowcontroller.autoResumeState=true
nifi.flowcontroller.graceful.shutdown.period=10 sec
nifi.flowservice.writedelay.interval=500 ms
nifi.administrative.yield.duration=30 sec
# If a component has no work to do (is "bored"), how long should
we wait before checking again for work?
nifi.bored.yield.duration=10 millis
nifi.queue.backpressure.count=10000
nifi.queue.backpressure.size=1 GB
nifi.authorizer.configuration.file=./conf/authorizers.xml
nifi.login.identity.provider.configuration.file=./conf/login-
identity-providers.xml
nifi.templates.directory=./conf/templates
nifi.ui.banner.text=
nifi.ui.autorefresh.interval=30 sec
nifi.nar.library.directory=./lib
nifi.nar.working.directory=./work/nar/
nifi.documentation.working.directory=./work/docs/components
En este primer bloque encontramos algunos parámetros
interesantes como las configuraciones de las colas que
soportan las conexiones entre los procesadores. El
backpresure.count definir el número de mensajes capaz de
soportar hasta parar el procesador. Lo mismo para el
backpressure.size que definirá el tamaño máximo de la cola.
Manejar estos parámetros adecuadamente nos puede ayudar
a definir los intervalos de retención para nuestros flujos de
información.
nifi.queue.backpressure.count=10000
nifi.queue.backpressure.size=1 GB
Un parámetro muy interesante que afecta directamente al
rendimiento del funcionamiento de Apache NiFi es:
nifi.bored.yield.duration=10 millis
Este parámetro está diseñado para ayudar con el control de
uso de la CPU. Evita que los procesadores, que utilizan la
estrategia de programación controlada por temporizador,
utilicen de forma excesiva la CPU cuando no tienen trabajo
que realizar. El valor por defecto de 10 milisegundos ya tiene
un gran impacto en la reducción de la utilización de CPU. Si
nuestro flujo necesitará una menor latencia podremos bajar
este parámetro incrementando el uso de la CPU. Por el
contrario, si la latencia(controlada) no es un limitante
podemos aumentar este parámetro para reducir el uso de
CPU.
Otro parámetro interesante en esta sección afecta al impacto
del rendimiento del navegador:
nifi.ui.autorefresh.interval=30 sec
Esta propiedad establece el valor del tiempo de actualización
del navegador del cliente conectado. Podemos disminuir este
tiempo de actualización a costa de un mayor consumo de
procesamiento y un mayor ancho de banda. Deberemos tener
en cuenta el número de usuarios conectado ya que también
incrementa las necesidades de la aplicación. Apache NiFi
recomienda mantener el valor predeterminado y sólo
cambiarlo en entornos donde se necesiten ver estadísticas en
tiempo real. El usuario siempre tiene la opción de activar
manualmente la actualización.
# H2 Setting #
En esta sección se definen parámetros relacionados con las
bases de datos de uso interno.
nifi.database.directory=./database_repository
nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERV
ER=FALSE
NiFi usa dos bases de datos. Una para usuarios, donde realiza
un seguimiento de los logins en la aplicación simpre y cuando
estén habilitadas las opciones de login. Y una base de datos
de histórico donde se guardan los datos de los gráficos.
Normalmente no suelen ser bases de datos grandes.
La ruta de instalación predeterminada de estas bases de datos
suele ser <root-level-nifi-dir>/database_repository por lo
8. pág. 8
que el directorio se crea en el nivel raíz de la instalación de
NiFi (el mismo nivel que los directorios conf, bin, lib, etc.).
Si bien hay poco o ningún aumento de rendimiento al mover
esto a una nueva ubicación, se recomienda mover todos los
repositorios a una ubicación fuera de los directorios de
instalación de NiFi. Es poco probable que el usuario o las
bases de datos de historial cambien entre las versiones de
NiFi, por lo que moverlo fuera de la ruta de instalación básica
puede simplificar la actualización; permitiéndonos conservar
la información básica de usuario y el historial de
componentes después de la actualización.
# FlowFile Repository #
Aquí se definen los parámetros de configuración más
importantes del corazón de NiFi, el repositorio de FlowFiles.
En este repositorio es donde se mantiene el estado de todos
los FlowFiles actualmente ubicados en cualquier lugar de los
flujos de datos en la interfaz de usuario de NiFi. Si se
corrompe, existe la posibilidad de que podamos perder el
acceso a algunos o todos los archivos que corren por NiFi. La
causa más común de corrupción es el resultado de quedarse
sin espacio en el disco.
nifi.flowfile.repository.implementation=org.apache.nifi.contro
ller.repository.WriteAheadFlowFileRepository
nifi.flowfile.repository.wal.implementation=org.apache.nifi.wa
li.SequentialAccessWriteAheadLog
nifi.flowfile.repository.directory=./flowfile_repository
nifi.flowfile.repository.partitions=256
nifi.flowfile.repository.checkpoint.interval=2 mins
nifi.flowfile.repository.always.sync=false
nifi.swap.manager.implementation=org.apache.nifi.controller.Fi
leSystemSwapManager
nifi.queue.swap.threshold=20000
nifi.swap.in.period=5 sec
nifi.swap.in.threads=1
nifi.swap.out.period=5 sec
nifi.swap.out.threads=4
Vemos que la ruta por defecto es <root-level-nifi-dir>/
flowfile_repository.
Por temas de seguridad y rendimiento es recomendable que
este directorio se saque fuera de la instalación base donde
este soportado por un volumen con alto rendimiento de E/S.
En los sistemas de alto rendimiento, este repositorio nunca
debería estar con el repositorio de contenido que veremos en
las próximas secciones.
Otro parámetro a tener en cuenta de esta sección es el
siguiente:
nifi.queue.swap.threshold=20000
NiFi usa los FlowFiles como la unidad de transferencia de un
procesador a otro. Para que esto sea lo más rápido posible,
estos FlowFiles viven(felizmente) dentro de la RAM de la
JVM. Esta técnica es muy buena, hasta que comenzamos a
tener miles de FlowFiles y nuestra JVM comienza a sufrir por
falta de memoria. Para reducir la probabilidad de que esto
ocurra, NiFi define el umbral de FlowFiles que pueden vivir
en la memoria en una sola cola de conexión antes de ser
escritos en el disco. Una vez alcanzado el umbral se producirá
el intercambio a disco. Dependiendo de la frecuencia de
intercambio el rendimiento del sistema se puede ver afectado.
Para evitar esto deberemos encontrar el equilibrio entre este
umbral y la memoria disponible en la máquina virtual. Más
adelante veremos que las características de la máquina virtual
de java las configuraremos en el archivo bootstrap.conf.
# Content Repository #
Dado que el contenido para cada FlowFile que consume NiFi
se coloca dentro del repositorio de contenido, este directorio
soportará una gran demanda de I/O. Por esto, como en el caso
anterior se recomienda sacar esta ruta del directorio de
instalación básico.
nifi.content.repository.implementation=org.apache.nifi.control
ler.repository.FileSystemRepository
nifi.content.claim.max.appendable.size=1 MB
nifi.content.claim.max.flow.files=100
nifi.content.repository.directory.default=./content_repository
nifi.content.repository.archive.max.retention.period=12 hours
nifi.content.repository.archive.max.usage.percentage=50%
nifi.content.repository.archive.enabled=true
nifi.content.repository.always.sync=false
nifi.content.viewer.url=../nifi-content-viewer/
En ocasiones este repositorio puede ser muy demandante de
I/O por lo que un solo volumen puede ser escaso. Para
prevenir esto NiFi nos permitirá configurar múltiples
repositorios de contenido que puede usar de forma Road
Robin. La configuración de estos repositorios de contenido
adicional es relativamente sencilla. Deberemos comentar la
línea del contenedor default y añadir una nueva línea para
cada repositorio que queramos agregar, sustituyendo default
por el identificador único que queramos. Un ejemplo:
nifi.content.repository.directory.contS1R1=/cont-
repo1/content_repository
nifi.content.repository.directory.contS1R2=/cont-
repo2/content_repository
nifi.content.repository.directory.contS1R3=/cont-
repo3/content_repository
# Provenance Repository #
Esta sección hace referencia al repositorio de provenance y
será la última que trataremos. De forma similar al repositorio
de contenido, el repositorio de provenance puede usar una
gran cantidad de I/Os de disco para leer y escribir los eventos
de procedencia. También deberemos de tener en cuenta que
estas consultas de eventos se pueden hacer en paralelo por
diferentes usuarios por lo que necesitaremos un mayor
rendimiento de los discos.
La configuración predeterminada nos creará el repositorio de
provenance en la siguiente ruta:
nifi.provenance.repository.directory.default=./provenance_repo
sitory
Desde Apache NiFi nos recomiendan que este repositorio
este también es su propio volumen y que no lo comparta con
ninguno de los otros repositorios. Al igual que el repositorio
de contenido, se pueden definir múltiples repositorios de
provenance al proporcionar nombres únicos en lugar de
'default' y rutas:
nifi.provenance.repository.directory.provS1R1=/prov-
repo1/provenance_repository
9. pág. 9
nifi.provenance.repository.directory.provS1R2=/prov-
repo2/provenance_repository
La capacidad de consultar la información de procedencia de
los archivos suele tener un gran valor para ciertos tipos de
usuario. El número de subprocesos que están disponibles
para realizar estas consultas de procedencia se define en:
nifi.provenance.repository.query.threads = 2
En los sistemas en los que numerosos usuarios pueden
realizar consultas simultáneas en el repositorio de
procedencias, puede ser necesario aumentar el número de
subprocesos asignados a este proceso.
Si usamos a menudo esta característica puede ser interesante
modificar la cantidad de subprocesos que se usaran para
indexar los eventos de procedencia. El parámetro que
deberemos editar será:
nifi.provenance.repository.index.threads = 1
Para flujos que operan en un número muy alto de archivos de
flujo, la indexación de eventos de procedencia podría
convertirse en un cuello de botella. Si este es el caso,
aparecerá una notificación indicando: "La velocidad del flujo
de datos está excediendo la velocidad de registro de
procedencia. Disminuyendo la velocidad del flujo para
adaptarse". Si esto sucede, aumentar el valor de esta
propiedad puede aumentar la velocidad a la que el repositorio
de provenance puede procesar estos registros, lo que puede
resultar en una mejora del rendimiento general.
Otro parámetro que tenemos que tener en cuenta cuando
consultamos la procedencia es el tamaño del bloque
configurado ya que tiene impacto en la cantidad de
almacenamiento dinámico que se utilizará en el proceso. Esta
característica se configura en el siguiente parámetro:
nifi.provenance.repository.index.shard.size = 500 MB
Valores altos de este parámetro implicarán un mayor uso de
la pila de java pero proporcionará un mejor rendimiento. Si
aumentamos el tamaño del bloque, es posible que debamos
aumentar el tamaño de la memoria asignada a java. Por regla
general el tamaño de bloque debe ser más pequeño que el
50% del tamaño de almacenamiento configurado para el
repositorio de provenance que se configura en el siguiente
parámetro:
nifi.provenance.repository.max.storage.size
Para finalizar indicar que aunque este repositorio de
provenance no se puede desactivar, si podemos cambiar su
configuración de "PersistentProvenanceRepository" a
"VolatileProvenanceRepository" Esto provocará que toda la
información de referencia se almacenará en la memoria
asignada a la máquina virtual de java. Para evitar saturarla
podemos configurar el parámetro:
nifi.provenance.repository.buffer.size = 100000
13
Basado en: https://www.digitalocean.com/community/tutorials/how-to-
install-and-use-docker-on-ubuntu-18-04
Este valor se establece en bytes y mantendrá contenido el uso
de la memoria. Esta es una buena opción, pero tendremos un
historial de procedencia limitado.
En las nuevas implementaciones de Apache NiFi se está
implementando una nueva opción denominada
WriteAheadProvenanceRepository. Esta opción parece
mejorar los rendimientos para volúmenes altos de datos, pero
parece que actualmente presenta algunos problemas con la
reutilización de la memoria de la pila de java.
2. Archivo Bootstrap.conf
Este archivo de configuración nos permite configurar las
opciones de configuración inicial de NiFi. Esto incluye la
parametrización de java como el tamaño de la heap.
Este fichero también se divide en secciones.
# JVM memory settings #
java.arg.2=-Xms512m
java.arg.3=-Xmx512m
En esta sección controlamos la cantidad de memoria de
almacenamiento dinámico que puede utilizar la JVM de
Apache Nifi. Los parámetros básicos de configuración son
los que usamos normalmente en la configuración de java, por
un lado “Xms” definirá la asignación de memoria inicial y
“Xmx” la memoria máxima que podrá alcanzar la JVM.
Como podemos observar, los valores que vienen
configurados por defecto no son óptimos para entornos de
producción, por lo que los deberemos modificar en función
de nuestros recursos y necesidades. Valores que pueden ser
buenos para comenzar son de 4GB y 8GB respectivamente.
Un buen indicativo de que necesitamos tocar estos valores es
encontrar algún erro de “out of memory” en el log de la
aplicación de NiFi. Al aumentar el tamaño de esta memoria
tenemos que tener en cuenta los problemas de rendimiento
que podemos sufrir por el garbage collector por lo que se
recomienda realizar una configuración adecuada o utilizar un
garbage collector más eficiente.
III. EJEMPLO I.
Treas a realizar:
[1] Instalar docker y docker-compose.
[2] Levantar apache NiFi.
[3] Añadir y configurar los procesadores: GenerateFlowFile
y Putfile.
[4] Pruebas básicas de funcionamiento.
Para este primer ejemplo no vamos a ser muy originales y
vamos a ver un “hola mundo” en Apache Nifi. Para levantar
el entorno de pruebas usaremos una máquina virtual Ubuntu
(18.04) sobre la que levantaremos un Docker. La instalación
y optimización de Docker no es objeto de este documento por
lo que simplemente pondremos los comandos de instalación
sin explicación alguna13
:
$ sudo apt update
10. pág. 10
$ sudo apt install apt-transport-https ca-certificates curl
software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo
apt-key add –
$ sudo add-apt-repository "deb [arch=amd64] $
https://download.docker.com/linux/ubuntu bionic stable"
$ sudo apt update
$ sudo apt install docker-ce
$ sudo systemctl status Docker
$ sudo usermod -aG docker ${USER}14
Después de comprobar que docker funciona correctamente
pasamos a levantar nuestro entorno NiFi de pruebas. Para ello
simplemente ejecutaremos:
$ docker run --name nifi -p 8080:8080 -d apache/nifi:latest
Unable to find image 'apache/nifi:latest' locally
latest: Pulling from apache/nifi
bc9ab73e5b14: Pull complete
193a6306c92a: Pull complete
e5c3f8c317dc: Pull complete
d21441932c53: Pull complete
fa76b0d25092: Pull complete
346fd8610875: Pull complete
a77dac7d6f90: Pull complete
6907d655b86d: Pull complete
6b80dc86d1b8: Pull complete
2c6dbb557fc3: Pull complete
83ed9735618c: Pull complete
32697d3c6fd5: Pull complete
4ba9e676ab44: Pull complete
Digest:
sha256:7a7586766ab9848d6b91f061b081748c9519075c3e41bcab7f501b8
bf4367cdf
Status: Downloaded newer image for apache/nifi:latest
4ff09c12dd7564898cd46cd7d8c9e04dcf7d98b827afcb15098f23b3c9b7c3
79
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
1bf29337005f apache/nifi:latest "../scripts/start.sh"
4 seconds ago Up 3 seconds 8443/tcp, 0.0.0.0:8080-
>8080/tcp, 10000/tcp nifi
Podemos comprobar que NiFi está funcionando mediante el
navegador accediendo a localhost:8080/nifi ó
${IP_SERVER}:8080/nifi. También lo podemos comprobar
con un simple curl.
Ilustración 7 Consola inicial de Apache NiFi.
No vamos a explicar todas las opciones de la consola ya que
podemos encontrar toda la información necesaria en:
https://nifi.apache.org/docs.html
Una vez levantado nuestro bonito entorno de pruebas, vamos
a centrar un poco lo que queremos hacer. Crearemos un par
14
Esta parte es opcional y hace referencia a dar permisos de ejecución a un
usuario para ejecutar dockers. Normalmente funciona mejor poniendo
directamente el usuario y reiniciando la sesión.
de procesador, uno que nos generará FlowFiles a demanda y
otro que los recogerá y los escribirá en un fichero. Es un
ejemplo muy sencillo pero que nos servirá de base para
explicar algunos conceptos básicos.
Comenzaremos añadiendo nuestro primer procesador, para
ello debemos seleccionar el icono de
procesador y arrastrarlo hasta el panel
principal. En este momento nos
aparecerá una ventana emergente
donde nos aparecerán todos los procesadores que NiFi nos
ofrece por defecto (268). Podemos ampliar esta lista con
procesadores creados a medida mediante los ficheros .nar.
Ilustración 8 Ventana para añadir procesadores.
Para nuestro ejemplo, vamos a usar un procesador
denominado “GenerateFlowFile”. Para buscarlo podemos
usar el filtro de la parte superior derecha.
Ilustración 9 Ejempo1. selección de procesador.
Una vez seleccionado nos aparecerá nuestro primer
procesador. Indicar que el triángulo amarillo que nos aparece
es un indicador de que el procesador no está configurado
correctamente.
Ilustración 10 Ejemplo 1. Primer procesador añadido.
11. pág. 11
Para ver las operatorios que podemos realizar sobre el
procesador bastará con pulsar con botón derecho sobre el
mismo:
Ilustración 11 Ejemplo 1. Menu configuración procesador.
Seleccionamos la opción de configure y accederemos a la
parte de configuración del procesador.
Vamos a ir explicando un poco las diferentes secciones y a la
vez configurando nuestro nuevo procesador:
• Configuración (Settings). Esta pestaña nos permitirá
renombrar el procesador y cambiar las configuraciones de
las relaciones de terminación automática. Si un
procesador permite que se creen relaciones definidas por
el usuario (como RouteOnAttribute), también nos
aparecerían aquí después de crearse. Otras
configuraciones que podremos hacer hacen referencia al
rendimiento, duración y el manejo de reintentos.
Ilustración 12 Configure Processor. Settings.
En este parte sólo marcaremos el check de success para
definir la terminación de la relación.
• Planificación (Scheduling). NiFi proporciona varias
posibilidades de planificación para los procesadores. Para
la mayoría de los casos, el temporizador suele ser la
estrategia más apropiada, aunque podremos utilizar otras
como la basada en eventos. Deberemos tener en cuenta
los problemas de rendimiento de las diferentes
configuraciones. En esta misma pestaña también
podremos configurar el número de procesos adicionales
que puede usar el procesador.
Ilustración 13 Configure Processor. Scheduling.
Dejamos todo por defecto menos el tiempo de
planificación que lo pasamos a 5 segundos.
• Propiedades (Properties). En este apartado configuramos
las propiedades del procesador. En muchos casos
tendremos numerosas variables por defecto que
podremos configurar a las que les podemos añadir
aquellas que creamos necesarias.
En este caso vamos a modificar el tamaño del FlowFile
generado a 5kb y le vamos a añadir un texto customizado,
“Hola Mundo!!!!!!!!!”.
Ilustración 14 Configure Processor. Properties.
Podemos observar que una vez configurado el procesador
el icono del triángulo pasa a un cuadrado rojo indicando
que el procesador está parado.
• Comentarios (Comments). Nos permite añadir
comentarios sobre los procesadores para documentar un
poco el sentido del procesador en el flujo que ejecutamos.
Una vez configurado nuestro primer procesador pasamos al
segundo que será “PutFile” que nos permitirá escribir los
FlowFiles generados con anterioridad a fichero. Como en el
caso anterior accedemos a la configuración y modificamos el
apartado de settings en el que marcaremos los checkbox de
failure y success. Luego pasaremos a las Property y
simplemente añadiremos el directorio de destino (tmp).
12. pág. 12
Ilustración 15 ejemplo 1. PutFile processor. Propiedades.
Una vez configurado vamos a crear nuestra primera
conexión. Para ello nos ponemos encima del primer
procesador creado y nos aparecerá una flecha que
seleccionamos y arrastramos hasta el segundo procesador. En
ese momento nos aparecerá un cuadro de configuración
donde podremos definir cómo se va a gestionar la asociación
que acabamos de crear. Dejando de lado en la pestaña de
‘Details’ pasamos a ‘settings’ que es la realmente interesante.
Ilustración 16 Ejemplo 1. Propiedades conexión.
En este apartado encontraremos los siguientes parámetros de
configuración:
• Name. Nombre de la conexión.
• FlowFile Expiration. El tiempo máximo que el FlowFile
puede permanecer en la cola antes de ser eliminado.
• Back Pressure. Número máximo de objetos que pueden
ser almacenados en la cola antes de que el back pressure
comience a aplicarse.
• Size Threshold. Tamaño máximo de la cola.
• Load Balance Strategy. Como balancear los datos de esta
conexión en los nodos del clúster de NiFi. Las opciones
pueden ser:
o Do not load balance.
o Partition by attribute.
o Round robin.
o Single node.
• Prioritizers. Definimos el modo de selección de los
FlowFile de esta cola. Las opciones son las siguientes:
Este es nuestro primer ejemplo así que lo dejaremos todo por
defecto. Aunque en desarrollos más complejos puede ser
interesante estudiar estas configuraciones.
Después de esta sencilla configuración ya tenemos nuestro
primer flujo de datos implementado. Ahora podremos
ejecutarlo de forma secuencial o total desde el panel de
operación.
Ilustración 17 Panel de operación.
Ilustración 18 Ejemplo I.
Para esta primera prueba recomiendo lanzarlo de forma
secuencial para poder ir viendo lo que pasa en cada punto de
nuestro flujo. Comenzaremos lanzando el primer
procesador(GenerateFlowFile). El refresh está configura a 30
segundos así que si queremos ver como se están generando
los ficheros lo podremos hacer con botón derecho actualizar.
Veremos cómo los mensajes se nos están acumulando en la
cola de la conexión y no sólo eso, con botón derecho vemos
que nos aparecen opciones interesantes sobre esta cola:
13. pág. 13
Ilustración 19 Opciones de la cola.
Tendremos la opción de vaciar la cola, ver los históricos de
utilización de esta e incluso listar y ver los mensajes de la
misma. Para ello seleccionamos lo opción de “List queque”.
Ilustración 20 Listando el contenido de la cola.
Aunque en la imagen no se ve correctamente tenemos dos
botones muy interesantes. Uno al inicio que nos dará acceso
a los datos del FlowFile:
Ilustración 21 Visualización de contenido de una cola.
Esta es una funcionalidad muy interesante y nos puede
ayudar mucho a saber que está pasando en nuestro flujo de
datos.
El otro icono interesante lo encontramos al final y nos dará
acceso a los datos de procedencia. En este caso es muy
simple:
Ilustración 22 Esquema de procedencia.
Vamos a continuar con el ejemplo, arrancando todos los
procesadores y comprobando que los ficheros se están
creando en el tmp.
Ilustración 23 Ejemplo en ejecución.
Para comprobar si se están creando los ficheros, deberemos
entrar en la consola del Docker:
gauss@gauss-virtual-machine:~/NIFI/EJEMPLOS/Hola_mundo/tmp$
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
1bf29337005f apache/nifi:latest "../scripts/start.sh"
About an hour ago Up About an hour 8443/tcp, 0.0.0.0:8080-
>8080/tcp, 10000/tcp nifi
gauss@gauss-virtual-machine:~/NIFI/EJEMPLOS/Hola_mundo/tmp$
docker exec -i -t 1bf29337005f /bin/bash
nifi@1bf29337005f:/opt/nifi/nifi-current$
14. pág. 14
Una vez dentro nos vamos al directorio tmp y hacemos la
comprobación.
nifi@1bf29337005f:~$ cd /tmp/
nifi@1bf29337005f:/tmp$ ls
06cf354e-e067-4662-805b-e28627110b9d 2566dc4f-d19a-4ee7-9af1-
818f019b7641 551cbc7f-942a-4c1a-91db-98acb58aa97f 91fa4985-
b009-48ca-9716-c29ccd21b137 d46eebe1-c6ae-44e1-b569-
ea96848128d9
0754dfb5-d5a6-4c8c-8547-3ed5b9d70116 269f0d91-57f0-46ba-8e46-
c0084761e49b 5f44c5b2-c61f-4f52-b541-4f6dce0b16fd 95ffa794-
fc21-4937-8583-cd23c9e81a98 dbac411a-4825-47e9-89e5-
6f3a10f0a387
088e4f25-6536-40d7-9781-c6e40caabfa0 27e7702a-aecf-46a2-aee0-
d02c19f6b711 6ee250c2-7e9e-4570-a858-932a1eed3de0
…………………………………………….
nifi@1bf29337005f:/tmp$ cat 06cf354e-e067-4662-805b-
e28627110b9d
Hola Mundo!!!!!!!!nifi@1bf29337005f:/tmp$
Viendo que todo funciona correctamente podemos parar los
procesadores.
Antes de terminar este ejemplo vamos a ver cómo podemos
exportar estos flujos e importarlos. Para ello bastará con que
en la sección de operación seleccionemos el icono que
contiene un disco (Create template).
Nos aparecerá un pequeño cuadro en el que sólo nos piden el
nombre y una pequeña descripción. Con eso creamos nuestro
primer template. Si lo queremos descargar deberemos ir al
menú de configuración general y seleccionar la opción de
templates.
Ilustración 24 Opciones generales.
Ilustración 25 NiFi Templates.
El botón de la derecha nos permitirá descargarnos el template
en formato xml. Este fichero podría/debería ser guardado en
el repositorio de código correspondiente.
Para volverlo a cargar bastará con que seleccionemos la
opción de upload template de la consola de operate.
Finalmente desplegar un template se realiza desde el menú
de los procesadores.
Este ha sido un ejemplo sencillo, pero nos ha valido para
explicar algunos de los modos de funcionamiento de NiFi y
sobre todo familiarizarnos con en el entorno.
Este ejemplo y todos los demas estan disponibles en el
sigueinte repositorio de githup:
https://github.com/vthot4/poc_nifi
IV. EJEMPLO II.
Treas a realizar:
[1] Levantar infraestructura necesaria medainte el docker-
compose.
[2] Añadir y configurar los procesadores necesarios
[3] Pruebas básicas de funcionamiento.
En este ejemplo vamos a ver una integración sencilla
compuesta de los siguientes componentes:
Ilustración 26 Integración Twitter, Apache Kafka, MongoDB.
15. pág. 15
La prueba constará de una simple ingesta de datos desde
Twitter mediante un procesador de NiFi que nos permitirá
tratar e insertar esos datos en una cola de Kafka para que
finalmente sean escritos en MongoDB o en raw en un
filesystem. La idea es ver de forma general cómo funcionan
los diferentes componentes de NiFi y sobre todo probar el
control que nos ofrece sobre los flujos de datos de la prueba.
Primeramente, necesitamos levantar los diferentes
componentes, para ello hemos creado un simple Docker-
compose que nos permita levantar el entorno de forma ágil y
sencilla.
Si no tenemos instalado docker-compose en nuestro sistema
lo podemos hacer de la siguiente forma:
$ sudo curl -L
"https://github.com/docker/compose/releases/download/1.23.2/do
cker-compose-$(uname -s)-$(uname -m)" -o
/usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.23.2, build 1110ad01
El docker-compose que hemos creado para la prueba es el
siguiente:
---
version: '3.1'
## Component: PoC Nifi Ejemplo: Twitter-Kafka-MongoDB
## Version: 0.2
## Author: Versia Tecnologías Emergentes
##
networks:
labnet:
driver: bridge
services:
mongo:
image: mongo
container_name: Poc_nifi_mongodb
restart: always
ports:
- "27017:27017"
#environment:
#MONGO_INITDB_ROOT_USERNAME: root
#MONGO_INITDB_ROOT_PASSWORD:
networks:
- labnet
mongo-express:
image: mongo-express
container_name: Poc_nifi_mongo_express
restart: always
ports:
- "8081:8081"
environment:
#ME_CONFIG_MONGODB_ADMINUSERNAME: root
#ME_CINFIG_MONGODB_ADMINPASSWORD:
ME_CONFIG_BASICAUTH_USERNAME: admin
ME_CONFIG_BASICAUTH_PASSWORD: admin
depends_on:
- mongo
networks:
- labnet
zookeeper:
image: confluentinc/cp-zookeeper:latest
container_name: Poc_nifi_zookeeper
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
networks:
- labnet
kafka:
image: confluentinc/cp-kafka:latest
container_name: Poc_nifi_kafka
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS:
PLAINTEXT://kafka:29092,PLAINTEXT_HOST://kafka:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP:
PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
networks:
- labnet
nifi:
image: apache/nifi
container_name: Poc_nifi_nifi
ports:
- "8080:8080"
environment:
- NIFI_WEB_HTTP_PORT=8080
networks:
- labnet
Para levantar el entorno de pruebas bastará con ejecutar:
$ docker-compose up -d
Creating network "twitter_kafka_mongodb_labnet" with driver
"bridge"
Creating Poc_nifi_mongodb ... done
Creating Poc_nifi_zookeeper ... done
Creating Poc_nifi_nifi ... done
Creating Poc_nifi_mongo_express ... done
Creating Poc_nifi_kafka ... done
Podemos comprobar que todo esta levantado correctamente
mediante:
$ docker-compose -f docker-compose.yml ps
Name Command State
Ports
--------------------------------------------------------------
-----------------------------------------------
Poc_nifi_kafka /etc/confluent/docker/run Up
0.0.0.0:9092->9092/tcp
Poc_nifi_mongo_express tini -- /docker-entrypoint ... Up
0.0.0.0:8081->8081/tcp
Poc_nifi_mongodb docker-entrypoint.sh mongod Up
0.0.0.0:27017->27017/tcp
Poc_nifi_nifi ../scripts/start.sh Up
10000/tcp, 0.0.0.0:8080->8080/tcp, 8443/tcp
Poc_nifi_zookeeper /etc/confluent/docker/run Up
2181/tcp, 2888/tcp, 3888/tcp
Si quisiéramos ver más información de los procesos
levantados podríamos usar $ Docker-compose top .
En caso de que nos fallara alguno de los Dockers veríamos
los logs mediante:
$ docker-compose logs
$ docker-compose logs -f $Service
Una vez que tenemos levantado el entorno, accedemos a
nuestro Apache NiFi, mediante:
http://localhost:8080
Para cargar nuestro ejemplo, usaremos lo aprendido en el
ejemplo anterior e importaremos el template y luego lo
desplegaremos: Twitter-kafka-MongoDB.xml
Una vez importado tendremos algo parecido a esto:
16. pág. 16
Vamos a ir poco a poco viendo como funciona cada uno de
los componentes.
Comenzaremos con el procesador de Twitter que nos
permitirá realizar una recogida selectiva de datos desde
Twitter. Lo hemos seleccionado porque lo hemos
considerado una fuente rápida y sencilla de datos.
Para configurar este procesador necesitaremos dar de alta una
aplicación en Twitter para conseguir los tokens de acceso
necesarios. Deberemos ir a:
https://developer.twitter.com
Y loguearnos con nuestro usuario de Twitter y crear una
nueva app15
. Una vez creada tendremos algo como esto:
La parte que necesitamos la encontraremos en la pestaña de
“Keys and tokens”.
15
No voy a explicar como crear la app porque no es objeto de este
documento. Un ejemplo de guía puede ser: https://iag.me/socialmedia/how-
to-create-a-twitter-app-in-8-easy-steps/
Ilustración 28 Sección "Key and tokens" de Twitter app.
Teniendo estos datos, la configuración quedaría de la
siguiente forma:
Ilustración 29 Twitter Processor. Settings.
Ilustración 30 Twitter Processor. Scheduling.
Ilustración 31 Twitter Processor. Properties.
Ilustración 27 Flujo general Twitter-Kafka-MongoDB.
17. pág. 17
Las propiedades a configurar son:
• Twitter Endpoint. Podemos recoger todos los datos o
filtrados por termino o ID de usuario. En mi caso
seleccionamos “Filter Endpoint” para poder filtrar por un
termino en concreto.
• Datos proporcionados por la App de Twitter.
o Cosumer key.
o Consumer Secret.
o Access Token.
o Access Token Secret.
• Languages. Idoma de los tweets que vamos a recoger. En
mi caso “en”.
• Terms to Filter On. Enumeración separada por comas de
los términos que deseamos filtrar. En mi caso
“blockchain”.
Una vez configurado podemos comprobar que recoge datos
de forma correcta, seleccionando el procesador, botón
derecho y “Strart”.
Ilustración 32 Twitter Processor funcionando.
Vemos como el procesador se ha conectado correctamente y
ha traído 90 mensajes y los ha enrutado a sus dos salidas. Una
que simplemente nos escribirá los tweets en fichero y otra
más compleja que tratará los datos los colocará en Kafka y
luego los escribirá en MongoDB.
Podemos comprobar el contenido de los flowfiles en las
conexiones.
Nos aparecerá toda la lista de flowfiles y podremos ver el
contenido de alguno de ellos mediante la “i” de la izquierda.
Comprobamos que tenemos todo el contenido y que ha
filtrado correctamente por blockchain.
Ilustración 33 Ejemplo de tweet incrustado en un flowfile.
Vamos a comenzar con el flujo más sencillo y vamos a ver
como escribe estos FlowFiles en ficheros. Para ello vamos al
procesador “Put Raw File” y vemos un poco su
configuración.
Ilustración 34 Put Raw File processor. Settings.
Ilustración 35 Put Raw File. Scheduling.
Ilustración 36 Put Raw File. Properties
Para comprobar que toda ha ido bien, tendremos que
comprobarlo en el Docker de NiFi.
$ docker exec -i -t f9396945d85b /bin/bash
nifi@f9396945d85b:/opt/nifi/nifi-current$ cd /tmp/ejemplo_raw/
18. pág. 18
nifi@f9396945d85b:/tmp/ejemplo_raw$ ls
051a7cd6-8494-4b54-b23a-fccdee7c6ca7.json 471730f4-b9d3-41ac-
ad10-2f480be4e361.json 82c75310-9bc5-4ee1-8331-
52d83ad78c19.json be41f09b-ee5e-4a4a-9160-3f08b0601c0b.json
nifi@f9396945d85b:/tmp/ejemplo_raw$ cat 051a7cd6-8494-4b54-
b23a-fccdee7c6ca7.json
{"created_at":"Tue Jan 22 12:46:41 +0000
2019","id":1087693030004613120,"id_str":"1087693030004613120",
"text":"RT @aoife_keady: Advice on buying Blockchain from John
Biggs. ud83dude48 He bought some. Then with all the hype they
were worth more money and thenu2026","source":"u003ca
href="http://twitter.com" rel="nofollow"u003eTwitter Web
Clientu003c/au003e","truncated":false,"in_reply_to_status_i
d":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id"
:null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name"
:null,"user":{"id":3574988954,"id_str":"3574988954","name":"Em
ily
…………..
Ahora vamos a ver la segunda parte del flujo en la llevaremos
los datos hasta kafka y luego los insertaremos en MongoDB.
Ilustración 37 Flujo de inserción en Kafka y MongoDB.
El primer procesador que nos encontramos en este flujo será
el EvaluateJsonPath
Ilustración 38 EvaluateJsonPath Processor.
Añadiremos dos nuevas propiedades relacionadas con los
campos text y lang del JSON. En la parte superior derecha
pulsaremos el botón “New property”, asignando el nombre
“twitter.lang” y su valor “$.lang” a la nueva propiedad. Y, de
nuevo, los mismo pero para “twitter.text” con el valor
“$.text”.
En la pestaña “Settings” activaremos dos de los tres flasg que
se encuentran en la derecha: “failure” y “unmatched”.
Ilustración 39 EvaluateJsonPath Processor. Settings.
Ilustración 40 EvaluateJsonPath Processor. Scheduling.
Ilustración 41. EvaluateJsonPath Processor. Properties.
Ilustración 42 RouteOnAttribute Processor.
No hemos terminado todavía, nos falta añadir la relación
“matched” para el procesador “EvaluateJsonPath” para ello
añadiremos un nuevo procesador. Aunque en esta ocasión
filtraremos por “route” y seleccionando la opción
“RouteOnAttribute”. Añadiremos (Add).
Una vez creado el procesador, vamos a configurarlo (como
los anteriores). Le asignaremos un nombre si queremos y
activamos el flag “unmatched” de la parte derecha.
Ya en “Properties” añadimos una “New property”, le
ponemos un nombre y añadimos el valor:
19. pág. 19
“${twitter.text:isEmpty():not():and(${twitter.lang:equals(“e
s”)})}“
Con esto conseguimos filtrar aquellos tweets que estén vacíos
y cuyo idioma no haya sido marcado como español.
Añadimos (Add) y Aplicamos (Apply).
Si bien es cierto, este último paso también lo hubiésemos
podido realizar al principio, en el momento de configurar el
procesador “getTweets”.
Ya casi como último paso, procederemos a conectar el
procesador “EvaluateJsonPath” con el de
“RouteOnAttribute”. Ya en la nueva ventana, en la pestaña
“Details” tendremos la opción “For relationships”.
Activaremos el flag “matched”. En la pestaña “Settings”
volveremos a indicar la política que queremos aplicar, será la
misma que en el caso anterior: “FirstInFirstOutPrioritizer”
y Añadiremos (Add).
Ilustración 43 RouteOnAttribute Processor. Settings.
Ilustración 44 RouteOnAttribute Processor. Scheduling.
Ilustración 45 RouteOnAttribute Processor. Properties.
${twitter.text:isEmpty():not():and(${twitter.lang:equals("en
")})}
Una vez que tenemos enrutados los FlowFiles solo nos falta
configurar la inserción de los mensajes en una topic de Kafka
y de ahí lo persistiremos en la base de datos Mongo. Para ello
usaremos los procesadores: PutKafka y PutMongo, que
consifuramos como mostramos a continuación:
Ilustración 46 Inserción en kafka y en MongoDB.
Las variables a configurar en el procesador de PutKafka son
bastante sencillas:
Known Brokers: kafka:9092
Topic Name: TopicTweets
Client Name: PoC
Ilustración 47 PutKafka Processor. Properties.
Después de configurar este procesador pasamos a configurar
PutMongo, cuya configuración es bastante sencilla también.
Mongo URI: mongodb://mongo:27017
Mongo Database Name: Poc_Twitter
Mongo Collection Name: Messages
20. pág. 20
Ilustración 48 PutMongo Processor. Settings.
Ilustración 49 PutMongo Processor. Properties.
Una vez que hemos resuelto todas las conexiones podremos
probar nuestro flujo. Para comprobar que todo esta
funcionando correctamente a la hora de insertar los datos en
la base de datos hemos añadadido mongo_express a nuestro
docker-compose. Podemos dirigirnos a nuestro navegador y
acceder a la url:
http://localhost:8081 (admin/admin)
Nos aparecerá el explorador de la base de datos MongoDB.
Ilustración 50 MongoDB Express.
Comprobamos que los datos se están guardando
correctamente.
Ilustración 51 Ejemplo de tweet insertado en MongoDB.
Para terminar nuestra prueba vamos a añadir una segunda
rama que colgara desde el procesador de “RuteOnAttribute”
donde haremos un pequeño procesado de los datos y los
volveremos a insertar en el circuito Kafka-MongoDB. La
nueva rama presentará esta forma:
Ilustración 52 Flojo de inserción de tweets procesados.
Una vez enrutados los FlowFiles pasan al procesador
JoltTransformJSON que nos permitirá aplica una lista de
especificaciones Jolt a la carga útil JSON del archivo de
flujo. Se crea un nuevo FlowFile con contenido transformado
y se enruta a la relación de "éxito". Si la transformación
JSON falla, el FlowFile original se enruta a la relación 'falla'.
Para configurar este procesador bastará con introducir las
especificaciones Jolt.
Ilustración 53 JoltTransformJSON Processor. Properties.
Jolt Specification:
[{
"operation": "shift",
"spec": {
"created_at": "created_date_time",
"id": "tweet_id",
"text": "tweet_text",
"user": {
"id": "user_id"
}
}
},
{
"operation": "default",
"spec":{
21. pág. 21
"chainr-rating" : 4
}
}
]
Este procesador nos proporciona acceso al uso de Jolt16
. Esta
librería nos ofrece un enfoque declarativo para definir la
salida JSON. Jolt proporciona proporciona un conjunto de
tipos de transformación, cada uno con su propio DSL, que
define la nueva estructura para los datos JSON salientes.
Una vez transformados los FlowFiles pasan a entrar de nuevo
al circuito Kafka-MongoDB. En las imágenes podemos ver
que las configuraciones son muy parecidas que en la caso
anterior. Simplemente cambiamos el nombre de la Topic
Name a “TopoicTweets_Pro” y el nombre de la colección en
la que insertaremos los datos a “Message_Pro”.
Ilustración 54 PutKafka processor. Properties.
Ilustración 55 PutMongo Processor. Properties.
Si comprobamos de nuevo el formato del json introdocido en
la base de datos, comprobamos que presentan el formato
especificado en las especificaciones de Jolt.
16
https://github.com/bazaarvoice/jolt
Ilustración 56 Ejemplo de tweet procesado insertado en
MongoDB.
V. EJEMPLO III.
En este ejemplo cogeremos la base del ejemplo anterior e
insertaremos los datos en Elasticsearch. Como, ya
deberíamos haber cogido un poco de soltura con el entorno
vamos a poner sólo los esquemas fundamentales.
Ilustración 57 Esquema general EJEMPLO III.
Treas a realizar:
[1] Levantar infraestructura necesaria medainte el docker-
compose.
[2] Configurar el JSON obtenido de Twitter y enrutarlo.
[3] Guardar los JSON en Elasticsearch.
[4] Ver los resultados en Kibana.
Primeramente deberemos levantar nuestro entorno de
pruebas mediante el dockerfile disponible en el repositorio17
.
Antes de poder lanzar este docker-file deberemos
asegurarnos de que en nuestra máquina tenemos configurado
el siguiente parámetro:
$ sudo sysctl -w vm.max_map_count=262144
17
En el ejemplo se levanta con un nginx que nor redirige al Kibana. En
nuestro entorno lo podríamos omitir y simplemente atacar directamente al
kibana.
22. pág. 22
Sin este parámetro el clúster de elasticsearch no levanta
correctamente.
El docker-file que usaremos para la prueba es el siguiente:
---
version: '3.1'
## Component: Elasticsearch-kibana
## Version: 0.1
## Author: Versia Tecnologías Emergentes
##
networks:
labnet:
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.5.4
container_name: elasticsearch
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata1:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- labnet
elasticsearch2:
image: docker.elastic.co/elasticsearch/elasticsearch:6.5.4
container_name: elasticsearch2
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "discovery.zen.ping.unicast.hosts=elasticsearch"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata2:/usr/share/elasticsearch/data
networks:
- labnet
elasticsearch3:
image: docker.elastic.co/elasticsearch/elasticsearch:6.5.4
container_name: elasticsearch3
environment:
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "discovery.zen.ping.unicast.hosts=elasticsearch"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata3:/usr/share/elasticsearch/data
networks:
- labnet
kibana:
image: docker.elastic.co/kibana/kibana-oss:6.5.4
container_name: kibana
environment:
SERVER_NAME: localhost
ELASTICSEARCH_URL: http://elasticsearch:9200/
ports:
- 5601:5601
ulimits:
nproc: 65535
memlock:
soft: -1
hard: -1
networks:
- labnet
nginx:
image: nginx:latest
ports:
- 8090:80
volumes:
- ${PWD}/nginx-conf/:/etc/nginx/conf.d/
command: /bin/bash -c "nginx -g 'daemon off;'"
ulimits:
nproc: 65535
networks:
- labnet
nifi:
image: apache/nifi
container_name: Poc_nifi_nifi
ports:
- "8080:8080"
environment:
- NIFI_WEB_HTTP_PORT=8080
networks:
- labnet
volumes:
esdata1:
driver: local
esdata2:
driver: local
esdata3:
driver: local
Nota: No sería necesario levantar el cluster de elasticsearch,
para la prueba valdía con un entorno simple. Lo podríamos
levantar de la siguiente forma:
$ docker run -d --name elastic -p 9200:9200 -p 9300:9300
elasticsearch
Ó
$ docker run -p 9200:9200 -p 9300:9300 -e
"discovery.type=single-node"
docker.elastic.co/elasticsearch/elasticsearch:6.5.4
$ docker run -d --name kibana -p 5601:5601 -e
ELASTICSEARCH_URL=http://IP-HOST-DOCKER-ELASTIC:9200 kibana
$ sudo docker run -d --name nifi -p 8080:8080 apache/nifi
Para levantar la infraestructura necesaria bastará con ejecutar
$ docker-compose up -d
Creating network "twitter_elasticsearch_labnet" with the default
driver
Creating volume "twitter_elasticsearch_esdata1" with local
driver
Creating volume "twitter_elasticsearch_esdata2" with local
driver
Creating volume "twitter_elasticsearch_esdata3" with local
driver
Creating twitter_elasticsearch_nginx_1 ... done
Creating elasticsearch ... done
Creating Poc_nifi_nifi ... done
Creating elasticsearch3 ... done
Creating kibana ... done
Creating elasticsearch2 ... done
Comprobamos que todo esta levantado correctamente de la
siguiente forma:
$ docker-compose ps
Name Command State
Ports
--------------------------------------------------------------
------------------------------------------------------
Poc_nifi_nifi ../scripts/start.sh Up
10000/tcp, 0.0.0.0:8080->8080/tcp, 8443/tcp
elasticsearch /usr/local/bin/docker-entr ...
Up 0.0.0.0:9200->9200/tcp, 9300/tcp
elasticsearch2 /usr/local/bin/docker-entr ...
Up 9200/tcp, 9300/tcp
elasticsearch3 /usr/local/bin/docker-entr ...
Up 9200/tcp, 9300/tcp
kibana /usr/local/bin/kibana-docker
Up 0.0.0.0:5601->5601/tcp
twitter_elasticsearch_nginx_1 /bin/bash -c nginx -g 'dae ...
Up 0.0.0.0:8090->80/tcp
23. pág. 23
Podemos comprobar que Elasticsearch esta levantado con
una simple prueba:
$ curl localhost:9200
{
"name" : "B931ITV",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "oqR1Y2uXRxichyUoLx9m_A",
"version" : {
"number" : "6.5.4",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "d2ef93d",
"build_date" : "2018-12-17T21:17:40.758843Z",
"build_snapshot" : false,
"lucene_version" : "7.5.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
Y comprobamos que Kibana esta levantado mediante:
http://localhost:5601
Ilustración 58 Pantalla incial de Kibana.
Finalmente nos conectamos a la consola de Apache Nifi e
importamos el template “Twitter-Elasticsearch.xml”.
Una vez importado, lo
desplegamos de forma que nos
deberían de aparecer todos los
procesadores ya configurados. Lo
único que nos quedará por
establecer serán las claves de
acceso a Twitter.
Ilustración 59 template Ejemplo III.
Respecto a los ejemplos anteriores el único procesador nuevo
que aparece es “PutElasticsearchHttp” que nos permitirá
insertar los datos en Elasticsearch de forma sencilla.
Ilustración 60 PutElasticsearchHttp processor.
Deberemos establecer las siguientes propiedades:
• Elasticsearch URL: http://elasticsearch:9200
• Identifier Attribute: uuid
• Index: twitter
• Type: default
Ilustración 61PutElasticsearchHttp processor.Settings.
Ilustración 62 PutElasticsearchHttp processor. Properties.
Una vez que tenemos todo configura y los diferentes temas
de conexión solucionados pasamos a ejecutar la prueba.
Para poder ver los datos en Kibana deberemos crearnos un
patron de indice nuevo “twitter*”
24. pág. 24
Ilustración 63 Creando patron de indice nuevo en kibana.
Una vez creado ya podemos ver todos los datos en kibana,
donde podríamos crear nuestros cuadros de mando.
Ilustración 64 Visión de datos en Kibana.
Podríamos seguir desarrollando ejemplos interesantes, pero
creo que con los expuestos nos hacemos una ligera idea de
las capacidades de Apache NiFi. Entre las pruebas que hemos
realizado estarían las conexiones a bases de datos
Oracle/postgres. Recogida de ficheros vía ftp, llamadas a api
rest, ejecución de scripts,…….
Según vaya teniendo tiempo ire colgando los ejemplos en el
repositorio de githup.
https://github.com/vthot4/poc_nifi
VI. Flow Development Life cycle con NiFi y
NiFi registry.
Una de las principales caracaterísticas de Apache NiFi es la
capacidad de permitirnos diseñar flujos de datos complejos
desde una interfaz de usuario sencilla. Esta sencillez es muy
buena para probar flujos de forma ágil pero se puede
convertir en un problema cuando queremos abordar un ciclo
de desarrollo completo. Para solventar este problema nace,
entre otras cosas, Apache NiFi Registry que nos permitirá
gestionar el “Flow Development Life Cycle with NiFi
registries(FDLC)” dentro de nuestros entornos.
Ilustración 65 Flow Development Life Cycle. Fuente:
Hortonworks.
Cuando hablamos de implementar un FDLC nos refereimos
a implementar un desarrollo ágil que nos permita la
reutilización de componentes y un control de versiones
centralizado equivalente al de cualquier otro lenguaje de
programación. Los componentes reutilizables de Apache
NiFi se centran en las plantillas y las configuraciones. El
esquema general sería el siguiente:
Ilustración 66 Componentes reutilizables niFi. Source:
https://community.hortonworks.com/articles/60868/enterprise-nifi-
implementing-reusable-components-a.html.
Los templates y las configuracones son los componentes
principales que tenemos que tener en cuenta. Cuando
exportamos un flujo podemos crear un template que se
traduce un fichero xml que podemos almacenar en nuestros
repositorios de código. Gestionando este fichero de forma
correcta nos puede servir para gestionar los ciclos de
despliegue en nuestros entornos. El siguiente flujo describe
de forma muy clara el flujo de FDLC que deberíamos seguir:
Ilustración 67 FDLC mediante templates.Source:
https://community.hortonworks.com/articles/60868/enterprise-nifi-
implementing-reusable-components-a.html
25. pág. 25
Aunque esta opción puede ser válida, desde Apache NiFi
decidieron añadir nuevas herramientas que ayudasen a
abordar este tipo de problemáticas.
Cuando los desarrolladores de NiFi se enfrentaron al
problema de gestionar el FDLC optaron por dotar a NiFi de
dos funcionalidades separadas:
• Flow Registry. Es un subproyecto de Apache NiFi que
nos provee de un almacenamiento centralizado donde
compartir los recursos entre diferentes instancias de NiFi
o MiNiFi. Admite el almacenamiento, la recuperación y
la actualización de flujos versionados.
• Variable Registry. Nos proporcionara flexibilidad para
crear variables dinámicamente y consultarlas en las
propiedades de los componentes. No solo simplifica la
configuración mediante la reutilización de valores, sino
que también mejora la portabilidad de los flujos a nuevos
entornos. La gestión de estas variables se realiza a través
de la interfaz de usuario de NiFi a nivel de grupo de
proceso. Estas variables se pueden actualizar en tiempo
de ejecución sin reiniciar NiFi.
Vamos a ver como hacer una configuración básica y alguna
prueba de funcionaiento, para ello usaremos el siguiente
docker-compose.yml:
---
version: '3.1'
## Component: nifi
## Version: 0.1
## Author: Versia Tecnologías Emergentes
##
networks:
labnet:
services:
nifi:
image: apache/nifi
container_name: Poc_registry_nifi
ports:
- "8080:8080"
environment:
- NIFI_WEB_HTTP_PORT=8080
networks:
- labnet
nifi2:
image: apache/nifi
container_name: Poc_registry_nifi2
ports:
- "9090:9090"
environment:
- NIFI_WEB_HTTP_PORT=9090
networks:
- labnet
registry-nifi:
image: apache/nifi-registry:latest
container_name: Poc_registry_registry
ports:
- 18080:18080
environment:
- NIFI_WEB_HTTP_PORT=18080
networks:
- labnet
El entorno esta copuesto de dos Apache NiFi y un NiFi
registry que nos permitirán explorar la carácterísticas de esta
integración.
Para levantar el entorno bastara con:
~/nifi/poc_nifi/examples/Nifi_registry$ docker-compose -f
docker-compose.yml up -d
~/nifi/poc_nifi/examples/Nifi_registry$ docker-compose -f
docker-compose.yml ps
Name Command State
Ports
--------------------------------------------------------------
--------------------------------------------------------
Poc_registry_nifi ../scripts/start.sh Up
10000/tcp, 0.0.0.0:8080->8080/tcp, 8443/tcp
Poc_registry_nifi2 ../scripts/start.sh Up
10000/tcp, 8080/tcp, 8443/tcp, 0.0.0.0:9090->9090/tcp
Poc_registry_registry /bin/sh -c ${NIFI_REGISTRY ... Up
0.0.0.0:18080->18080/tcp, 18443/tcp
Podremos acceder a los diferentes servicios mediante:
• NiFi1: http://localhost:8080/nifi
• NiFi2: http://localhost:9090/nifi
• NiFi Registry: http://localhost:18080/nifi-registry/
Una vez que tenemos todo levantado, nos conectamos a la
consola del NiFi Registry.
Ilustración 68 Consola inicial NiFi Registry.
Lo primero que vamos a hacer es crear un nuevo “Bucket”
que a efectos prácticos será un nuevo repositorio. Para crearlo
bastará con que pulsemos el menu de settings que aparece en
la parte superior derecha y nos aparecerá la pantalla para
crear el nuevo repositorio. Le daremos el original nombre de
“Prueba”.
Ilustración 69 Añadiendo nuevo Bucket en NiFi Registry.
Una vez creado uestro nuevo bucket poco más podemos
hacer, ya que para poder habilitar permisos deberíamos
conectar nuestro entorno a un ldap o algo simlar.
Ahora vamos a conectar nuestro primer NiFi al NiFi registry.
En la parte superior derecha, desplegamos el menu y
seleccionamos “controller settings”. En el nuevo menu que
nos aparece seleccionamos la pestaña de “Registry clients” y
le damos al “+” para añadir nuestra instacia de NiFi registry.
Name: Nifi registry
URL: http://Poc_registry_registry:18080
26. pág. 26
Si todo ha ido bien, ya tendríamos que tener configurado
nuestro entorno de pruebas. Vamos a comenzar creando un
nuevo “Process Group” con nombre Prueba.
Ilustración 71 Añadiendo Process Group Prueba.
Una vez creado vamos a ver como configuramos
principalmente dos cosas:
• Variables.
• Versionado.
Para configurar las variables generales de un Process Group
bastará con que accedamos a su configuración → Variables.
Ilustración 72 Configurando un Process Group.
La ventana que nos aparce nos permitirá crear variables que
se podrán usar en todos los flujos que están dentro. De esta
forma podremos cambiar todas las configuraciones de forma
ágil. En este caso he creado dos variables de prueba:
kafka_broker: localhost
kafka_port: 9092
Ilustración 73 Configurando variables del Process Group.
Cuando le damos a aplicar vemos como el mismo hace una
reconfiguración de todos los processors que tengamos dentro
del grupo.
Ilustración 74 Reconfiguración de variables.
Si exportamos este flujo de trabajo y revisaramos el template
xml que nos crea podemos podemos ver esas variables que
acabos de crear:
Antes de pasar a ver como se implementan estas variables
que hemos creado vamos a hailitar el versionado de nuestro
componente. Para ello accedemos a la configuración –A
versión y “Start verion control”. Nos saldrá una pantalla
donde podremos escoger el servidor y repositorio en el que
queremos que se guarde. En nuestro caso:
Registry: Nifi registry
Bucket: Prueba
Flow Name: Insercción Kafka-Mongo
Ilustración 70 Añadiendo NiFi registry a NiFi.
27. pág. 27
Ilustración 75 Iniciando control de versiones del componente.
Ahora si volvemos a la parte de Version veremos que el menu
nos ha cambiado.
Continuemos con nuestra pequeña prueba añadiendo un par
de processor, para ello entramos en el Process Group de
prueba que hemos creado con anterioridad. En la parte
inferior izquierda podemos ver de forma simple donde nos
encontramos.
Ya situados añadiremos dos procesadores básicos, PutKafka
y PutMongo18
. El flujo quedará de la siguiente forma:
Ilustración 76 Flujo simple de prueba.
18
En esta prueba sólo busco ver las funcionalidades del Kafka Regstry por
lo que he optado por crear el flujo sin la infraestructura. Usando los ejemplos
anteriores es sencillo comoner la prueba real completa.
Para usar las variables bastará con ir a properties del objeto y
en lugar de añadir los valores poner las variables de la
siguiente forma:
Known Brokers: ${kafka-broker}:${kafka-port}
Añadidos nuestros cambios sobre el grupo de proceso prueba
volvemos a la parte de version de la configuración. Veremos
que nos aparcen las opciones de ver los cambios locales,
revertir los cambios y subir los nuevos cambios al
repositorio.
Ilustración 77 Opciones de la gestión de versionado.
Podemos añadir algunos procesadores
mas como un GenerateFlowfile y
realizar varios commits. Una vez
realizado poderemos ir a la opción de
change e ir recuperando las diferentes
versiones.
Podemos ver el historial de cambios
desde Apache Regsitry:
Ilustración 78 Change log niFi Registry.
28. pág. 28
Para terminar esta sencilla prueba podemos conectar el
segundo nifi que tenemos levantado al NiFi registry y probar
a crear un Process Group nuevo. Cuando añadimos el
componente nuevo podemos ver que tenemos la opción de
importar
Y nos aparecera la verdadera magia de NiFi registry.
Si se sube alguna nueva version del componente, nos
aparecerá una flecha roja en la parte superior izquierda:
Ilustración 79 Alerta de nueva versión en componente.
Actualizaríamos la versión y el componente cogería todos los
nuevos cambios19
.
Con esto ya tenemos a nuestra disposión un gestor de flujos
que nos puede ayudar a controlar su creación y producción
de forma ágil y centralizada.
A. Arquitectura interna.20
Vamos a ver un poco como esta implementado este
componente. En principio el interfaz de usuario es una
aplicación web creada con angular que se comunica con el
19
En algunos casos nos puede dar error si todavía quedan pendientes
pensajes de procesar en las colas intermedias. Normalmente deberemos
esperar a que se vacien o forzar parando flujos anteriores.
20
https://bryanbende.com/development/2018/06/20/apache-nifi-registry-0-
2-0
servidor mediante el API REST del registro de NIFI21
. Detrás
de esta API REST encontramos la capa de servicio donde se
implementa la lógica principal, la capa de servicio que
interactua con la la base de metadatos y el proveedor de
persistencia de flujo.
La base de metadatos almacenará la información sobre
grupos y elementos versionados, como identificadores,
nombres, descripciones y comentarios de confirmación. En
una primera versión se uso la base de datos H2 de forma
embebida pero en las nuevas versiones permite usar bases de
datos externas como postgres. Para llevar a cabo esta
configuración deberemos modificar algunos parámetros del
fichero de configuración:
nifi.registry.db.url=
nifi.registry.db.driver.class=
nifi.registry.db.driver.directory=
nifi.registry.db.username=
nifi.registry.db.password=
El proveedor de persistencia de flujo almacena el contenido
de cada flujo versionado y se considera un punto de extensión
público. Esto significa que se pueden proporcionar
implementaciones personalizadas implementando la interfaz
FlowPersistenceProvider. En la versión inicial se
implemento esta funcionalidad usando el sistema de archivos
local para la persistencia pero en las nuevas versiones se ha
implementado en base a git mediante el uso de la biblioteca
JGit. Esto nos proporciona la posibilidad de almacenar el
repositorio en un repo git.
El proveedor de git se puede configurar en el fichero de
configuración suppliers.xml:
<flowPersistenceProvider>
<class>
org.apache.nifi.registry.provider.flow.git.GitFlowPersistenceP
rovider
</class>
<property name="Flow Storage
Directory">./flow_storage</property>
<property name="Remote To Push"></property>
<property name="Remote Access User"></property>
<property name="Remote Access Password"></property>
</flowPersistenceProvider>
Con la propiedad “Flow Starage Directory” especificaremos
el directorio local que se espera que sea un repositorio git.
La propiedad "Remote To Push" especifica el nombre del
repositorio remoto al que se enviará automáticamente. Esta
propiedad es opcional y, si no se especifica, las
confirmaciones permanecerán en el repositorio local, a
menos que la subida la hagamos manualmente.
Resumiendo un poco los pasos para conectar nuestro
repositorio a git serían:
1. Crear un nuevo repositorio de GitHub y clonarlo
localmente.
21
Podemos ver la documentación del API en
https://nifi.apache.org/docs/nifi-registry-docs/index.html.
29. pág. 29
2. Establecer el Flow storage directory en el directorio
que se clonó el repositorio.
3. Crear un nuevo “Personal Access Token” para
nuestra instancia de Nifi Registry.
4. Establecer el “ Remote Access User” en GitHub.
5. Establecer “Remote Access Password” en el token
de acceso.
Ilustración 80 Source:
https://bryanbende.com/development/2018/06/20/apache-nifi-
registry-0-2-0
Otra funcionalidad interesante que presenta la arquitectura de
Apache NiFi Registry es la posibilidad de los “Event
Hooks”. Nos permitirá ejecutar código personalizado cuando
ocurran eventos de aplicación. Para implementar los event
hook, deberá ser implementada la siguiente interfaz de Java:
public interface EventHookProvider extends Provider {
void handle(Event event) throws EventHookException;
}
Donde el objeto evento contendrá un tipo de evento, junto
con una lista de pares campo/valor que son específicos de
cada evento. Algunos posibles eventos son:
CREATE_BUCKET
CREATE_FLOW
CREATE_FLOW_VERSION
UPDATE_BUCKET
UPDATE_FLOW
DELETE_BUCKET
DELETE_FLOW
Si no queremos meternos a implementar la interfaz de Java
podríamos configurar el “ScriptedEventHookProvider” que
nos permitiría ejecutar scripts para cada evento. La
configuración para este tipo de event hook sería:
<eventHookProvider>
<class>
org.apache.nifi.registry.provider.hook.ScriptEventHookProvider
</class>
<property name="Script Path"></property>
<property name="Working Directory"></property>
</eventHookProvider>
Los argumentos del script serán los campos de eventos en el
orden en que se especifican para el tipo de evento dado.
Como ejemplo, digamos que creamos un script llamado
logging-hook.sh con el siguiente contenido:
#!/bin/bash
echo $@ >> /tmp/nifi-registry-event.log
Para cada evento, esto reflejaría los argumentos del script y
los agregaría a /tmp/nifi-registry-event.log. Después de crear
un grupo y comenzar el control de versión en un grupo de
procesos, el registro debería mostrar algo como lo siguiente:
CREATE_BUCKET feeb0fbe-5d7e-4363-b58b-142fa80775e1 anonymous
CREATE_FLOW feeb0fbe-5d7e-4363-b58b-142fa80775e1 1a0b614c-3d0f-
471a-b6b1-645e6091596d anonymous
CREATE_FLOW_VERSION feeb0fbe-5d7e-4363-b58b-142fa80775e1
1a0b614c-3d0f-471a-b6b1-645e6091596d 1 anonymous v1
VII. Cluster NiFi.
Como vimos anteriormente, Apache NiFi presenta la
capacidad de clasterización mediante el uso de ZooKeeper
como coordinador. El esquema general que nos proponen en
la configuración es el siguiente:
Ilustración 81 Esquema de cluster Apache NiFi
Usa el paradigma de Zero-Master, en el que cada nodo del
clúster realiza las mismas tareas sobre los datos, pero cada
uno opera en un conjunto de datos diferente. Uno de los
nodos será elegido automáticamente como el coordinador del
clúster que pasará a gestionar el estado de los nodos.
Deberemos entender algunos conceptos antes de realizar una
configuración base:
• NiFi Cluster Coordinator. Un coordinador de
agrupaciones de NiFi es el nodo responsable de llevar a
cabo las tareas para gestionar qué nodos se permiten en
la agrupación y proporcionar el flujo más actualizado a
los nodos recién incorporados.
• Nodes. Cada gruopo se compone de uno o más nodos.
Los nodos son los que llevan a cabo el procesamiento
real de los datos.
• Primary Node. En cada clúster existe un nodo primario.
En este nodo es posible ejecutar “Procesadores
aislados”. Este nodo será elegido automáticamente por
ZooKeeper, de modo que si se desconecta del clúster,
otro nodo será elegido en su lugar. Los adminsitradores
podrán determinar que nodos pueden elegirse para ser
primarios desde la consola de administración.
30. pág. 30
• Isolated Processors. En un cluster Nifi, el mismo flujo
de datos se ejecuta en todos los nodos. Como resultado,
cada componente en el flujo se ejecuta en cada nodo.
Sin embargo, pueden existir casos en los que queramos
que los procesos sólo se ejecuten en el nodo primario
para evitar problemas en la ingesta de datos. Para estos
casos podemos configurar los procesadores aislados.
• Heartbeats. El nodo principal recibe el estado de salud
del resto de nodos mediante el “hearbeat(latidos)”. De
forma predeterminada, los nodos emiten hearbeats cada
5 segundos. Si el coordinador no recibe esta señal
durante 40 segundos, desconectará el nodo. Si, después
de 40 segundos, el nodo envía de nuevo un latido, el
coordinador solicitará automáticamente que el nodo
vuelva a unirse al clúster. Estas configuraciones de
tiempo de hearbeat y tiempo de espera hasta
desconexión se pueden configurar en el fichero
“nifi.proprties”.
Entendidos algunos de los conceptos básicos vamos a probar
a levantar un pequeño clúster usando una funcionalidad muy
interesante de docker-compose. Usaremos el siguiente
docker-compose:
---
version: "3.1"
## Component: nifi
## Version: 0.2
## Author: Versia Tecnologías Emergentes
##
services:
zookeeper:
hostname: zookeeper
container_name: zookeeper
image: 'bitnami/zookeeper:latest'
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
nifi:
image: apache/nifi
ports:
- 8080
environment:
- NIFI_WEB_HTTP_PORT=8080
- NIFI_CLUSTER_IS_NODE=true
- NIFI_CLUSTER_NODE_PROTOCOL_PORT=8082
- NIFI_ZK_CONNECT_STRING=zookeeper:2181
- NIFI_ELECTION_MAX_WAIT=1 min
Y lo levantaremos medainte:
$ docker-compose -f docker-compose-cluster.yml up --scale nifi=3
-d
$ docker-compose -f docker-compose-cluster.yml ps
Name Command State Ports
--------------------------------------------------------------
---------------------------------
nifi_nifi_1 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32775->8080/tcp, 8443/tcp
nifi_nifi_2 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32776->8080/tcp, 8443/tcp
nifi_nifi_3 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32777->8080/tcp, 8443/tcp
zookeeper /app-entrypoint.sh /run.sh Up 2181/tcp,
2888/tcp, 3888/tcp
Podremos acceder a nuestro nuevo cluster vía los puertos:
32775,32776 ó 32777. Estos puertos se generan de forma
semi-aleatoria así que hay que comprobarlos después de cada
arranque.
Una vez que tenemos todo levantado podemos acceder y
desde el menu lateral, entrar en las opciones del cluster. Nos
debería de aparecer algo parecido a esto:
Ilustración 82 Consola de administración del cluster.
En esta consola de administración tenemos varias pestañas
que nos proporcionan información sobre el estado del cluster:
• Nodes. Muestra información sobre el direccionamiento
de los nodos, tamaño de las colas y el estado. En la parte
de estado podemos ver que rol tiene cada nodo en el
clúster y los últimos datos de hearbeat. Desde esta vista
también podemos desconectar los nodos que queramos.
• System. Nos proporciona información sobre los
recursos que dispone la máquina sobre la que corre el
nodo. Se muestra número de cores, el load de los cores
y el número de Threads.
• JVM. Información destacada del uso de la máquina
virtual de java en cada nodo.
Ilustración 83 Administración clúster. JVM.
• Storage. Disponemos de tres pestañas destinadas a
mostrar los porcentajes de uso del FlowFile storage,
Content Storage y Provenance Storage.
• Versions. Nos permite ver de forma ágil, las versiones
de los productos de nuestro clúster.
Ilustración 84 Administración clúster. Versions.
No me voy a extender mucho más, aunque sería interesante
hacer pruebas de HA para ver como cambia el master y
analizar como se comportan los flujos. Sólo indicar que ahora
desde la pestaña de scheduling de los processors podremos
decidir si se va a ejectuar en todos los nodos o solo en el
primario.
31. pág. 31
Ilustración 85 Scheduling execution.
Con esta forma de levantar el cluster podemos probar a
escalar hacia arriba y hacia abajo el número de nodos a
nuestra voluntad.
$ docker-compose -f docker-compose-cluster.yml up --scale nifi=8
-d
Starting nifi_nifi_1 ...
Starting nifi_nifi_1 ... done
Starting nifi_nifi_2 ... done
Starting nifi_nifi_3 ... done
Creating nifi_nifi_4 ... done
Creating nifi_nifi_5 ... done
Creating nifi_nifi_6 ... done
Creating nifi_nifi_7 ... done
Creating nifi_nifi_8 ... done
$ docker-compose -f docker-compose-cluster.yml ps
Name Command State Ports
--------------------------------------------------------------
---------------------------------
nifi_nifi_1 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32775->8080/tcp, 8443/tcp
nifi_nifi_2 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32776->8080/tcp, 8443/tcp
nifi_nifi_3 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32777->8080/tcp, 8443/tcp
nifi_nifi_4 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32780->8080/tcp, 8443/tcp
nifi_nifi_5 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32781->8080/tcp, 8443/tcp
nifi_nifi_6 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32778->8080/tcp, 8443/tcp
nifi_nifi_7 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32782->8080/tcp, 8443/tcp
nifi_nifi_8 ../scripts/start.sh Up 10000/tcp,
0.0.0.0:32779->8080/tcp, 8443/tcp
zookeeper /app-entrypoint.sh /run.sh Up 2181/tcp,
2888/tcp, 3888/tcp
Y si tenemos un poco de paciencia, podremos ver algo como
esto:
VIII. MiNiFi.
MiNiFi, es un subproyecto de Apache NiFi, que nace con un
enfoque más orientado a la recopilación de datos en origen.
Esto le permitirá a NiFi aumentar el control sobre el flujo de
datos. Los objetivos específicos para el impulso inicial del
esfuerzo de MiNFi incluyen:
• Pequeño tamaño y bajo consumo de recursos.
• Gestión central de agentes.
• Generación de procedencia de datos (Cadena completa de
custodia de la información).
• Integración con NiFi para la gestión de flujo de datos de
seguimiento.
Siguiendo estos objetivos optaron por eliminar toda la parte
de la consola y reducir los procesadores a un número
reducido aunque siempres e pueden añadir si los
necesitamos. El esquema general de MiNiFi queda de la
sigueinte forma:
Figure 1 MiNiFi Java Processes. Source: HortonWorks.
Existen numerosas posibilidades para el binomio MiNiFi-
NiFi, pero una de las más interesantes es la de gateway de
IoT. No vamos a desarrollar los ejemplos en este documento,
pero pongo dos enlaces a proyectos muy interesantes y fáciles
de implementar.
Por un lado esta la centralización de datos recogidos
mediante protocolos MQQT. Podemos encontrar la
documentación del desarrollo en:
https://medium.freecodecamp.org/building-an-iiot-system-
using-apache-nifi-mqtt-and-raspberry-pi-ce1d6ed565bc
Y el esquema sería el siguiente:
Ilustración 86 Arquitectura IoT. Source:
https://medium.freecodecamp.org/building-an-iiot-system-using-
apache-nifi-mqtt-and-raspberry-pi-ce1d6ed565bc
Mosquitto se encargaría de recibir los datos mediante mqqt
desde los sensores y MiNiFi estaría enganchado a los