• Saltar a la navegación principal
  • Saltar al contenido principal
  • Saltar al pie de página
Bluetab

Bluetab

an IBM Company

  • Soluciones
    • DATA STRATEGY
    • DATA READINESS
    • DATA PRODUCTS AI
  • Assets
    • TRUEDAT
    • FASTCAPTURE
    • Spark Tune
  • Conócenos
  • Oficinas
    • España
    • Mexico
    • Perú
    • Colombia
  • talento
    • España
    • TALENT HUB BARCELONA
    • TALENT HUB BIZKAIA
    • TALENT HUB ALICANTE
    • TALENT HUB MÁLAGA
  • Blog
  • English

Bluetab

KubeCon 2023: Una mirada hacia el futuro de Kubernetes

abril 26, 2023 by Bluetab

KubeCon 2023: Una mirada hacia el futuro de Kubernetes

Lucas Calvo

Cloud Engineer

Javier Pérez

Practice Lead for MLOps

Ángel Maroco

Enterprise Architect

Como es costumbre en Bluetab, desde hace ya varios años asistimos a la KubeCon + CloudNative Europa 2023 celebrada en Amsterdam, el evento tecnológico líder a nivel mundial en referencia a Kubernetes, Cloud Native y tendencias DevOps.

Durante esta conferencia, que reúne a miles de desarrolladores, ingenieros y expertos en tecnología de todo el mundo, hemos tenido la oportunidad de adquirir ideas innovadoras para nuestro trabajo. 

Además, pudimos presenciar casos de uso reales de las principales empresas a nivel mundial, lo que nos permitió adentrarnos en los desafíos complejos que enfrentan las grandes organizaciones en la actualidad.

En este artículo, nos proponemos explorar algunas de las tendencias y temas clave que captaron nuestra atención durante este destacado evento. 

El año pasado nos despedimos de la KubeCon 2022 de Valencia descubriendo las capacidades que convertían al Gateway API como un API oficial, graduado de incubación a beta, simplificando el modelo de service networking en Kubernetes, incluyendo nuevos objetos como GatewayClass, Gateway, HTTPRoute, TCPRoute, etc. 

El Gateway API es un proyecto mantenido por el SIG de Networking, en continua evolución, y este año empezamos la KubeCon 2023, esta vez en Amsterdam, justo donde lo dejamos el año pasado, con las novedades que nos trae este grupo de trabajo sobre la evolución del Gateway API, graduado de Beta a GA, incluyendo las capacidades de Multi-Cluster Services.  

Sin lugar a dudas, uno de los temas principales en los últimos días ha sido cómo se pueden desplegar aplicaciones en plataformas Multi-Cluster, mejorando la disponibilidad y reduciendo la latencia. Hace un tiempo, la sincronización de clusters era una tarea complicada, que podría llegar a requerir cierto trabajo manual dependiendo del entorno en que trabajemos.

Afortunadamente, mediante la evolución de las APIs de Kubernetes, podemos simplificar este problema con el Gateway API haciendo uso de los servicios de Multi-Cluster, habilitando la gestión avanzada del routing entre diferentes clusters. 

Este caso de uso nos permite abordar situaciones donde tenemos una falla catastrófica, como la pérdida de una región o zona de computación, en la cual están localizadas las máquinas que ejecutan nuestras aplicaciones, ofreciendo una conmutación instantánea del tráfico de un cluster a otro. 

Si, por ejemplo, tenemos una sistema ejecutando para USA y Europa a la vez, podemos elegir a dónde redirigir la carga de trabajo: de forma local a los orígenes de tráfico, minimizando la latencia, y usar la otra región del mundo para ser resilientes.

La unión de varias APIs de Kubernetes no abre nuevas oportunidades para lograr nuestros objetivos, aunque todavía estamos en los primeros pasos de estos proyectos, os animamos a que os pongáis al día con alguna de sus implementaciones[1].

En la edición del año pasado vimos como uno de los principales temas de interés fue la orquestación de cargas de trabajo mediante técnica de Advanced Scheduling. Trabajar en el ámbito big data es siempre un reto, pero si añadimos kubernetes, se abre la oportunidad de emplear otros paradigmas que coordinan pods para realizar trabajos individuales.

Si tradicionalmente nos encontramos ante falta de recursos como principal fuente de problemas, en kubernetes también se pueden generar problemas de inanición debido al scheduler original, sin olvidar cómo gestionar el sistema de shuffle de datos entre los ejecutores de las aplicaciones. 

Uno de los puntos más relevantes y críticos es la parte de monitorización y observabilidad. Buena parte de las ponencias giran en torno a estos dos ámbitos debido a la necesidad de las organizaciones de conocer en tiempo real el estado del cluster, servicios y despliegues.

También este año, con la explosión de las plataformas multi-cluster llega un nuevo reto, monitorizar y centralizar todas las métricas de tus distintos clusters para mantener la integridad de tu arquitectura. Para esto vienen viejos conocidos como Prometheus, Grafana, Thanos, Cortex, etc. para resolver esta problemática. 

Además, cada vez se hace más énfasis en la monitorización y alertado defensivo, es decir, como usar tus herramientas para saber cuándo, cómo y dónde estás recibiendo algún ataque en tu plataforma, ya sea un ataque DDoS, ataques por inyección de SQL o hasta analizar el consumo de tus propios pods por si hubiera algún consumo elevado que pudiera ser por un posible crypto-mining.

Para esto cada vez la monitorización va más de la mano de la analítica de datos y analítica avanzada para buscar patrones en las métricas de tu plataforma y poder evitar cualquier tipo de fallo o incidencia.

La unión de Monitorización y Seguridad no solo se percibe en la evolución de los proyectos del CNCF, sino también en cómo afecta a las organizaciones. Este año destaca cómo las organizaciones comienzan a adoptar un modelo de gestión donde un equipo dedicado  acumula cada vez más tareas, como revisar el control de acceso de los usuarios,  gestionar la asignación de las políticas de seguridad, revisar el rendimiento de la infraestructura de datos u otras tareas según la organización.

No queríamos terminar la experiencia sin hablar de la nueva tecnología que está oculta actualmente en varios proyectos de la CNCF: “extended Berkeley Packet Filter” (eBPF)[2].

El origen de esta tecnología recae en el grupo de trabajo de tcpdump, donde se desarrolló para analizar el tráfico de red sin impactar en el rendimiento de las aplicaciones. Sin embargo, se ha visto claramente extendido su uso en términos de seguridad y monitorización. 

A modo resumen, eBPF permite ejecutar un código de usuario a nivel de kernel-space, teniendo acceso a las estructuras de memoria sin restricciones. Esto se realiza mediante unos hook que tiene programados el propio kernel de linux para habilitar el punto de entrada de la función.

eBPF requiere un kernel moderno, puesto que es una tecnología en incubación, siendo incluso posible que un mismo programa no llegue a funcionar entre diferentes sistemas operativos debido a las modificaciones que está realizando del propio kernel, aún con ello os animamos a explorar su utilidad. 

Conclusiones

  • La KubeCon 2023 ha sido una experiencia enriquecedora. Compartir ideas y conocimientos con otros expertos del ámbito de contenedores y cloud native nos permite debatir nuevas visiones y confirmar que Bluetab está trabajando en la línea correcta. Como siempre, las sesiones son de gran utilidad y abarcan las nuevas características y funcionalidades que podemos esperar en los próximos meses para Kubernetes.
  • Kubernetes continúa manteniendo su posición como la plataforma líder en el campo de la orquestación de contenedores. Sin embargo, también es importante reconocer que su adopción por parte de las organizaciones no está exenta de desafíos. Si bien se han logrado significativos avances en áreas como la construcción de imágenes, la integración continua y la implementación continua (CI/CD), el despliegue automatizado con infraestructura como código y el almacenamiento distribuido, aún persisten retos críticos en el ámbito de la seguridad que requieren atención.
  • La escalabilidad sigue siendo una de las principales preocupaciones para las organizaciones. En esta KubeCon 2023 se han presentado nuevas soluciones y mejores prácticas que están ayudando a abordar la gestión de los clusters de forma efectiva y sostenible entre los que destaca los servicios de Multi-Cluster para Networking y Observability.
  • El apartado de inteligencia artificial y analítica avanzada ha quedado relegado a un segundo plano en esta conferencia, incluso siendo el año donde más se está hablando de LLM, y su llamativo uso intenso de recursos de cómputo. A destacar entre las pocas charlas que hubo de este tema las centradas en la parte de Kubeflow y MLOps y sobre todo la última charla del viernes donde se trataban temas de HPC[3] y daban ciertas pinceladas sobre el uso de Flux[4] y Flux Operator[5] y la creación de mini cluster para aprovechar al máximo las capacidades de Kubernetes.

Referencias

https://gateway-api.sigs.k8s.io/implementations/

https://www.tcpdump.org/papers/bpf-usenix93.pdf

https://www.youtube.com/playlist?list=PLj6h78yzYM2NHzRYIwDwiTaoogfv8bO5i

https://github.com/flux-framework

https://github.com/flux-framework/flux-operator

Lucas Calvo

Cloud Engineer

Javier Pérez

Practice Lead for MLOps

Ángel Maroco

Enterprise Architect

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

¿Cómo pueden las empresas asegurarse de que sus datos estén estructurados, escalables y disponibles cuando se necesiten?

septiembre 13, 2024
LEER MÁS

Big Data e IoT

febrero 10, 2021
LEER MÁS

Bluetab se certifica como AWS Well Architected Partner Program

octubre 19, 2020
LEER MÁS

Mi experiencia en el mundo de Big Data – Parte II

febrero 4, 2022
LEER MÁS

El futuro del Cloud y GenIA en el Next ’23

septiembre 19, 2023
LEER MÁS

Snowflake, el Time Travel sin DeLorean para unos datos Fail-Safe.

febrero 23, 2023
LEER MÁS

Publicado en: Tech

LA BANCA Y LA ERA DEL OPEN DATA

abril 19, 2023 by Bluetab

LA BANCA Y LA ERA DEL OPEN DATA

Julian Andres Delgadillo

Director comercial - Consultor en Inteligencia de Negocios, Big Data y Analítica

El pasado 17 de Marzo concluyó en Cali el 13° Congreso de Acceso a Servicios Financieros y Medios de Pago CAMP organizado por Asobancaria en Colombia, un evento de dos días cuyo objetivo es conocer sobre impacto de las innovaciones tecnológicas en la prestación de servicios financieros y los avances para desarrollar una economía digital.

Aunque la agenda de este evento anual normalmente contiene temas de alta relevancia relacionados con medios de pago como puentes entre la informalidad y la bancarización de la población, así como el acceso a servicios financieros a sectores económicos en la ruralidad, en los últimos años los temas asociados al Open banking, Open Finance y Open data vienen abarcando más espacio en la agenda del evento puesto que facilitan la bancarización pero al mismo tiempo están siendo consideradas como “armas de doble filo” por lo cual existen muchos temas asociados a la regulación que se están definiendo en este momento.

Según la hoja de ruta trazada por la super intendencia financiera de Colombia (SIC), en 2026 se debería estar finalizando la última etapa de implementación de la regulación en torno al open data para entidades financieras. Es importante entonces establecer la diferencia entre estos tres conceptos para poder hablar de los mencionados desafíos:

Open Banking, Open Finance y Open Data son términos que a menudo se confunden, pero que en realidad son conceptos distintos.

Open Banking se refiere a la práctica de compartir datos financieros entre diferentes instituciones financieras, de manera segura y estandarizada, para brindar a los clientes un mejor acceso a sus datos y una mayor transparencia en cuanto a la gestión de sus finanzas. La idea es que los clientes puedan compartir sus datos con otras instituciones financieras, permitiendo así que estas puedan ofrecer productos y servicios financieros personalizados y más adecuados a sus necesidades.

Por otro lado, Open Finance es una extensión del concepto de Open Banking, pero en lugar de limitarse a la banca tradicional, incluye todas las empresas financieras que ofrecen productos y servicios financieros, como las aseguradoras, las empresas de inversión y las empresas de gestión de patrimonio. De esta forma, el concepto de Open Finance amplía la cantidad de datos que pueden compartirse y la cantidad de empresas que pueden beneficiarse de ello.

Finalmente, Open Data se refiere a la idea de que los datos deben ser accesibles y utilizables por cualquier persona o empresa, sin restricciones o barreras. Esto incluye no solo los datos financieros, sino cualquier tipo de datos que puedan ser relevantes para la toma de decisiones, el desarrollo de productos y servicios o la investigación. La idea detrás de Open Data es que al hacer que los datos sean más accesibles y disponibles, se puede impulsar la innovación y el progreso en distintos ámbitos.

En resumen, Open Banking se enfoca en la banca tradicional, mientras que Open Finance abarca todo el sector financiero, y Open Data se refiere a la apertura de datos en general, más allá del sector financiero. Cada uno de estos conceptos tiene el potencial de impulsar la innovación y mejorar la calidad de los servicios y productos ofrecidos, lo que podría beneficiar tanto a las empresas como a los consumidores.

Sin duda, se avecinan cambios de paradigma importantes no solo para los clientes, también para las entidades del sector financiero que de la mano de estos cambios, experimentarán el surgimiento de nuevas necesidades en torno al tratamiento de datos, conocimiento del cliente, diseño de productos, seguridad y estrategias comerciales que se pueden comenzar a cubrir desde la base de una combinación eficiente de  procesos, personas y tecnología para adaptarse a las nuevas condiciones de juego.

En Bluetab, gracias a nuestra experiencia de mas de 15 años enfocados en la gestión del ciclo de vida de los datos, estamos listos desde ya para acompañar a nuestros clientes a recorrer este camino del Open Data.

Julian Andres Delgadillo

Director comercial - Consultor en Inteligencia de Negocios, Big Data y Analítica

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Mi experiencia en el mundo de Big Data – Parte I

octubre 14, 2021
LEER MÁS

Cómo depurar una Lambda de AWS en local

octubre 8, 2020
LEER MÁS

Detección de Fraude Bancario con aprendizaje automático

septiembre 17, 2020
LEER MÁS

Análisis de vulnerabilidades en contenedores con trivy

marzo 22, 2024
LEER MÁS

Serverless Microservices

octubre 14, 2021
LEER MÁS

De documentos en papel a datos digitales con Fastcapture y Generative AI

junio 7, 2023
LEER MÁS

Publicado en: Tech

LakeHouse Streaming en AWS con Apache Flink y Hudi

abril 11, 2023 by Bluetab

LakeHouse Streaming en AWS con Apache Flink y Hudi

Alberto Jaen

AWS Cloud Engineer

Alfonso Jerez

AWS Cloud Engineer

Adrián Jiménez

AWS Cloud Engineer

Introducción

Cada día la ingesta y procesamiento de streams de datos en Near Real Time (NRT) es más necesario. Los requisitos de negocio son cada vez más exigentes en cuanto a tiempos de procesamiento y la disponibilidad de los datos más recientes y este artículo pretende abordar esta cuestión.

Utilizando la nube de AWS y con un enfoque serverless se desplegará en este artículo una aplicación capaz de ingestar streams de datos y procesarlos en NRT, escribiendo su resultado en un LakeHouse de tal manera que se puedan realizar operaciones ACID (Atomicidad, Consistencia, Aislamiento y Durabilidad) sobre estos. Se desplegará una arquitectura en la que se ingestan datos con Locust, se procesan con Flink y finalmente se escriben en Hudi y JSON.

Locust es un framework de Python que sirve para poder realizar Load Testing de una manera fácil y escalable. Las ventajas que ofrece Locust son la capacidad de poder definir este comportamiento de los usuarios con un lenguaje de propósito general y su facilidad de escalado.

Flink se ha convertido en un framework de referencia en el ámbito de procesamiento distribuido sobre streams de datos. Se caracteriza por su orientación al procesamiento de streams (aunque también puede ejecutar procesos batch), su rapidez de procesamiento y su eficiencia en el uso de memoria. Hay otros frameworks populares en el sector, como Spark Streaming y Storm, en el apartado de arquitectura se discutirá por qué en última instancia Flink ha sido el elegido.

Finalmente, Hudi es un formato de fichero transaccional que proporciona las habilidades propias de una base de datos y DataWarehouse al Data Lake. Hudi da la capacidad de dejar atrás los conceptos de batching y sustituirlo con una perspectiva de procesamiento incremental. Como el resto de las tecnologías usadas en este artículo, se describe en detalle más adelante.

Todo el código utilizado en este artículo, tanto IaC como de Python, puede visitarse en nuestro repositorio[1] en Github.

En próximos artículos

Múltiples artículos utilizarán este como base para hablar de los siguientes temas:

  • Comparativa en cuanto a eficiencia de procesamiento, escritura y lectura de ficheros y costes en JSON vs Hudi.
  • Comparativa de MOR vs COW, además del consumo de estas tablas por los distintos tipos de queries (Snapshot, Read Optimized, Incremental).
  • Escalabilidad.
  • Otras formas de explotación del dato, como pueden ser Redshift o Pinot.

Arquitectura

A continuación se puede ver la arquitectura a alto nivel que se desplegará:

Como se puede ver, se utiliza Locust como herramienta de Load Testing para enviar datos sintéticos a nuestra aplicación. Estos serán ingestados a través de un Kinesis Stream aprovisionado en modo On Demand, de esta manera el stream escalará de manera automática. La alternativa al modo On Demand es el modo Provisioned, donde debemos especificar el número de shards (componente en los que se divide el stream), con el que queremos aprovisionar el stream. Las diferencias y particularidades de estos dos modos se explicarán más en detalle en el apartado de Kinesis.

Del stream de entrada leen las dos aplicaciones de Kinesis Analytics Flink. Como se mencionó en el apartado de próximos pasos, la razón de tener dos aplicaciones independientes escribiendo en Hudi y JSON respectivamente es para realizar una comparativa en próximos artículos en cuanto a eficiencia. Finalmente los datos se alojarán en S3, el servicio de almacenamiento de objetos de AWS.

La particularidad que tiene la aplicación de Kinesis Analytics Flink es que es serverless, es decir, abstrae al desarrollador de la complejidad de configurar y desplegar un cluster con Flink. A esta aplicación se deben asignar unos KPUs o Kinesis Processing Units y un jar con la librería de Flink y los conectores necesarios para poder desplegarla correctamente. Todos estos conceptos serán explicados en los siguientes apartados.

La alternativa a esta perspectiva serverless con un servicio administrado en AWS es la administración completa de la aplicación por parte del desarrollador, pudiendo utilizar herramientas como Kubernetes o EKS (Kubernetes administrado en AWS) para poder desplegar en un cluster esta aplicación Flink. Las ventajas de esta segunda alternativa sería el poder configurar tanto el cluster (número de nodos, memoria, CPU, disco duro, etc…) como la aplicación Flink (gestión de disaster recovery, gestión de metadatos, etc…) con un grado de detalle mucho mayor. En este artículo se decidió la primera alternativa por su simplicidad y facilidad de uso a la hora de conocer el framework de Flink.

Locust

La primera pieza en la pipeline de ingesta de datos es el componente de Locust escrito en Python. A diferencia de otros frameworks disponibles en el mercado como JMeter, Locust nos da la capacidad de poder escribir un código simple con Python en vez de utilizar un lenguaje específico a un dominio o una interfaz de usuario.

Además, Locust está basado en eventos y utiliza greenlet[2], lo que le da la capacidad de con un solo hilo del procesador poder administrar la capacidad de varios miles de usuarios. Por ejemplo, en el caso de JMeter, se necesita un hilo para cada usuario, lo que supone un problema de escalabilidad para casos en los que se necesite un número alto de estos.

Locust tiene varias posibilidades a la hora de ejecutarse y escalar, pudiendo funcionar en local para aplicaciones con menos exigencias en cuanto a volumen de datos o desplegar en un cluster de Kubernetes al crear una imagen de Docker a raíz del código de Locust.

En cuanto a clientes y sistemas a los que enviar datos, Locust proporciona un cliente HTTP integrado. En el caso de querer enviar eventos a otros sistemas, como el de este artículo, siempre se puede escribir un cliente personalizado gracias a la ventaja de ser un framework de Python.

Además, Locust también proporciona una interfaz web para poder comprobar el progreso de tu envío de datos en tiempo real. Por todas estas razones se ha decidido utilizar esta tecnología en este artículo.

Kinesis Data Analytics

Para la ingesta de datos, se utilizará Kinesis Data Streams, un servicio de streaming de datos completamente administrado y serverless ofrecido por AWS. Un Kinesis Stream está formado por una agrupación lógica de shards, que representan la unidad fundamental de capacidad de un stream y son procesados en paralelo. Cada shard dota al stream de 1 MB/s o 1,000 eventos por segundo de escritura y 2 MB/s de lectura. Los eventos serán distribuidos entre los shards de un stream en función de su clave de partición, por lo que es importante que el particionado sea homogéneo para evitar un sesgo en la distribución y ocurrencia de hot shards. Existen dos modos de aprovisionamiento de capacidad:

  • On Demand – el número de shards se gestiona automáticamente para acomodar la carga, asegurando un rendimiento óptimo sin necesidad de ajustes manuales.
  • Provisioned – debes especificar el número de shards para el stream en función de la carga esperada.

Por simplicidad, y por ser idóneo para nuestro caso de uso, se optará por el modo On Demand. Esto acomodará automáticamente el número de shards a la cantidad de datos generados por nuestra aplicación de Locust.

Para leer y procesar los datos ingestados a través de Kinesis Data Streams, se usará otro servicio de la familia Kinesis, Kinesis Data Analytics (KDA). Este servicio es ofrecido en dos sabores

  • Kinesis Analytics SQL – Permite la creación de aplicaciones de procesamiento de datos en streaming mediante el uso de SQL. Este servicio se considera deprecado en favor del servicio de KDA for Apache Flink.
  • Kinesis Analytics for Apache Flink – Proporciona una forma de desplegar un cluster de Flink gestionado por AWS. El uso de Flink faculta la creación de aplicaciones más avanzadas y con mayor rendimiento.

Una aplicación de Flink consta de una serie de tareas de procesado en paralelo, también conocidas como operadores, que se conectan en una Directed Acyclic Graph (DAG). El stream de datos es procesado por esta DAG, con cada operador ejecutando una operación específica sobre el dato.

KDA asigna potencia de computación para nuestra aplicación en forma de Kinesis Processing (KPUs), cada una de ellas equivalente a 1 vCPU y 4GB de RAM. Se determina el número de KPUs para la aplicación mediante la especificación de dos parámetros:

  • Parallelism – Número de tareas que se pueden ejecutar concurrentemente.
  • ParallelismPerKPU – Número de tareas que pueden ejecutarse en una única KPU.

El número total de KPUs de la aplicación viene dado por Parallelism / ParallelismPerKPU. Es posible desplegar este servicio con autoescalado automático, que ajustará automáticamente el número de KPUs en función del consumo de CPU para acomodar la demanda.

Figure 1. KDA configuration with Parallelism 4 and ParallelismPerKPU 2

Los costos[3] de Amazon Kinesis Analytics se basan en un modelo pay-per-use, apoyándose en las Kinesis Processing Units consumidas. Además, se asume un coste por el almacenamiento usado por la aplicación y sus copias de seguridad.

Flink

Profundizando más en la aplicación de Flink, una de las características más importantes es la capacidad de ser resiliente a fallos. Para ello, Flink incorpora un sistema de checkpointing mediante el cual se toma un snapshot de la aplicación y su estado que es guardado en un almacenamiento remoto en caso de que sea necesario recuperar la aplicación.

El proceso de checkpointing de una aplicación de Flink está diseñado para ser resiliente y eficiente. Flink puede hacer uso de diferentes backends para guardar el estado de la aplicación. El más simple sería la memoría de la propia Java Virtual Machine, y aunque esto ofrece baja latencia y una gestión más simple, rápidamente pueden surgir problemas de escalado y capacidad que no lo hacen recomendable para entornos de producción. Por eso es común el uso de RocksDB como backend de Flink, una base de datos de clave-valor con alto rendimiento, escalable y con tolerancia a fallos. Adicionalmente KDA guarda estos snapshots en S3 para una capa extra de durabilidad.

Para el propósito de este blog, se ha desarrollado una sencilla aplicación de  ingesta de datos en tiempo real y su posterior guardado en S3. Flink ofrece dos APIs mediante las cuales puedes desarrollar una aplicación:

  • DataStream API – Es una API basada en el concepto de streams. Ofrece control a bajo nivel de la aplicación con la desventaja de requerir un mayor esfuerzo por parte del desarrollador.
  • Table API – Esta API se basa en el concepto de tablas. Ofrece una manera declarativa de desarrollar la aplicación mediante el uso de expresiones SQL. Conlleva una pérdida de control sobre los detalles de la aplicación en favor de ser mucho más sencilla.

Para este caso de uso se usará la Table API por su simplicidad, pero es igualmente compatible con el uso de la DataStream API.

A la hora de desplegar la aplicación con Kinesis Data Analytics sólo es necesario definir el punto de entrada del código de la aplicación y proporcionar un uber jar con todas las dependencias de esta. Conviene explicar las dependencias usadas para esta aplicación, pues suele ser uno de los mayores puntos de fricción a la hora desarrollar una aplicación de Flink:

  • SQL connector for Kinesis – Conector fundamental para que nuestra aplicación de Flink sea capaz de leer de un Kinesis Stream.
  • S3 Filesystem for Hadoop – Permite a la aplicación operar sobre S3.
  • Hudi Bundle – Paquete proporcionado por los desarrolladores de Hudi, con todas las dependencias necesarias para trabajar con la tecnología.
  • Hadoop MapReduce Client Core – Dependencia adicional necesaria para que la escritura a Hudi funcione correctamente en KDA. Es posible que en futuras versiones del Hudi Bundle esta dependencia no sea necesaria.

 La aplicación está preparada para escribir datos tanto en formato JSON como en tablas de Hudi MoR o CoW (que se explicarán en detalle en la siguiente sección). Tanto el código de la aplicación como la infraestructura están disponibles en el repositorio.

Hudi

Conceptos

Hudi se presenta como una fuente de almacenamiento Open Source a nivel de formato de datos. Al igual que hacen otras soluciones como Iceberg o Delta Lake, ofrece algunas propiedades ya existentes en estas como es el soporte de transacciones ACID (Atomicidad, Consistencia, Aislamiento y Durabilidad), procesos enfocados a la optimización de tareas de lectura/escritura, actualización de datos incrementales y otras que se explicarán a continuación. Es importante resaltar que estas no podrían conseguirse mediante ficheros de formato Avro y Parquet.

Las características que presenta Hudi son las siguientes:

  • Transacciones ACID: unas de las principales ventajas que ofrece Apache Hudi es el soporte para transacciones ACID, posibilitando que las operaciones de escritura sean atómicas y consistentes. Además también proporciona que los datos estén aislados y sean duraderos, lo que garantiza la integridad de los datos y la consistencia del sistema. Más adelante se analizará más en detalle cómo las distintas formas de almacenamiento lo hacen posible y las ventajas que estas ofrecen.
  • Pipelines Incrementales: la clusterización de los eventos en función de variables de negocio permite que tareas de borrado/actualización de datos se puedan realizar de una forma más eficiente si estas se encuentran indexadas de forma conjunta aunque no se hayan dado en la misma franja temporal.
  • Ingesta en Streaming: Hudi permite obtener unos workloads computacionalmente menos pesados a través de Upserts que recurren a una indentación optimizada[4] por grupos de archivos, lo que hace que en tareas de escritura (Update/Append/Delete) sean más eficientes. Esto permite que muchas de las aplicaciones basadas en Hudi no deban ser deduplicadas.
  • Queries de estados previos de los datos – Time Travel: Hudi permite actualizar y consultar información de particiones pasadas sin la necesidad de tener que reprocesar ni incluir particiones temporales mayores. De esta manera se asegura que eventos enviados con posterioridad no sean procesados y sean correctamente almacenados.
  • Tareas de escritura simultáneas: mediante OCC (Optimistic Concurrency Control[5]) se permite que muchas de las tareas como Upsert e Insert puedan realizarse correctamente aun realizándose de forma simultánea.

A la hora de analizar cómo Hudi procede a realizar el almacenamiento de los eventos ingestados, estos son agrupados por particiones y estas a su vez agrupadas en grupos de archivos. Estos últimos teniendo asignado un file_id único para cada grupo en el cual se encuentra el base file, en formato parquet, el cual surge tras una acción, ya sea un commit o  compactación, y el log file que es donde se encuentran registrados todas las actualizaciones realizadas (event version tracking).

Tipos de Tablas y Queries

Hudi ofrece 2 tipos de tablas en función de la necesidad de negocio, esto tiene un impacto a nivel de performance y limitación de ciertas funcionalidades como se verán en más detalle:

Copy on Write (COW)

Sistema de almacenamiento mediante el cual en las tareas de actualización, eliminación o registro de nuevos datos se realizan directamente sobre el archivo de logs (delta file) y se crea una nueva instantánea que incluye una copia completa del conjunto de datos actualizado, incluyendo una nueva versión del base file y un archivo delta que contiene los cambios realizados en esa operación.

No es hasta la compactación de datos (programada o al alcanzar un tamaño de datos definido) cuando se realiza la combinación de los archivos delta con la versión más reciente del conjunto de datos completo.Se crea así un nuevo archivo completo donde se eliminan los archivos delta que ya no son necesarios, actualizando a su vez el archivo de índice para que pueda acceder a los datos del archivo compactado.

Este sistema de almacenamiento está especialmente recomendado para casos de uso en los que las tareas de lectura sean más frecuentes que las de escritura al no requerir de  transformaciones de datos adicionales al leer los datos. A continuación se muestra el Timeline de los principales archivos al realizarse las distintas tareas de escritura:

Acción NUEVO archivo base Archivo delta Archivo de índice Snapshot
Nuevo registro
Se escribe el registro en el archivo base
No se crea un archivo delta
Se actualiza el archivo de índice con el nuevo registro
No se crea un nuevo snapshot
Actualización de registro existente
Se escribe el registro actualizando en un nuevo archivo base
Se escribe el registro actualizando en el archivo delta
Se actualiza el archivo de índice con la versión actualizada del registro
No se crea un nuevo snapshot
Eliminación de registro
No se escribe el registro eliminado en el nuevo archivo
Se escribe una marca de eliminación en un nuevo archivo delta
Se actualiza el archivo de índice con la marca de eliminación
No se crea un nuevo snapshot
Compactación de archivos delta
Se fusionan los archivos delta en un nuevo archivo base
No se crea un nuevo archivo delta
Se crea un nuevo archivo índice que contiene todas las entradas del índice de los archivos fusionados
Se crea un nuevo snapshot que refleja el estado actual de los datos después de la compactación

Merge On-Read (MOR)

En este caso, no se utilizan delta files separados como en el modelo Copy-on-Write (COW). En su lugar, los cambios se escriben directamente en los archivos de datos existentes (base files). En las tareas en las que se realizan actualizaciones de registros, estos nuevos son añadidos en el base file, y en el caso de eliminación, estos son marcados como tal en el base file, en ambos casos estos cambios son registrados en el archivo de índice, hasta que se realiza la compactación. Es en esta operación donde se aplican todas las actualizaciones a los registros en el archivo base correspondiente y elimina las versiones anteriores de los registros actualizados. 

Esta alternativa está especializada en realizar consultas de datos históricos versionados y transformaciones y análisis NRT de grandes volúmenes, ya que es posible realizarlo sin tener que copiar los datos a otra ubicación en el disco. Además de ser óptimo para casos de uso en los que las tareas de escritura son concurrentes al ser más eficiente ya que no es necesario realizar transformaciones de datos adicionales durante la escritura, aunque posee una menor tolerancia al fallo ya que en caso de que el archivo de logs se corrompa puede generar pérdida de las versiones de los datos.

A continuación se muestra el Timeline de los principales archivos al realizarse las distintas tareas de escritura:

Acción Archivo base Archivo delta Archivo de índice Snapshot
Nuevo registro
Se escribe el registro en el archivo base
No se crea un archivo delta
Se actualiza el archivo de índice con el nuevo registro
No se crea un nuevo snapshot
Actualización de registro existente
Se escribe el registro actualizando en un nuevo archivo delta
Se escribe el registro actualizando en el archivo delta correspondiente
Se actualiza el archivo de índice con la versión actualizada del registro
No se crea un nuevo snapshot
Eliminación de registro
No se elimina el registro del archivo base
Se escribe una marca de eliminación en un nuevo archivo delta
Se actualiza el archivo de índice con la marca de eliminación
No se crea un nuevo snapshot
Compactación de archivos delta
Se fusionan los archivos delta en un nuevo archivo base
Se crea un nuevo archivo delta que contiene las actualizaciones pendientes después de la última compactación
Se crea un nuevo archivo índice que contiene todas las entradas del índice de los archivos fusionados
Se crea un nuevo snapshot que refleja el estado actual de los datos después de la compactación

Como resumen, se realiza una comparativa de las principales métricas de performance entre Copy on-Write y Merge on-Read:

COW MOR
Coste de escritura
Mayor
Menor
Latencia
Mayor
Menor
Rendimiento de consulta
Mayor
Menor antes de compactación
Igual tras compactación
  • Escritura: COW tiene un mayor costo de escritura que MOR debido a que cada vez que se realiza una operación de escritura (ya sea añadir un nuevo registro o actualizar uno existente), se crea un nuevo delta file y se deben actualizar los archivos de índice correspondientes. En cambio, en MOR, los registros se escriben directamente en el base file, lo que implica una menor cantidad de operaciones de escritura y, por lo tanto, un menor costo en términos de rendimiento y uso de recursos.
  • Latencia: COW tiene un menor data latency que MOR debido a que los registros nuevos o actualizados se escriben primero en un delta file separado, en lugar de actualizar directamente el base file como en MOR.
  • Tiempos de consulta: COW tiene un menor tiempo de consulta que MOR debido a que en COW, los datos actualizados se almacenan en los Delta Files y los datos originales se mantienen en el Base File. Esto significa que no es necesario realizar ninguna operación de lectura para obtener la versión actualizada de los datos.

Hudi no solo ofrece distintas formas de almacenamiento, sino también, distintas formas de realizar consultas sobre la información almacenada, dependiendo de nuevo tanto de los casos de negocio como del tipo de almacenamiento escogido:

  • Snapshots: consulta la última versión procedente de un commit o compactación. Gracias a este tipo de consultas, se pueden obtener las versiones de los datos en momentos específicos gracias a la combinación del base y delta file (time travel). Misma performance en CoW y MoR.
  • Read Optimized: únicamente disponible si el tipo de tabla en el que se almacenan los datos es MoR. Basado en la obtención de vistas optimizadas para lectura de un conjunto de datos grande y distribuido. Esto se consigue mediante indexación optimizada (Bloom Filter Index), lo que permite reducir considerablemente el tiempo de búsqueda de datos. Además se apoya también en la compactación de datos que hace que, de nuevo, las tareas de búsqueda sean menos costosas al disminuir el volumen de los mismos.
  • Incremental: Permite leer solo los datos actualizados o agregados desde la última consulta. Esto ayuda a reducir el tiempo de lectura y el uso del almacenamiento en disco.

Conclusiones

En este artículo se ha descrito como desplegar una aplicación que ingesta eventos en tiempo real y forma con la salida un LakeHouse con una arquitectura serverless. Con esto se ha buscado un nivel de abstracción intermedio de tal manera que sea una aplicación simple pero con la suficiente potencia para poder llegar a utilizarse en entornos productivos reales.

Desplegar aplicaciones basadas en la combinación de tecnologías como son Apache Flink y Hudi otorga la capacidad de procesar grandes volúmenes de datos en tiempo real y de manera escalable. Esto combinado con la garantía que aportan las transacciones ACID, hace que la combinación de Apache Flink y Apache Hudi sea una solución sólida para la ingesta y procesamiento de datos en entornos críticos.

A pesar de todas las ventajas que se han descrito cabe resaltar algunos inconvenientes que se han podido detectar desarrollando esta arquitectura. El mayor problema que se ha encontrado ha sido la resolución de dependencias entre las librerías de Flink y los conectores necesarios, como por ejemplo el de Hudi. La falta de comunidad que existe a día de hoy, aunque esta crecerá con el paso del tiempo, supuso un problema inicial considerable para poder formar el paquete final con todas las dependencias necesarias sin que hubiese conflictos entre sí. Además, cabe resaltar que se ha percibido menos comunidad para el lenguaje de Python que para el de Java o Scala. En este artículo se eligió Python ya que existía un conocimiento interno más fuerte pero en el caso de que el stack tecnológico se acerque más a lenguajes soportados por la JVM (Java Virtual Machine) sería aconsejable el uso de Scala o Java.

En los próximos artículos entraremos más en detalle en las particularidades que tienen tanto Hudi como Flink para poder personalizar y ajustar el comportamiento de esta aplicación dependiendo de las necesidades que presente nuestro caso de uso.

Referencias

[1] Repositorio Github Flink-Hudi (Terraform). [link]

[2] Greenlet 2.0.2. Documentation [link] (February 28, 2023)

[3] Amazon Kinesis Data Analytics Costs. [link] (March 23, 2022)

[4] Hudi Optimized Indexing. [link] (September 23, 2021)

[5] Hudi Writing Concurrency. [link] (September 23, 2021)

Autores

Alberto Jaen

AWS Cloud Engineer

Empecé mi carrera laboral con el desarrollo, mantenimiento y administración de bases de datos multidimensionales y Data Lakes. A partir de ahí comencé a estar interesado en plataformas de datos y arquitecturas cloud, estando certificado 3 veces en AWS y 2 con Hashicorp.

Actualmente me encuentro trabajando como un Cloud Engineer desarrollando Data Lakes y DataWarehouses con AWS para un cliente relacionado con la organización de eventos deportivos a nivel mundial.

Alfonso Jerez

AWS Cloud Engineer

Comencé mi carrera como Data Scientist en distintos sectores (banca, consultoría,…) enfocado en la automatización de procesos y desarrollo de modelos. En los últimos años aposté por Bluetab motivado por el interés en especializarme como Data Engineer y comenzar a trabajar con los principales proveedores Cloud (AWS, GPC y Azure) en clientes como Olympics, específicamente en la optimización del procesamiento y almacenamiento del dato.

Colaborando activamente con el grupo de Práctica Cloud en investigaciones y desarrollo de blogs de tecnologías punteras e innovadoras tales como esta, fomentando así el continuo aprendizaje.

Adrián Jiménez

AWS Cloud Engineer

Dedicado al aprendizaje constante de nuevas tecnologías y su aplicación, disfrutando de utilizarlas en la resolución de desafíos tecnológicos. Desarrollo mi carrera como Cloud Engineer diseñando, implementando y manteniendo infraestructura en AWS.

Colaboro activamente en la Práctica Cloud, donde investigamos y experimentamos con nuevas tecnologías, buscando soluciones para los retos que enfrentan nuestros clientes.

Navegación

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Tenemos Plan B

septiembre 17, 2020
LEER MÁS

Algunas de las capacidades de Matillion ETL en Google Cloud

julio 11, 2022
LEER MÁS

Databricks on Azure – An architecture perspective (part 2)

marzo 24, 2022
LEER MÁS

Bluetab en la ElixirConfEU 2023

mayo 3, 2023
LEER MÁS

Oscar Hernández, nuevo CEO de Bluetab LATAM

mayo 16, 2024
LEER MÁS

Características esenciales que debemos tener en cuenta al adoptar un paradigma en la nube

septiembre 12, 2022
LEER MÁS

Publicado en: Blog, Practices, Tech

LakeHouse Streaming on AWS with Apache Flink and Hudi (Part 1)

abril 11, 2023 by Bluetab

LakeHouse Streaming on AWS with Apache Flink and Hudi (Part 1)

Alberto Jaen

AWS Cloud Engineer

Alfonso Jerez

AWS Cloud Engineer

Adrián Jiménez

AWS Cloud Engineer

Introduction

Every day the ingestion and processing of Near Real Time (NRT) data streams becomes more necessary. Business requirements are becoming more demanding in terms of processing times and availability of the latest data and this article aims to address this issue.

Using the AWS cloud and a serverless approach, this article will deploy an application capable of ingesting data streams and processing them in NRT, writing their result in a

LakeHouse in such a way that ACID (Atomic, Consistent, Isolated and Durable) operations can be performed on them. An architecture will be deployed in which data is ingested with Locust, processed with Flink and finally written in Hudi and JSON formats.

Locust is a Python framework to perform Load Testing in an easy and scalable way. The advantages offered by Locust are the ability to define this user behavior with a general purpose language and its ease of scalability.

Flink has become a reference framework in the field of distributed processing on data streams. It is characterized by its stream processing orientation (although it can also execute batch processes), its processing speed and its memory efficiency. There are other popular frameworks in the industry, such as Spark Streaming and Storm, the architecture section will discuss why Flink was ultimately chosen.

Finally, Hudi is a transactional file format that provides the capabilities of a database and DataWarehouse to the Data Lake. Hudi gives the ability to leave behind the concepts of batching and replace it with an incremental processing perspective. Like the other technologies used in this article, it is described in detail below.

All the code used in this article, both IaC and Python, can be found in our repository[1] on Github.

In future articles

Multiple articles will use this one as a basis for discussing the following topics:

  • Comparison in terms of processing efficiency, writing and reading files and costs in JSON vs Hudi.
  • Comparison of MOR vs COW, in addition to the consumption of these tables by the different types of queries (Snapshot, Read Optimized, Incremental).
  • Scalability.
  • Other forms of data mining, such as Redshift or Pinot.

Architecture

Below you can see the high-level architecture that will be deployed:

As you can see, Locust is used as a Load Testing tool to send synthetic data to our application. These will be ingested through a Kinesis Stream provisioned in On Demand mode, so the stream will scale automatically. The alternative to the On Demand mode is the Provisioned mode, where we must specify the number of shards (component in which the stream is divided), with which we want to provision the stream. The differences and particularities of these two modes will be explained in more detail in the Kinesis section.

The input stream is read by two Kinesis Analytics Flink applications. As mentioned in the next steps section, the reason to have two independent applications writing in Hudi and JSON respectively is to make a comparison in future articles in terms of efficiency. Finally the data will be hosted in S3, the AWS object storage service.

The particularity of the Kinesis Analytics Flink application is that it is serverless, that is, it abstracts the developer from the complexity of configuring and deploying a Flink cluster. This application must be assigned KPUs or Kinesis Processing Units and a jar with the Flink library and the necessary connectors to be able to deploy it correctly. All these concepts will be explained in the following sections.

The alternative to this serverless perspective with a managed service on AWS is the complete administration of the application by the developer, who can use tools such as Kubernetes or EKS (Kubernetes managed on AWS) to deploy this Flink application in a cluster. The advantages of this second alternative would be to be able to configure both the cluster (number of nodes, memory, CPU, hard disk, etc…) and the Flink application (disaster recovery management, metadata management, etc…) with a much greater degree of detail. In this article, the first alternative was chosen because of its simplicity and ease of use when learning about the Flink framework.

Locust

The first piece in the data ingestion pipeline is the Locust component written in Python. Unlike other frameworks available on the market such as JMeter, Locust gives us the ability to write simple code with Python instead of using a domain-specific language or user interface.

In addition, Locust is event-driven and uses greenlet[2], which gives it the ability to manage the capacity of several thousand users with a single processor thread. For example, in the case of JMeter, one thread is needed for each user, which poses a scalability problem for cases where a high number of users are needed.

Locust has several possibilities when it comes to running and scaling, being able to run locally for less data-intensive applications or deploy to a Kubernetes cluster by creating a Docker image from Locust code.

As for clients and systems to send data to, Locust provides a built-in HTTP client. In case you want to send events to other systems, like the one in this article, you can always write a custom client thanks to the advantage of being a Python framework.

In addition, Locust also provides a web interface so that you can check the progress of your data submission in real time. For all these reasons it has been decided to use this technology in this article.

Kinesis Data Analytics

For data ingestion, Kinesis Data Streams, a fully managed and serverless data streaming service offered by AWS, will be used. A Kinesis Stream consists of a logical grouping of shards, which represent the fundamental unit of capacity of a stream and are processed in parallel. Each shard provides the stream with 1 MB/s or 1,000 events per second write and 2 MB/s read. The events will be distributed among the stream shards according to their partitioning key, so it is important that the partitioning is homogeneous to avoid a bias in the distribution and occurrence of hot shards. There are two modes of capacity provisioning:

  • On Demand – the number of shards is automatically managed to accommodate the load, ensuring optimal performance without the need for manual adjustments.
  • Provisioned – you must specify the number of shards for the stream based on the expected load.

For simplicity, and because it is suitable for our use case, we will opt for the On Demand mode. This will automatically accommodate the number of shards to the amount of data generated by our Locust application.

To read and process the data ingested through Kinesis Data Streams, another service of the Kinesis family, Kinesis Data Analytics (KDA), will be used. This service is offered in two flavors:

  • Kinesis Analytics SQL – Enables the creation of streaming data processing applications using SQL. This service is considered deprecated in favor of the KDA for Apache Flink service.
  • Kinesis Analytics for Apache Flink – Provides a way to deploy a Flink cluster managed by AWS. Using Flink empowers the creation of more advanced and better performing applications.

A Flink application consists of a series of parallel processing tasks, also known as operators, which are connected in a Directed Acyclic Graph (DAG). The data stream is processed by this DAG, with each operator performing a specific operation on the data.

KDA allocates computing power for our application in the form of Kinesis Processing (KPUs), each equivalent to 1 vCPU and 4GB of RAM. The number of KPUs for the application is determined by specifying two parameters:

  • Parallelism – Number of tasks that can be executed concurrently.
  • ParallelismPerKPU – Number of tasks that can run on a single KPU.

The total number of KPUs of the application is given by Parallelism / ParallelismPerKPU. It is possible to deploy this service with automatic autoscaling, which will automatically adjust the number of KPUs based on CPU consumption to accommodate demand.

Figure 1. KDA configuration with Parallelism 4 and ParallelismPerKPU 2

The costs[3] of Amazon Kinesis Analytics are based on a pay-per-use model, based on the Kinesis Processing Units consumed. In addition, a cost is assumed for the storage used by the application and its backups.

Flink

Delving deeper into the Flink application, one of the most important features is the ability to be resilient to failures. To this end, Flink incorporates a checkpointing system whereby a snapshot of the application and its state is taken and stored in remote storage in case the application needs to be recovered.

The checkpointing process of a Flink application is designed to be resilient and efficient. Flink can make use of different backends to store the state of the application. The simplest would be the Java Virtual Machine’s own memory, and while this offers low latency and simpler management, scaling and capacity issues can quickly arise that make it undesirable for production environments. This is why it is common to use RocksDB as a backend for Flink, a high-performance, scalable and fault-tolerant key-value database. Additionally KDA stores these snapshots in S3 for an extra layer of durability.

For the purpose of this blog, a simple application has been developed for real-time data ingestion and subsequent saving to S3. Flink offers two APIs through which you can develop an application:

  • DataStream API – It is an API based on the concept of streams. It offers low-level control of the application with the disadvantage of requiring more effort from the developer.
  • Table API – This API is based on the concept of tables. It provides a declarative way to develop the application by using SQL expressions. It leads to a loss of control over the details of the application in favor of being much simpler.

For this use case the Table API will be used for its simplicity, but it is equally compatible with the use of the DataStream API.

Deploying the application with Kinesis Data Analytics requires only to define the entry point of the application code and provide an uber jar with all the application dependencies. It is fitting to explain the dependencies used for this application, as it is usually one of the major pain points when developing a Flink application:

  • SQL connector for Kinesis – Fundamental connector for our Flink application to be able to read from a Kinesis Stream.
  • S3 Filesystem for Hadoop – Allows the application to operate on top of S3.
  • Hudi Bundle – Package provided by Hudi developers, with all the necessary dependencies to work with the technology.
  • Hadoop MapReduce Client Core – Additional dependency required for writing to Hudi to work correctly in KDA. It is possible that in future versions of the Hudi Bundle this dependency will not be needed.

The application is prepared to write data both in JSON format and in Hudi MoR or CoW tables (which will be explained in detail in the next section). Both the application code and the infrastructure are available in the repository.

Hudi

Concepts

Hudi is presented as a source of Open Source storage at the data format level. Like other solutions such as Iceberg or Delta Lake, it offers some of their existing properties such as ACID (Atomicity, Consistency, Isolation and Durability) transaction support, processes focused on optimizing read/write tasks, incremental data updates and others that will be explained below. It is important to highlight that these could not be achieved by means of Avro and Parquet format files.

Hudi’s features are as follows:

  • ACID transactions: One of the main advantages offered by Apache Hudi is the support for ACID transactions, enabling write operations to be atomic and consistent. It also provides data isolation and durability, ensuring data integrity and system consistency. How the various forms of storage make this possible and the advantages they offer will be discussed in more detail later.
  • Incremental Pipelines: the clustering of events based on business variables allows data deletion/update tasks to be performed more efficiently if they are indexed together even if they have not occurred in the same time frame.
  • Streaming Ingest: Hudi allows to obtain computationally lighter workloads through Upserts that resort to an optimized indentation[4] by file groups, which makes writing tasks (Update/Append/Delete) more efficient. This allows many Hudi-based applications not to be deduplicated.
  • Queries of previous data states – Time Travel: Hudi allows updating and consulting information from past partitions without the need to reprocess or include major temporary partitions. This ensures that events sent later are not processed and are correctly stored.
  • Concurrent write tasks: by means of OCC (Optimistic Concurrency Control[5]), many of the tasks such as Upsert and Insert can be performed correctly even if they are performed simultaneously.

When analyzing how Hudi proceeds to store the ingested events, these are grouped by partitions and these in turn are grouped into groups of files. The latter are assigned a unique file_id for each group in which the base file is found, in parquet format, which arises after an action, either a commit or compaction, and the log file which is where all the updates are registered (event version tracking).

Table Types and Queries

Hudi offers 2 types of tables depending on the business need, this has an impact in terms of performance and limitation of certain functionalities as we will see in more detail:

Copy on Write (COW)

A storage system whereby the tasks of updating, deleting or recording new data are performed directly on the log file (delta file) and a new snapshot is created that includes a complete copy of the updated dataset, including a new version of the base file and a delta file containing the changes made in that operation.

It is not until data compacting (scheduled or upon reaching a defined data size) that the delta files are combined with the most recent version of the complete dataset, creating a new complete file where the delta files that are no longer needed are removed and the index file is updated so that it can access the data in the compacted file.

This storage system is especially recommended for use cases where read tasks are more frequent than write tasks as it does not require additional data transformations when reading data.

The Timeline of the main files is shown below when the various writing tasks are performed:

task NEW Base File Delta File Index File Snapshot
New event
The record is written to the base file
No delta file is created
The index file is updated with the new record
No new snapshot is created
Updating existing registration
The updated record is written to a new delta file
the updated record is written to the corresponding delta file
The index file is updated with the updated version of the registry
No new snapshot is created
De-registration
Record is not deleted form the base file
A deletion flag is written to a new delta file
The index file is updated with the deletion flag
No new snapshot is created
Compacting delta file
The delta file are merged into a new base file
A new delta file is created containing the pending updates after the last compacting
A new index file is created containing all index entries of the merged files
A new snapshot is created reflecting the current state of the data after compaction

Merge On-Read (MOR)

In this case, separate delta files are not used as in the Copy-on-Write (COW) model. Instead, changes are written directly to the existing data files (base files). In tasks where record updates are performed, these new records are added to the base file, and in the case of deletions, these are marked as such in the base file, in both cases these changes are recorded in the index file, until compaction is performed. It is in this operation that all updates are applied to the records in the corresponding base file and deletes the previous versions of the updated records.

This alternative is specialized in performing queries of versioned historical data and NRT transformations and analysis of large volumes, since it is possible to do so without having to copy the data to another location on disk. In addition to being optimal for use cases where write tasks are concurrent as it is more efficient since it is not necessary to perform additional data transformations during the write, although it has a lower tolerance to failure since in case the log file is corrupted it can generate loss of data versions.

The Timeline of the main files is shown below when the various writing tasks are performed:

Task NEW Base File Delta File Index File Snapshot
New event
The record is written to the new base file
No delta file is created
The index file is updated with the new record
No new snapshot is created
Updating existing registration
The updatad record is written to the new base file
The updated record is written to a new delta file
The index file updated with the updated version of the registry
No new snapshot is created
De-registration
The deleted record is not written to the new base file
A deletion flag is written to a new delta file
The index file is updated with the deletion flag
No new snapshot is created
Compacting delta files
The delta file is merged into the new base file
No new delta file is created
A new index file is created containing all index entries of the merged files
A new snapshot is created reflecting the current state of the data after compaction

As a summary, a comparison of the main performance metrics between Copy on-Write and Merge on-Read is made:

COW MOR
Writing cost

Higher

Lower

Latency

Higher

Lower

Query Performance

Lower

Slower before compaction

Igual tras compactación

  • Write: COW has a higher write cost than MOR because each time a write operation is performed (either adding a new record or updating an existing one), a new delta file is created and the corresponding index files must be updated. In MOR, on the other hand, records are written directly to the base file, which means fewer write operations and therefore a lower cost in terms of performance and resource usage.
  • Latency: COW has a lower data latency than MOR because new or updated records are first written to a separate delta file, instead of directly updating the base file as in MOR.
  • Query times: COW has a shorter query time than MOR because in COW, the updated data is stored in the Delta Files and the original data is kept in the Base File. This means that no read operation is required to get the updated version of the data.

Hudi not only offers different forms of storage, but also different ways of querying the stored information, again depending on both the business cases and the type of storage chosen:

  • Snapshots: queries the latest version coming from a commit or compaction. Thanks to this type of queries, it is possible to obtain the versions of the data at specific times thanks to the combination of the base and delta file (time travel). Same performance in CoW and MoR.
  • Read Optimized: only available if the type of table in which the data is stored is MoR. Based on obtaining optimized views for reading a large and distributed data set. This is achieved by means of optimized indexing (Bloom Filter Index), which considerably reduces data search time. In addition, it also relies on data compaction, which again makes search tasks less costly by reducing the volume of data.
  • Incremental: Allows to read only the data updated or added since the last query. This helps to reduce reading time and disk storage usage.

Conclusions

In this article we have described how to deploy an application that ingests events in real time and forms a LakeHouse with a serverless architecture. With this we have sought an intermediate level of abstraction so that it is a simple application but with enough power to be able to be used in real production environments.

Deploying applications based on the combination of technologies such as Apache Flink and Hudi provides the ability to process large volumes of data in real time and in a scalable manner. This, combined with the guarantee provided by ACID transactions, makes the combination of Apache Flink and Apache Hudi a solid solution for data ingestion and processing in critical environments.

In spite of all the advantages described above, it is worth mentioning some drawbacks that have been detected in the development of this architecture. The biggest problem encountered has been the resolution of dependencies between Flink libraries and the necessary connectors, such as Hudi. The lack of community that exists today, although this will grow over time, was a considerable initial problem to be able to form the final package with all the necessary dependencies without conflicts between them. In addition, it is worth noting that less community has been perceived for the Python language than for Java or Scala. In this article Python was chosen as there was a stronger internal knowledge but in the case that the technology stack is closer to languages supported by the JVM (Java Virtual Machine) it would be advisable to use Scala or Java.

In the next articles we will go into more detail on the particularities that both Hudi and Flink have in order to customize and adjust the behavior of this application depending on the needs of our use case.

References

[1] Github Flink-Hudi (Terraform) repository. [link]

[2] Greenlet 2.0.2. Documentation [link] (February 28, 2023)

[3] Amazon Kinesis Data Analytics Costs. [link] (March 23, 2022)

[4] Hudi Optimized Indexing. [link] (September 23, 2021)

[5] Hudi Writing Concurrency. [link] (September 23, 2021)

Autores

Alberto Jaen

AWS Cloud Engineer

Empecé mi carrera laboral con el desarrollo, mantenimiento y administración de bases de datos multidimensionales y Data Lakes. A partir de ahí comencé a estar interesado en plataformas de datos y arquitecturas cloud, estando certificado 3 veces en AWS y 2 con Hashicorp.

Actualmente me encuentro trabajando como un Cloud Engineer desarrollando Data Lakes y DataWarehouses con AWS para un cliente relacionado con la organización de eventos deportivos a nivel mundial.

Alfonso Jerez

AWS Cloud Engineer

Comencé mi carrera como Data Scientist en distintos sectores (banca, consultoría,…) enfocado en la automatización de procesos y desarrollo de modelos. En los últimos años aposté por Bluetab motivado por el interés en especializarme como Data Engineer y comenzar a trabajar con los principales proveedores Cloud (AWS, GPC y Azure) en clientes como Olympics, específicamente en la optimización del procesamiento y almacenamiento del dato.

Colaborando activamente con el grupo de Práctica Cloud en investigaciones y desarrollo de blogs de tecnologías punteras e innovadoras tales como esta, fomentando así el continuo aprendizaje.

Adrián Jiménez

AWS Cloud Engineer

Dedicado al aprendizaje constante de nuevas tecnologías y su aplicación, disfrutando de utilizarlas en la resolución de desafíos tecnológicos. Desarrollo mi carrera como Cloud Engineer diseñando, implementando y manteniendo infraestructura en AWS.

Colaboro activamente en la Práctica Cloud, donde investigamos y experimentamos con nuevas tecnologías, buscando soluciones para los retos que enfrentan nuestros clientes.

Navegation

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Del negocio físico a la explosión del On-Line

abril 7, 2021
LEER MÁS

LA BANCA Y LA ERA DEL OPEN DATA

abril 19, 2023
LEER MÁS

Snowflake: Zero-Copy clone, o cómo librarte del duplicado de datos al clonar.

marzo 22, 2023
LEER MÁS

Data Mesh

julio 27, 2022
LEER MÁS

FinOps

mayo 20, 2024
LEER MÁS

Conceptos básicos de AWS Glue

julio 22, 2020
LEER MÁS

Publicado en: Blog, Practices, Tech

Snowflake: Zero-Copy clone, o cómo librarte del duplicado de datos al clonar.

marzo 22, 2023 by Bluetab

Snowflake: Zero-Copy clone, o cómo librarte del duplicado de datos al clonar.

Roberto García Parra

Technical Delivery Manager

Gabriel Gallardo Ruiz

Enterprise Architect

Introducción

Cómo continuación a la serie de artículos que estamos haciendo sobre las funcionalidades avanzadas que se derivan de la forma en la que se almacenan los datos en Snowflake, presentamos este nuevo artículo sobre el Zero-copy clone, que permite mediante diferentes operaciones a nivel metadato poder tener diferentes copias o versiones de la información, sin tener que duplicar datos en la mayoría de las ocasiones.

¿Qué es Zero-Copy Clone?

Uno de los casos de uso más frecuente que implica gran consumo de tiempo, recursos y almacenamiento, especialmente si hablamos de grandes dataset, es el copiado de datos. Para la realización de copias de objetos, snowflake ofrece zero-copy clone. Esta operación se realiza sobre la metadata, lo que permite realizar clonado de objetos rápidamente sin tener que duplicar los datos.

¿Cómo funciona?

Snowflake realmente lo que realiza es una copia de la metadata asociada al objeto que se va a clonar. Como podemos ver en el ejemplo de clonación de la tabla ‘Events’ en la siguiente imagen, simplemente duplica la metadata sin realizar ningún cambio en la parte de almacenamiento.

Una vez realizado el clon, los objetos clonados tienen su propio ciclo de vía, lo que permite que se puedan realizar cambios sobre los datos sin afectar al objeto original, de igual modo los cambios realizados sobre el objeto original tampoco serán reflejados sobre el objeto clonado.

Zero-copy clone permite la realización de clones prácticamente de cualquier objeto de Snowflake siendo especialmente útil en bases de datos, esquemas y tablas.

¿Qué coste tiene?

Al tratarse de una operación exclusiva de metadata, no se repercuten costes ni de procesamiento ni de almacenamiento, ni siquiera es necesario realizar la operación con un virtual data warehouse activo.

¿Cómo se puede clonar una tabla?

Privilegios: Para poder clonar una tabla, el ROLE que va a realizar la clonación tiene que tener privilegios de SELECT sobre la tabla que se va a clonar, además como es lógico, privilegios de CREATE TABLE sobre el esquema destino en el que se va a crear el clon de la tabla.

Sentencia: La sentencia utilizada para la clonación de tablas es similar a la de creación pero añadiendo la cláusula CLONE. A continuación, vamos a clonar la tabla “events»:

USE ROLE INGESTA_HUB_ROLE;
USE SCHEMA WEATHER.HISTORICAL;
CREATE TABLE EVENTS_CLONE CLONE EVENTS;

Podemos comprobar que la clonación de la tabla se realiza de inmediato, ya que como se comentó anteriormente únicamente se opera sobre la metadata.

Además, podemos observar en la siguiente tabla que todas las propiedades de la tabla origen se han clonado en la nueva tabla. Únicamente en el caso en que la tabla origen tenga asignado una cluster key, la nueva tabla se creará con automatic_clustering suspendido.

EVENTS EVENTS
cluster_by
LINEAR (COUNTRY,CITY)
LINEAR (COUNTRY,CITY)
rows
7,479,165
7,479,165
bytes
105,110,528
105,110,528
owner
INGESTA_HUB_ROLE
INGESTA_HUB_ROLE
retention_time
30
30
automatic_clustering
ON
OFF
change_tracking
OFF
OFF
search_optimization
OFF
OFF
is_external
N
N

Con respecto a los privilegios, por defecto no serán clonados. Esto lo podemos comprobar con las sentencias siguientes:

SHOW GRANTS ON TABLE WEATHER.HISTORICAL.EVENTS;

SHOW GRANTS ON TABLE WEATHER.HISTORICAL.EVENTS_CLONE;

Para que se clonen los privilegios asignados a la tabla origen, hay que añadir COPY GRANTS en la sentencia de clonado:

CREATE TABLE EVENTS_CLONE_1 CLONE EVENTS COPY GRANTS;

Ahora podemos comprobar que los privilegios han sido clonados:

SHOW GRANTS ON TABLE WEATHER.HISTORICAL.EVENTS_CLONE;

Clonación usando time travel

Snowflake permite realizar la clonación de una tabla para un momento histórico determinado, para ello tendremos que utilizar la cláusula AT o BEFORE en la sentencia de clonado.

Para la ejecución de la prueba, vamos a hacer cambios en la tabla de EVENTS y después realizaremos el clonado con un time travel anterior al cambio.

DELETE FROM EVENTS WHERE AIRPORTCODE=’KS47′;

Clonamos la tabla con un time travel anterior a la realización del borrado

CREATE TABLE EVENTS_CLONE_TIME_TRAVEL CLONE EVENTS at (offset => -60*5);

Si consultamos la información referente a ambas tablas, podemos comprobar que el clonado se ha realizado en el momento anterior en el que la tabla EVENTS tenía 9.062 filas más.

Consideraciones del clonado de tablas

  • Actualmente las tablas externas no pueden ser clonadas.
  • La tabla clonada tiene su propio ciclo de vida con lo que no tiene acceso a los datos históricos de la tabla origen utilizando time travel.
  • Una tabla clonada no incluye el historial de carga(LOAD_HISTORY) de la tabla de origen.
  • Si se clona una tabla con una secuencia asignada como valor por defecto a una columna, ésta seguirá referenciando a la secuencia original. En el caso de clonación de base de datos o esquemas que contengan tanto la secuencia como la tabla, la columna referenciará a la secuencia clonada (esto lo veremos con un ejemplo en la parte de clonado de Esquemas y Bases de dato)
  • Si clonamos una tabla que contiene a una foreign key, esta seguirá haciendo referencia a la tabla con al primary key. Como pasaba en el caso de las secuencias, si la clonación se realiza sobre un esquema o una base de datos y contiene ambas tablas, las referencias se realizan sobre las clonadas. En el caso de que la referencia de la foreign key sea sobre otra base de datos, seguirá realizándose sobre la tabla que contiene la primary key.

¿Cómo realizar la clonación de Esquemas y Base de datos?

Privilegios: Para poder clonar una base de datos o un esquema en Snowflake el role que va a realizar la operación tiene que tener permisos USAGE sobre los objetos que se van a clonar y los privilegios adecuados para la creación de los objetos en el destino.

La realización de clonado de un esquema o de una base de datos se realiza de manera recursiva, clonando todos los objetos hijos con la única excepción de las tablas externas , stages internos y snowpipes internos que no serán clonados.

A diferencia de la clonación de tablas, cuando se realiza la clonación de un esquema o una base de datos todos los permisos son heredados, por tanto, todos los objetos de la base de datos o del esquema clonado tendrán los mismos privilegios que tenían en el original.

Sentencia

USE ROLE ACCOUNTADMIN;
USE DATABASE WEATHER;
CREATE SCHEMA HISTORICAL_CLON CLONE HISTORICAL;

Al igual que sucedía con la clonación de tablas, la operación de clonado se realiza únicamente sobre la metadata, lo que permite que se realice en un tiempo reducido y sin necesidad de tener un virtual warehouse activo.

Para comprobar que la clonación se ha realizado de la forma esperada, podemos observar los objetos de cada una de los esquemas. Comprobamos tablas e internal stages.

SHOW TABLES IN HISTORICAL;

SHOW TABLES IN HISTORICAL_CLON;

Observamos que las tablas del esquema original y del clonado son iguales, además, se han heredado tanto owner como resto de propiedades. Como sucedía en el caso de la clonación de tablas, automatic_clustering está desactivado en las tablas del esquema clonado.

A continuación, vamos a comprobar que los internal stage del esquema original no se han clonado en el nuevo esquema

SHOW STAGES IN HISTORICAL;

SHOW STAGES IN HISTORICAL_CLON;

Clonación usando time travel

Como sucedía con el clonado de tablas, Snowflake también permite realizar el clonado de bases de datos y esquemas usando la opción de time travel.

En este caso vamos a realizar la clonación de la base de datos en un tiempo anterior a la clonación del esquema “HISTORICAL” que hemos realizado anteriormente.

CREATE DATABASE WEATHER_CLONE CLONE WEATHER at (offset => -60*60);

SHOW SCHEMAS IN WEATHER;

SHOW SCHEMAS IN WEATHER_CLONE;

Podemos comprobar en la base de datos clonada que no se encuentra el esquema que hemos clonado anteriormente.

Secuencias y foreign key:

 Como se comentó anteriormente en el clonado de tablas, si se clona un esquema que contiene una tabla con una columna con un valor por defecto de una secuencia o una foreign key y están en el mismo esquema o base de datos, la referencia de la secuencia apuntará a la misma referencia en el esquema o base de datos clonada.

Se ha añadido al esquema “HISTORICAL” una tabla “event_temperature” que contiene una secuencia y una foreign key a otra tabla. Se realiza la clonación:

CREATE SCHEMA HISTORICAL_CLON_2 CLONE HISTORICAL;

Si se observa la definición de la table, podemos comprobar cómo se ha cambiado la referencia tanto de la secuencia como de la foreign key.

Consideraciones del clonado de esquemas y bases de datos

  • Para el clonado de esquemas y bases de datos hay que tener en cuenta las mismas consideraciones observadas en la parte de las tablas.
  • Cuando se clona una base de datos o un esquema que contiene tareas, las tareas del clon se suspenden de forma predeterminada.
  • La clonación es rápida, pero no instantánea, especialmente para objetos grandes. Por tanto, si se ejecutan comandos de DDL en los objetos de origen mientras la operación de clonación está en curso, es posible que los cambios no sean reflejados en objeto clonado.

Conclusiones

Como vimos también en los artículos anteriores, Snowflake nos ofrece muchas características avanzadas, es muy importante comprender el funcionamiento de cada una de ellas para poder sacar el máximo partido siendo este el objetivo principal de esta serie de artículos. En este caso, comprender correctamente el clonado de datos nos va a ayudar a poder utilizar esta característica de manera correcta cuando sea necesario como puede ser en la creación de entornos de prueba o en la realización de snapshot.

Finalmente, hay que destacar que Snowflake nos ofrece un potente mecanismo de clonado de objetos, permitiéndonos la clonación de una forma sencilla, apenas incurriendo en costes y sin duplicación de datos. Estas características pueden ser muy importantes cuando vayamos a seleccionar un datawarehouse para nuestro entorno analitico.

Navegación

Introducción

¿Qué es Zero-Copy Clone?

¿Cómo funciona?

¿Qué coste tiene?

¿Cómo se puede clonar una tabla?

Clonación usando time travel

Consideraciones del clonado de tablas

¿Cómo realizar la clonación de Esquemas y Base de datos?

Clonación usando time travel

Consideraciones del clonado de esquemas y bases de datos

Conclusiones

Autores

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

Roberto García Parra

Technical Delivery Manager

Gabriel Gallardo Ruiz

Enterprise Architect

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Starburst: Construyendo un futuro basado en datos.

mayo 25, 2023
LEER MÁS

LakeHouse Streaming en AWS con Apache Flink y Hudi

abril 11, 2023
LEER MÁS

MDM como ventaja competitiva en las organizaciones

junio 18, 2024
LEER MÁS

Cambios de liderazgo en Bluetab EMEA

abril 3, 2024
LEER MÁS

Usando los Grandes Modelos de Lenguaje en información privada

marzo 11, 2024
LEER MÁS

Introducción a los productos de HashiCorp

agosto 25, 2020
LEER MÁS

Publicado en: Blog, interes, Practices, Tech

¿Qué está pasando en el mundo de la AI?

marzo 6, 2023 by Bluetab

¿Qué está pasando en el mundo de la AI?

Luis San Roman

Researcher and developer in machine learning

Uno de los eventos más importante que encontramos en el mundo IA es el WAICF (World Artificial Intelligence Cannes Festival).

Cannes es una ciudad ubicada en la Riviera francesa, que, aparte de ser una ciudad muy bonita, es conocida por el festival de cine que se celebra todos los años. Un lugar perfecto para poner la moqueta roja al mundo de AI.

La revolución de los modelos generativos autorregresivos

Sin duda uno de los temas más comentados fue ChtaGPT. La arquitectura de los Transformers, que es la base de modelos como ChatGPT, ha sido completamente revolucionaria, permitiendo entrenar modelos ultra-grandes con varios cientos de billones (americanos) de parámetros. Todos los grandes players de AI están trabajando sobre ellos.

Los modelos ultra-grandes han sido preentrenados con trillones (americanos) de palabras. Esto les permite hace cosas impresionantes, están revolucionando los casos de uso de NLP (Natural Language Processing) y abren la puerta a una ola de innovación. También tienen limitaciones… el camino hacia una inteligencia artificial que pueda aprender y planificar es largo.

Estos modelos son transformacionales. Su entrada puede ser cualquier tipo de secuencia: texto, imágenes o voz. Los casos de uso donde se están aplicando son de todo tipo. En el WAICF pudimos ver ejemplos que van desde el análisis de documentos, chats, sistemas que interactúan con voz, hasta robótica.

Cómo desarrollar AI a escala

Pensar a largo plazo, vincular el desarrollo de AI con objetivos de negocio, pensar en líneas de investigación transformacionales con AI, construir un equipo AI de primer nivel, gestionar el cambio cultural, pensar en todo el ciclo de AI, especialmente en la última milla y establecer alianzas con la comunidad AI son las características que más se escuchan para desarrollar AI a escala.

AI responsable

En el WAICF, cuando algún ponente expuso casos de uso de AI con un fin de ayudar a las personas, y en particular a colectivos minoritarios, la audiencia aplaudió esporádicamente.

AI responsable es una de las materias que más interés está generando en esta ola de innovación con AI. ¿Un modelo de AI optimizado para que tenga una precisión muy buena incorpora salvaguardas de sesgo y de equidad?

El desarrollo de AI responsable requiere un trade-off entre la precisión y el sesgo y la equidad del modelo, y tener muy presente los aspectos éticos a la hora de definir “el problema” que se quiere resolver con AI.

AI responsable es una materia muy compleja de implementar. Matemáticamente requiere analizar el comportamiento de los modelos en diferentes colectivos con umbrales que disparen señales de alarma.

Los mundos corporativo, académico y startups

La unión de los mundos corporativos, académico y startups es un valor seguro. Es una unión imprescindible para la evolución de AI.

En definitiva, el mundo de la AI está en ebullición y hoy en día es en eventos como el WAICF, donde se escenifica dando lugar a un espacio de aprendizaje con enfoques estratégicos, casos de uso y diferentes líneas de investigación que pueden confluir.

Luis San Roman

Researcher and developer in machine learning

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?
DESCUBRE BLUETAB

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Empoderando a las decisiones en diversos sectores con árboles de decisión en AWS

junio 4, 2024
LEER MÁS

Workshop Ingeniería del caos sobre Kubernetes con Litmus

julio 7, 2021
LEER MÁS

CDKTF: Otro paso en el viaje del DevOps, introducción y beneficios.

mayo 9, 2023
LEER MÁS

MODELOS DE ENTREGA DE SERVICIOS EN LA NUBE

junio 27, 2022
LEER MÁS

Cómo preparar la certificación AWS Data Analytics – Specialty

noviembre 17, 2021
LEER MÁS

Desplegando una plataforma CI/CD escalable con Jenkins y Kubernetes

septiembre 22, 2021
LEER MÁS

Publicado en: Tech

  • « Ir a la página anterior
  • Página 1
  • Páginas intermedias omitidas …
  • Página 9
  • Página 10
  • Página 11
  • Página 12
  • Página 13
  • Páginas intermedias omitidas …
  • Página 41
  • Ir a la página siguiente »

Footer

LegalPrivacidadPolítica de cookies
LegalPrivacy Cookies policy

Patrono

Patron

Sponsor

Patrocinador

© 2025 Bluetab Solutions Group, SL. All rights reserved.