{"id":15634,"date":"2023-10-04T14:12:51","date_gmt":"2023-10-04T14:12:51","guid":{"rendered":"https:\/\/beta.bluetab.net\/?p=15634"},"modified":"2023-10-04T14:12:51","modified_gmt":"2023-10-04T14:12:51","slug":"lakehouse-streaming-en-aws-con-apache-flink-y-hudi-parte-2","status":"publish","type":"post","link":"https:\/\/beta.bluetab.net\/en\/2023\/10\/lakehouse-streaming-en-aws-con-apache-flink-y-hudi-parte-2\/","title":{"rendered":"LakeHouse Streaming en AWS con Apache Flink y Hudi (Parte 2)"},"content":{"rendered":"<figure><a href=\"https:\/\/www.linkedin.com\/in\/albertojaenrevuelta\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/albertojaenrevuelta\/\" target=\"_blank\" rel=\"noopener\">Alberto Jaen<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<figure><a href=\"https:\/\/www.linkedin.com\/in\/alfonsojerezizquierdo\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/alfonsojerezizquierdo\/\" target=\"_blank\" rel=\"noopener\">Alfonso Jerez<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<figure><a href=\"https:\/\/www.linkedin.com\/in\/adrianjimenezhernandez\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/adrianjimenezhernandez\/\" target=\"_blank\" rel=\"noopener\">Adri\u00e1n Jim\u00e9nez<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<h2>Introducci\u00f3n<\/h2>\n<p>Este art\u00edculo es el segundo en una serie de publicaciones que se centran en la <b>creaci\u00f3n de un LakeHouse con Hudi<\/b> a partir de una ingesta en streaming procesada por una aplicaci\u00f3n Flink. <a href=\"https:\/\/beta.bluetab.net\/lakehouse-streaming-en-aws-con-apache-flink-y-hudi\/\">El primer art\u00edculo<\/a> se centra en sentar una buena base para esta plataforma, donde se desplegaron unas aplicaciones Flink con KDA (Kinesis Data Analytics) para cada tipo de formato (MoR, CoW para Hudi y JSON) que escriben el resultado de este procesamiento en unos <i>buckets<\/i>.<\/p>\n<p>El env\u00edo de datos que se utiliza como <i>input<\/i> se mandaba en el anterior art\u00edculo desde una m\u00e1quina en local ejecutando una aplicaci\u00f3n de Locust, lo que puede presentar problemas a la hora de escalar y querer procesar un volumen alto de eventos. Adem\u00e1s, las aplicaciones de Kinesis Data Analytics con Flink presentan problemas de agilidad en su modo de autoescalado. Todos estos nuevos retos ser\u00e1n resueltos en este art\u00edculo.<\/p>\n<p>Tambi\u00e9n se catalogar\u00e1n estas tablas en Glue, servicio que disponibiliza un cat\u00e1logo de datos en AWS, para poder acceder a estos y as\u00ed realizar <i>queries<\/i> de todo tipo. Como motor de <i>queries <\/i>que consumir\u00e1 estos metadatos se utilizar\u00e1 Athena, que proporciona una experiencia escalable, \u00e1gil y <i>serverless<\/i> para poder ejecutar <i>queries<\/i> con SQL o Spark para nuestras tablas alojadas en S3.<\/p>\n<p>Por otro lado, <b>en este art\u00edculo tambi\u00e9n se han desplegado los componentes necesarios para poder monitorizar nuestras aplicaciones<\/b> y extraer as\u00ed conclusiones sobre la velocidad a la que se ingestan los datos y los posibles problemas a resolver para que el procesamiento tenga la latencia requerida seg\u00fan los requisitos que se impongan.<\/p>\n<p>Finalmente se realizar\u00e1 una <b>comparativa en cuanto a rendimiento y latencia de las diferentes aplicaciones de Flink<\/b> que escriben datos en los formatos de Hudi y JSON para as\u00ed poder ver las diferentes ventajas e inconvenientes de estos formatos.\u00a0<\/p>\n<h2>Arquitectura<br \/>\n<\/h2>\n<p>A continuaci\u00f3n se puede ver la arquitectura a alto nivel que se desplegar\u00e1:<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"296\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17-1024x296.png\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17-1024x296.png 1024w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17-300x87.png 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17-768x222.png 768w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17-1536x444.png 1536w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image17.png 1999w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Para un mayor entendimiento vamos a explicarla de izquierda a derecha. Como se puede observar, el cambio m\u00e1s rese\u00f1able con respecto al primer art\u00edculo es la <b>inclusi\u00f3n de un cluster de Kubernetes<\/b> para poder escalar los eventos que ser\u00e1n mandados como <i>input <\/i>de nuestra aplicaci\u00f3n de <i>streaming<\/i>. De esta manera se podr\u00e1 testear de manera exhaustiva el rendimiento de las aplicaciones de Flink dependiendo de su aprovisionamiento y sobre todo del tipo de formato y tabla en el que escriben al LakeHouse. Adem\u00e1s, se ha disponibilizado un ALB (Application Load Balancer) que permite acceder a la interfaz de Locust para poder definir el n\u00famero de usuarios a simular y c\u00f3mo deben escalar estos con el tiempo. La URL para acceder a esta aparecer\u00e1 como <i>output <\/i>al desplegar la infraestructura con Terraform.<\/p>\n<p>Por otro lado se han realizado <b>cambios rese\u00f1ables en las aplicaciones KDA de Flink y el <\/b><b><i>stream <\/i><\/b>del que leen estas. Cada aplicaci\u00f3n lee ahora como consumidores EFO (Enhanced Fan Out), de tal manera que cada una de ellas tiene un ancho de banda dedicado. La raz\u00f3n de este cambio y sus detalles ser\u00e1n explicados m\u00e1s en detalle en el apartado dedicado para Kinesis.<\/p>\n<p>En cuanto a la monitorizaci\u00f3n y la extracci\u00f3n de m\u00e9tricas en NRT (Near Real Time) se han desplegado unas funciones lambdas que acceden a las tablas apoy\u00e1ndose en Athena gracias a haber registrado los metadatos de estas en el cat\u00e1logo de Glue. Es importante resaltar que los metadatos de las tablas de Hudi son registrados en Glue por Flink pero en el caso de JSON se despliega un <i>crawler <\/i>que registra estas tablas en el cat\u00e1logo. Este crawler se debe ejecutar manualmente para que esta tabla quede registrada en Glue.<\/p>\n<h2>Escalado<\/h2>\n<h3>Kinesis Stream<\/h3>\n<p>Dado que el objetivo es someter la aplicaci\u00f3n a una carga considerable de eventos por segundo, es necesario explicar c\u00f3mo cada una de las piezas de la arquitectura pueden escalar de acuerdo al volumen de datos.<\/p>\n<p>Como hemos comentado previamente, se ha optado por un Kinesis Stream <i>On-Demand<\/i> para automatizar el escalado de los <i>shards<\/i> durante las pruebas de carga. Es necesario tener en cuenta que estos <i>streams<\/i> pueden acomodar una tasa de escritura de hasta el 200% de lo especificado por el n\u00famero de <i>shards<\/i> en un momento dado.<\/p>\n<p>Una vez que el <i>stream<\/i> se encuentra por encima del 100%, aumentar\u00e1 autom\u00e1ticamente el n\u00famero de <i>shards<\/i> en un plazo de 15 minutos. La \u00fanica limitaci\u00f3n por tanto es no superar el doble del volumen de escritura admitido en menos de dicho periodo.<\/p>\n<p>Por otro lado, dado que se tendr\u00e1n tres aplicaciones de Flink leyendo del mismo <i>stream<\/i>, las limitaciones a nivel de lectura ser\u00e1n el mayor problema. Un Kinesis Stream solo admite 5 llamadas <i>GetRecord<\/i> por <i>shard <\/i>por segundo. Dado que cada aplicaci\u00f3n tiene que leer todo el <i>stream<\/i> (y por lo tanto, todos los <i>shards<\/i>), aumentar el n\u00famero de <i>shards<\/i> no ayuda a solventar este problema.<\/p>\n<p>La soluci\u00f3n pasa por registrar cada una de las aplicaciones como un consumidor Enhanced Fan-Out. Esta funcionalidad de los Kinesis Stream provee a cada uno de estos consumidores con un l\u00edmite individual de 5 llamadas <i>GetRecord<\/i> y 2MB por <i>shard<\/i> por segundo de lectura.<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"851\" height=\"501\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image7.png\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image7.png 851w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image7-300x177.png 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image7-768x452.png 768w\" sizes=\"(max-width: 851px) 100vw, 851px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Esta configuraci\u00f3n se realiza en el lado del consumidor, en nuestro caso mediante el conector de Kinesis para Flink:<\/p>\n<pre><code class='language-python'>'scan.stream.recordpublisher' = 'EFO',\n'scan.stream.efo.registration' = 'EAGER\/LAZY',\n'scan.stream.efo.consumername' = '{consumer_name}' <\/code><\/pre>\n<p>Conviene mencionar que alternativamente, es posible aumentar la latencia de lectura de nuestras aplicaciones de Flink. Por defecto Flink realiza una lectura cada 200 ms por <i>shard<\/i>, de modo que una aplicaci\u00f3n consume completamente la cuota de lectura de un <i>stream<\/i>. Incrementando este valor a 600ms podr\u00edamos acomodar las tres aplicaciones, a costa de una mayor latencia:<\/p>\n<pre><code class='language-python'>scan.shard.getrecords.intervalmillis = '600' <\/code><\/pre>\n<p>Tambi\u00e9n se har\u00e1 uso de la opci\u00f3n <i>Adaptive Reads<\/i>, que modifica din\u00e1micamente el n\u00famero de eventos recogidos por llamada en funci\u00f3n del tama\u00f1o de cada record. Esto permite aprovechar los 2 MB\/s por <i>shard <\/i>disponibles para cada consumidor:\u00a0 <\/p>\n<pre><code class='language-python'>'scan.shard.adaptivereads' = 'true' <\/code><\/pre>\n<p>En lo que respecta al escalado en KPUs (<i>Kinesis Processing Unit<\/i>) de Flink, se ha optado por no hacer uso del autoescalado, ya que cada proceso de escalado incurren en <i>downtime<\/i> para la aplicaci\u00f3n. Debido a los diferentes requerimientos de cada una de las aplicaciones, las acciones de escalado en momentos inesperados podr\u00edan interrumpir las pruebas de carga. Adem\u00e1s es interesante medir el rendimiento de escritura de cada una de las aplicaciones en igualdad de capacidad de computaci\u00f3n.<\/p>\n<h2>Hudi<\/h2>\n<h3>Timeline<\/h3>\n<p>Uno de los sistemas base sobre la que se sustenta el funcionamiento y caracter\u00edsticas de Hudi es la <i>timeline<\/i>. Hudi guarda un registro temporal de todas las acciones que se han realizado sobre la tabla, as\u00ed como el estado de esta acci\u00f3n.<\/p>\n<p>Las principales acciones que componen la <i>timeline <\/i>son<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Commits<\/i><\/b> &#8211; escritura at\u00f3mica de un conjunto de registros en la tabla en formato columnar<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Delta Commit<\/i><\/b> &#8211; similar al <i>commit<\/i>, representa una escritura de registros en forma de <i>logs <\/i>en una tabla <i>Merge on Read<\/i><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Compaction<\/i><\/b> &#8211; compactaci\u00f3n de las escrituras en <i>logs <\/i>(<i>delta commits<\/i>) de una tabla MoR a formato columnar<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Cleans<\/i><\/b> &#8211; borrado de versiones antiguas de archivos<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Rollback<\/i><\/b> &#8211; eliminado de los registros escritos por un <i>commit <\/i>o <i>delta commit <\/i>fallido<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Savepoint<\/i><\/b> &#8211; marca un conjunto de archivos como \u201cguardados\u201d para que no sean eliminados por el proceso de limpieza. Permite restaurar la tabla a un punto anterior en la timeline<\/li>\n<\/ul>\n<p>Cualquiera de estas acciones pueden encontrarse en uno de estos tres estados<\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Requested<\/i><\/b> &#8211; una acci\u00f3n ha sido planeada sin iniciar<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Inflight<\/i><\/b> &#8211; la acci\u00f3n est\u00e1 en proceso<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Completed<\/i><\/b> &#8211; denota que la acci\u00f3n ha sido completada<\/li>\n<\/ol>\n<h3>Tipos de tabla<\/h3>\n<p>Como se ha dejado entrever en el funcionamiento de la <i>timeline <\/i>de Hudi, existen dos tipos de escritura soportados: columnar y <i>logs<\/i>. El formato columnar (parquet) constituye la forma final de una tabla de Hudi, junto con los metadatos de la <i>timeline<\/i>. Sin embargo, es posible hacer uso de las escrituras en <i>logs <\/i>(avro) para disminuir la latencia de escritura y eventualmente compactarse a formato columnar sin entorpecer la escritura.<\/p>\n<p>El uso de estos m\u00e9todos de escritura dan lugar a los dos tipos de tabla que Hudi pone a nuestra disposici\u00f3n<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Copy on Write<\/i><\/b> &#8211; las escrituras se realizan exclusivamente en formato columnar, creando un nuevo fichero con los nuevos registros de la tabla. Los datos est\u00e1n disponibles inmediatamente pero incurre en mayor latencia de escritura<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Merge on Read<\/i><\/b> &#8211; hace uso de la escritura en <i>logs<\/i>. Los nuevos registros son inicialmente escritos como <i>logs<\/i>, y posteriormente ser\u00e1n transformados a formato columnar por el proceso de compactaci\u00f3n. Obtenemos menor latencia de escritura a costa de latencia de lectura; los nuevos registros no estar\u00e1n disponibles hasta que se realice la compactaci\u00f3n.\n<\/li>\n<\/ul>\n<h3>Tipos de Query<\/h3>\n<p>Para poder aprovechar las caracter\u00edsticas de cada tipo de tabla, existen tres tipos de <i>queries <\/i>que se pueden realizar sobre una tabla de Hudi<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Snapshot<\/i><\/b> &#8211; obtiene la \u00faltima versi\u00f3n de la tabla. Para las tablas MoR esto implica incurrir en un proceso de compactaci\u00f3n para obtener los \u00faltimos registros en formato <i>log<\/i>.\u00a0<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Read Optimized<\/i><\/b> &#8211; para tablas MoR, lee s\u00f3lamente los registros ya expuestos en formato columnar sin incurrir en latencia de lectura adicional.<\/li>\n<li><b><i>Incremental<\/i><\/b> &#8211; recoge \u00fanicamente los nuevos registros desde un cierto <i>commit <\/i>o compactaci\u00f3n, facilitando la creaci\u00f3n de <i>pipelines <\/i>incrementales. No est\u00e1 soportada por Athena<\/li>\n<\/ul>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"361\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image1.png\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image1.png 821w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image1-300x132.png 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image1-768x338.png 768w\" sizes=\"(max-width: 821px) 100vw, 821px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<h2 contenteditable=\"true\" data-elementor-setting-key=\"title\" data-pen-placeholder=\"Teclea aqu\u00ed...\">Integraci\u00f3n con Glue Catalog<\/h2>\n<p>El conector de Hudi permite una integraci\u00f3n nativa con el cat\u00e1logo de Glue en AWS. Basta con a\u00f1adir las dependencias de Hive en nuestra aplicaci\u00f3n de Flink:<\/p>\n<pre><code class='language-python'>com.amazonaws.aws-java-sdk-glue\norg.apache.hive.hive-common\norg.apache.hive.hive-exec <\/code><\/pre>\n<p>Y especificar la configuraci\u00f3n del cat\u00e1logo en el conector de Hudi:<\/p>\n<pre><code class='language-python'>'hive_sync.enable' = 'true',\n'hive_sync.db' = '{glue_database}',\n'hive_sync.table' = '{table_name}',\n'hive_sync.partition_fields' = '{partition_fields}',\n'hive_sync.mode' = 'glue',\n'hive_sync.use_jdbc' = 'false' <\/code><\/pre>\n<p>Con esta integraci\u00f3n, la aplicaci\u00f3n crear\u00e1 autom\u00e1ticamente las tablas en el cat\u00e1logo. Como hemos mencionado anteriormente, existen distintos tipos de <i>query <\/i>para consultar una tabla de Hudi. Se crear\u00e1n por tanto en el cat\u00e1logo distintas tablas para soportar las diferentes consultas.<\/p>\n<p>Para una tabla CoW, la tabla se consultar\u00e1 mediante una query <i>Snapshot<\/i>. Para MoR en cambio se pondr\u00e1n a disposici\u00f3n dos tablas, para soportar consultas <i>Read Optimized<\/i> o <i>Snapshot<\/i>.<\/p>\n<p>La principal aplicaci\u00f3n de Glue es de soporte a las lambdas para que al ejecutar las queries mediante Athena su ejecuci\u00f3n pueda realizarse de una forma m\u00e1s eficiente, r\u00e1pida y segura:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Glue Catalog:<\/b> almacenamiento centralizado de la informaci\u00f3n acerca de la organizaci\u00f3n, dise\u00f1o y formato de los datos, utilizado por Athena para realizar directamente las consultas a S3 sin necesidad de tener que apoyarse en terceros para conseguir esta informaci\u00f3n<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Automatizaci\u00f3n del Esquema:<\/b> Glue rastrea y cataloga autom\u00e1ticamente los datos en S3, detectando y adaptando los cambios en el esquema. Esto evita posibles errores y permite la lectura de los nuevos campos en caso de que se produzcan alteraciones en los esquemas de los eventos<\/li>\n<\/ul>\n<h2>Configuraci\u00f3n de Hudi<\/h2>\n<p>Es importante entender las configuraciones que nos ofrece Hudi para optimizar nuestra aplicaci\u00f3n, en particular para una aplicaci\u00f3n en <i>Near Real Time <\/i>conviene estar al tanto de las opciones disponibles. Aunque la capacidad de configuraci\u00f3n es inmensa <a href=\"\/#referencias\">[<\/a>1], se intentar\u00e1 sintetizar las que pueden ser m\u00e1s relevantes para una primera toma de contacto con esta tecnolog\u00eda.<\/p>\n<h3>Particionado<\/h3>\n<p>Apache Hudi ofrece los tipos de particionado que pueden encontrarse en otras soluciones, se detallar\u00e1n las principales y se justificara la implementada:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Simple<\/b>: particionado basado en un \u00fanico campo, en este caso el campo escogido es \u2018ticker\u2019 ya que se ha identificado que es el que tiene una cardinalidad menor.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Particionado Compuesto<\/b>: particionamiento basado en m\u00faltiples campos, podr\u00eda resultar interesante escoger un campo de baja cardinalidad (ticker) y otro de cardinalidad media (fecha)<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Particionado Din\u00e1mico<\/b>: elecci\u00f3n de la variable en base de los valores, puede resultar interesante cuando la cardinalidad de las variables puede sufrir variaciones y se quiera una actualizaci\u00f3n del particionamiento de una forma autom\u00e1tica y flexible.<\/li>\n<\/ul>\n<h3>\u00cdndices<\/h3>\n<p>Apache Hudi cuenta con una m\u00faltiples\u00a0 tipos de indexaci\u00f3n<a href=\"\/#referencias\">[<\/a>2], comentaremos brevemente los m\u00e1s comunes:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Bloom Index<\/i><\/b> &#8211; Hace uso de un bloom filter sobre la <i>key<\/i> de los eventos, adicionalmente se puede complementar con un filtrado por rango de de <i>key<\/i>. Funciona bien cuando tratamos con una tabla donde la mayor\u00eda de cambios ocurren en las particiones m\u00e1s recientes o para deduplicado de eventos.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Simple<\/i><\/b>: indexaci\u00f3n realizada mediante la combinaci\u00f3n de <i>FileID<\/i> y <i>RecordKey<\/i>. Recomendado cuando las operaciones <i>Upsert <\/i>no son tan frecuentes debido a la simplicidad que este ofrece.<\/li>\n<\/ul>\n<p>Ambos tipos de \u00edndices pueden ser usados en su forma global<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>\u00cdndice global<\/b> &#8211; Imponen la unicidad de las <i>keys<\/i> en todas las particiones de la tabla, es decir, garantizan que existir\u00e1 s\u00f3lamente un registro con una cierta <i>key<\/i>.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>\u00cdndice no global<\/b> &#8211; La unicidad de la <i>key<\/i> s\u00f3lo es exigida a nivel de partici\u00f3n. Si los datos son consistentes y una key s\u00f3lo va a existir en una partici\u00f3n, este tipo de \u00edndices ofrecen un rendimiento mucho mayor y mejor escalado.<\/li>\n<\/ul>\n<p>En este caso, se ha optado por un <i>Bloom Index<\/i>, el cual es el que se toma por defecto en caso de que no se declare expresamente:<\/p>\n<pre><code class='language-python'>&quot;hoodie.index.type&quot; = &quot;BLOOM&quot; <\/code><\/pre>\n<p>La elecci\u00f3n de este tipo de indexaci\u00f3n se debe a que los casos de uso que se han planteado requieren de un procesamiento de datos considerablemente alto y eficiente.<\/p>\n<h3>Tipos de operaci\u00f3n<\/h3>\n<p>Apache Hudi ofrece varios tipos de operaciones<a href=\"\/#referencias\">[<\/a>3] que permiten a los usuarios administrar y modificar conjuntos de datos de gran tama\u00f1o. A continuaci\u00f3n se detallan tanto las principales operaciones realizadas en los Stress Tests como en otros escenarios:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b><i>Upsert &#8211; <\/i><\/b>Es la operaci\u00f3n por defecto, y ejecutar\u00e1 un insert o un update dependiendo de si el registro ya existe tras una b\u00fasqueda en el \u00edndice. Con esta operaci\u00f3n la tabla no tendr\u00e1 duplicados para su clave primaria.<\/li>\n<li aria-level=\"1\"><b>Insert &#8211; <\/b>Esta operaci\u00f3n ignora la b\u00fasqueda en el \u00edndice a la hora de insertar eventos. Es la m\u00e1s r\u00e1pida pero la tabla puede contener duplicados. A\u00fan as\u00ed es \u00fatil si se utilizan m\u00e9todos auxiliares\u00a0 de deduplicado, o simplemente la existencia de estos es tolerable en el caso de uso.<\/li>\n<li aria-level=\"1\"><b><i>Delete<\/i><\/b>: Hudi ofrece dos m\u00e9todos de borrado. <i>Soft Delete<\/i> convierte a nulos los valores del evento a excepci\u00f3n de la <i>key<\/i>. <i>Hard Delete<\/i> ejecuta un borrado f\u00edsico del evento en la tabla.<\/li>\n<li aria-level=\"1\"><b><i>Bulk Insert<\/i><\/b> Operaci\u00f3n similar al Insert pero optimizada para la inserci\u00f3n de un gran volumen de datos, a costa de sacrificar ciertas garant\u00edas en el control del tama\u00f1o de ficheros. Escala bien para cientos de TBs en caso de <i>bootstrap<\/i> inicial de una tabla de gran tama\u00f1o.<\/li>\n<\/ul>\n<h3>Compactaci\u00f3n<\/h3>\n<p>En el caso de usar una tabla MoR es posible configurar el ritmo de compactaci\u00f3n de logs en parquet para buscar el equilibrio entre latencia de escritura y lectura que m\u00e1s convenga al caso de uso. Se pueden especificar una estrategia de tiempo o n\u00famero de delta commits (o ambos) que ejecutan un proceso de compactaci\u00f3n:<\/p>\n<pre><code class='language-python'>compaction.delta_commits\ncompaction.delta_seconds\ncompaction.trigger.strategy <\/code><\/pre>\n<h3>Acciones as\u00edncronas<\/h3>\n<p>Ciertas acciones de la <i>timeline <\/i>como la compactaci\u00f3n, limpieza, archivado y <i>clustering <\/i>pueden ser realizadas as\u00edncronamente por la aplicaci\u00f3n, o incluso ser relegadas a procesos auxiliares a la aplicaci\u00f3n de escritura. Para el caso de Flink, puede ayudar a mejorar la latencia de escritura y evitar problemas de <i>BackPressure<\/i> en la aplicaci\u00f3n:<\/p>\n<pre><code class='language-python'>compaction.async.enabled\nhoodie.clean.async\nhoodie.archive.async\nhoodie.clustering.async.enabled <\/code><\/pre>\n<h2>Stress Tests &#038; Insights<br \/>\n<\/h2>\n<p>Al desplegar las aplicaciones, se ha procedido a realizar distintos <i>tests <\/i>variando tanto la carga m\u00e1xima de eventos como la concurrencia y el grado exponencial de crecimiento de los mismos. Esto ha sido posible\u00a0 gracias a la flexibilidad ofrecida por Locust al estar levantado sobre un cluster de Kubernetes, pudiendo establecer un l\u00edmite m\u00e1ximo de concurrencia de eventos y un incremental de los mismos. En los <i>tests <\/i>se ha establecido un l\u00edmite m\u00e1ximo de 5 a 15K usuarios simult\u00e1neos (<i>Peak Concurrency<\/i>) escalando la frecuencia de los mismos de forma lineal, desde 5 a 20 usuarios m\u00e1s por segundo (<i>Spawn Rate<\/i>):<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"383\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image12-1024x383.png\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image12-1024x383.png 1024w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image12-300x112.png 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image12-768x288.png 768w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/image12.png 1167w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Se ha procedido a monitorizar los distintos test para as\u00ed sacar conclusiones del rendimiento teniendo en cuenta las caracter\u00edsticas espec\u00edficas de cada uno de los formatos. Las m\u00e9tricas en las que se han apoyado los an\u00e1lisis son tanto las nativas de CloudWatch Metrics (<i>CPU &amp; Memory Utilization<\/i>, <i>KPUs<\/i>, <i>LastCheckpoint SIze &amp; Duration<\/i>,..), como las m\u00e9tricas obtenidas a partir de las Lambdas que peri\u00f3dicamente consultan el n\u00famero de eventos disponibles en los buckets y realizan c\u00e1lculos del promedio de la latencia de los mismos.<\/p>\n<h3>N\u00famero de Eventos<\/h3>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"135\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/low5.jpg\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/low5.jpg 1000w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/low5-300x41.jpg 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/low5-768x104.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>A la hora de analizar el n\u00famero total de eventos procesados, los cuales son enviados de forma gradual, es decir, a medida que pasa el tiempo cada vez son m\u00e1s los eventos que se env\u00edan por segundo, se identifica una tendencia bastante similar aunque destacan JSON y Hudi MoR sobre Hudi CoW en cuanto a la rendimiento. Cabe destacar que JSON muestra un crecimiento m\u00e1s estable y constante en comparaci\u00f3n con Hudi MoR y CoW y esto se debe a que estos \u00faltimos son capaces de manejar actualizaciones incrementales en los datos.<\/p>\n<p>La similitud entre JSON y Hudi MoR hace que la elecci\u00f3n se base completamente en las caracter\u00edsticas del proyecto. En caso de que los datos no sean actualizados JSON puede resultar una soluci\u00f3n m\u00e1s interesante debido principalmente a su simplicidad, mientras que si hay una alta frecuencia de actualizaci\u00f3n de datos hist\u00f3ricos, Hudi MoR puede ser una mejor soluci\u00f3n. Esto se debe tanto a la mayor eficiencia en las tareas de lectura como por la posibilidad de registrar las distintas versiones de los datos.<\/p>\n<p>\u00a0<\/p>\n<h3>Latencia<\/h3>\n<p>Debido a la dificultad de estandarizar la l\u00f3gica del c\u00e1lculo de la latencia entre 3 tipos de almacenamiento distintos, se ha optado por simplificarla calculandolo como la diferencia entre la hora de creaci\u00f3n del evento y la del procesamiento en la respectiva aplicaci\u00f3n.<\/p>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"135\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new4.jpg\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new4.jpg 1000w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new4-300x41.jpg 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new4-768x104.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Se observa un comportamiento similar entre JSON y Hudi MoR, aunque este primero de una forma m\u00e1s cr\u00edtica, al tener una latencia inicial muy baja pero a medida que tanto el tiempo de procesamiento como el volumen de carga aumenta, esta latencia se ve negativamente afectada.<\/p>\n<p>La elecci\u00f3n entre JSON y Hudi MoR depender\u00e1 tanto de la tolerancia de fallo que tenga la aplicaci\u00f3n como las propias caracter\u00edsticas de cada uno de los formatos, en caso de que la estructura de los datos sea estable y no cambie con frecuencia,o bien, no dependa de actualizaciones incrementales y pueda lidiar con reescrituras completas, en ese caso JSON puede que sea una mejor opci\u00f3n.<\/p>\n<p>La elecci\u00f3n de Hudi CoW sobre MoR puede darse cuando se necesite una alta tolerancia a errores y una alta capacidad de recuperaci\u00f3n de eventos de escritura fallidos o corrompidos.`<\/p>\n<h3>Uso de CPU<\/h3>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"135\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new3.jpg\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new3.jpg 1000w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new3-300x41.jpg 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new3-768x104.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Al analizar el uso de CPU, se ha identificado cierta homogeneidad entre los distintos <i>tests <\/i>aun trabajando con distintas cargas de trabajo. JSON Y Hudi MoR destacan por tener los niveles de uso de CPU m\u00e1s bajos, ambos por distintos motivos. JSON destaca por la simplicidad al incluir directamente los nuevos datos sin necesidad de tener que lidiar con versionado de datos, mientras que MoR no consume tanta CPU ya que por sus caracter\u00edsticas, el consumo mayor de CPU se hace al realizar consultas de lectura, en las tareas de escritura \u00fanicamente identifica los cambios que ser\u00e1n aplicados al consultarlos.<\/p>\n<p>Recordar que las m\u00e9tricas nativas de CloudWatch \u00fanicamente nos permiten monitorizar las aplicaciones, que corresponden a las tareas de escritura. La monitorizaci\u00f3n de las tareas de lectura corresponde a las Lambdas mencionadas anteriormente.\u00a0<\/p>\n<p>En este caso MoR es m\u00e1s beneficioso respecto a CoW, dado que el mayor consumo de CPU en MoR se produce al consultar los datos almacenados mientras que en CoW tiene lugar al actualizar los datos.<\/p>\n<p>La elecci\u00f3n entre los formatos m\u00e1s eficientes se deben a las necesidades del proyecto, en caso de que se requiera una mayor tolerancia al fallo, versionado de los datos y una mayor eficiencia de lectura, se optara por MoR frente a JSON, entre los dos formatos de Hudi, de nuevo, la elecci\u00f3n depender\u00e1 de las caracter\u00edsticas del proyecto, en caso de que las consultas requieran transformaciones pesadas y\/o complejas se optar\u00eda por MoR, si en cambio, el proyecto requiera de una mayor integridad de datos y\/o la ingesta de datos sea en <i>batch<\/i>,\u00a0 resultar\u00eda m\u00e1s interesante CoW debido a que al trabajar con esos vol\u00famenes de datos, el contar con copias de seguridad, en caso de surgir errores, el impacto en t\u00e9rmino de costes y tiempo de recuperaci\u00f3n es menor.<\/p>\n<p>\u00a0<\/p>\n<h3>Memory Utilization<\/h3>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"135\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new2.jpg\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new2.jpg 1000w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new2-300x41.jpg 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new2-768x104.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>JSON de nuevo destaca por tener los valores de uso de memoria m\u00e1s bajos aunque para la operativa de transformaciones que se realizan son relativamente altos y m\u00e1s teniendo en cuenta que no tiene que lidiar con la administraci\u00f3n de versiones o la combinaci\u00f3n de datos. Estos valores se deben a que no tiene capacidades de compresi\u00f3n optimizadas ni manejo eficiente de esquemas.<\/p>\n<p>Respecto a Hudi, se pueden obtener unas conclusiones similares a las del apartado de uso de CPU, MoR tiene una utilizaci\u00f3n de memoria mayor que JSON debido al procesamiento de <i>logs<\/i> delta y la administraci\u00f3n de versiones y una menor a CoW ya que la consolidaci\u00f3n real de los datos no ocurre durante la escritura.<\/p>\n<h3>Last Checkpoint Size<\/h3>\n<p>\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"135\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new1.jpg\" alt=\"\" srcset=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new1.jpg 1000w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new1-300x41.jpg 300w, https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/new1-768x104.jpg 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/p>\n<p>Destacar, nuevamente, la estabilidad de JSON frente a las aplicaciones Hudi, ya que no solo muestra en los <i>test <\/i>realizados un valor inferior a ambos, si no una estabilidad que no se consigue ni con MoR ni CoW, ya que como puede apreciarse, al monitorear el tama\u00f1o de los <i>Checkpoints<\/i>, se percibe una volatilidad considerable.<\/p>\n<p>La volatilidad percibida en las aplicaciones Hudi se debe principalmente a fallos surgidos en <i>Checkpoints <\/i>lo que conlleva que el <i>Checkpoint <\/i>posterior al fallido, tenga un volumen mayor. Adem\u00e1s de esto, la volatilidad en los tama\u00f1os de los <i>Checkpoints <\/i>puede estar relacionado con las operaciones de optimizaci\u00f3n y compactaci\u00f3n realizadas internamente que puede conllevar la compactaci\u00f3n del estado y que esto reduzca considerablemente el tama\u00f1o del mismo.<\/p>\n<h2>Desaf\u00edos en el desarrollo<\/h2>\n<h3>Read Throughput de Kinesis y EFO<\/h3>\n<p>Para no sobrepasar el l\u00edmite de lectura sobre el Kinesis Stream se ha optado por suscribir los consumidores como Enhanced Fan-Out. En algunas pruebas en conjunto con Autoscaling esto ha dado problemas con el conector de Kinesis de Flink siendo incapaces de cerrar conexiones a la hora de escalar el cluster.<\/p>\n<h3>Configuraci\u00f3n de Hudi<\/h3>\n<p>La configuraci\u00f3n de Hudi ha sido otro de los puntos de fricci\u00f3n durante el desarrollo. Bajo cargas elevadas los procesos de compactaci\u00f3n y limpieza son m\u00e1s propensos a causar problemas de Backpressure y causar errores en la aplicaci\u00f3n. Aunque configurar estos procesos para que ocurran de forma as\u00edncrona puede aliviar este problema, pueden surgir conflictos y desalineaci\u00f3n entre procesos bajo cargas elevadas. Un equilibrio entre estas configuraciones y la capacidad del cluster de la aplicaci\u00f3n son claves para el buen funcionamiento de la aplicaci\u00f3n.<\/p>\n<h3>Heterogeneidad de formato<\/h3>\n<p>Al hacer un an\u00e1lisis del rendimiento de las 3 aplicaciones, se cuenta con una dificultad adicional debido a la naturaleza de los tipos de formato, teniendo esto tanto un impacto a la hora de plantear la arquitectura como en el planteamiento de las l\u00f3gicas.<br \/>El distinto comportamiento de los formatos en la ingesta, complica el desarrollo de las l\u00f3gicas a la hora de calcular la latencia. MoR escribe en logs previa compactaci\u00f3n, por lo que los datos no est\u00e1n disponibles inmediatamente como ocurre con CoW o JSON.\u00a0 Esto implica que la m\u00e9trica com\u00fan medible para todos los formatos es la de disponibilidad de lectura, la cual no es el principal objetivo de una tabla MoR.\u00a0\u00a0<\/p>\n<h3>Sincronizaci\u00f3n con el Glue Catalog<\/h3>\n<p>Una de las grandes ventajas que nos hemos encontrado con Hudi es su capacidad para sincronizarse con el cat\u00e1logo de Glue, creando las tablas y manteni\u00e9ndose actualizadas sin necesidad de un crawler. Esto permite una aplicaci\u00f3n y arquitectura m\u00e1s limpia que para el caso de JSON, para el cual debe ejecutarse manualmente al desplegar las aplicaciones.<\/p>\n<h2>Conclusiones<\/h2>\n<p>Los resultados de los <i>tests <\/i>muestran <b>diferencias considerables entre los formatos JSON, Hudi MoR y CoW<\/b> en t\u00e9rminos de eficiencia, capacidad de respuesta y utilizaci\u00f3n de recursos. Se procede a analizar cada uno de los aspectos m\u00e1s en detalle:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Eficiencia de Procesamiento:<\/b> JSON y Hudi MoR destacan en la mayor\u00eda de las m\u00e9tricas, mostrando un desempe\u00f1o \u00f3ptimo en t\u00e9rminos de Latencia, <i>CPU &amp; Memory Utilization<\/i>. Sin embargo, el comportamiento de JSON es m\u00e1s estable y predecible, aunque MoR cuente con ventajas sobre JSON, como por ejemplo, en la gesti\u00f3n de actualizaciones incrementales.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Resiliencia y Tolerancia a Fallos:<\/b> la tolerancia a fallos es un factor muy importante en la decisi\u00f3n sobre la elecci\u00f3n entre Hudi y JSON. En el caso de\u00a0 MoR y CoW, depender\u00e1 del grado de criticidad, ya que a nivel general el rendimiento en tareas de escritura para MoR es superior.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Uso de Recursos: <\/b>JSON se muestra como el m\u00e1s ligero, con baja utilizaci\u00f3n de CPU y memoria, debido a su simplicidad inherente. Mientras que Hudi MoR y CoW, por la naturaleza de su dise\u00f1o y gesti\u00f3n de datos, requieren m\u00e1s recursos, especialmente en operaciones que involucran el manejo de versiones y la compactaci\u00f3n de datos.<\/li>\n<\/ul>\n<p>Para finalizar, resulta interesante identificar en qu\u00e9que<b> casos de uso o proyectos puede resultar m\u00e1s recomendable cada uno de los formatos<\/b> en funci\u00f3n de las caracter\u00edsticas de los mismos y las <i>red flags <\/i>que puedan establecerse:<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>JSON:<\/b> Recomendado para aplicaciones con estructuras de datos estables que no requieren actualizaciones incrementales y donde la simplicidad y la estabilidad son clave.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Hudi MoR:<\/b> Adecuado para proyectos que requieren una gesti\u00f3n eficiente de actualizaciones incrementales y donde la latencia y la eficiencia en la escritura son cruciales.<\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Hudi CoW:<\/b> Ideal para contextos donde la integridad de los datos es esencial, y se necesita una robusta recuperaci\u00f3n de errores, especialmente en escenarios de ingestas en batch.\u00a0<\/li>\n<\/ul>\n<h2>Referencias<\/h2>\n<p>[1] Configuraciones Tablas Hudi. [<a href=\"https:\/\/hudi.apache.org\/docs\/next\/configurations\/\" target=\"_blank\" rel=\"noopener\">link<\/a>]<\/p>\n<p>[2] Tipos de Indexacion Hudi. [<a href=\"https:\/\/hudi.apache.org\/docs\/next\/indexing\/#index-types-in-hudi\" target=\"_blank\" rel=\"noopener\">link<\/a>]<\/p>\n<p>[3] Tipos de Operaciones Hudi. [<a href=\"https:\/\/hudi.apache.org\/docs\/write_operations\/\" target=\"_blank\" rel=\"noopener\">link<\/a>]<\/p>\n<h2>Autores<\/h2>\n<figure><a href=\"https:\/\/www.linkedin.com\/in\/albertojaenrevuelta\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/albertojaenrevuelta\/\" target=\"_blank\" rel=\"noopener\">Alberto Jaen<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<p>Empec\u00e9 mi carrera laboral con el desarrollo, mantenimiento y administraci\u00f3n de bases de datos multidimensionales y <i>Data Lakes<\/i>. A partir de ah\u00ed comenc\u00e9 a estar interesado en plataformas de datos y arquitecturas cloud, estando certificado 3 veces en AWS y 2 con Hashicorp.<\/p>\n<p>Actualmente me encuentro trabajando como un <i>Cloud Engineer <\/i>desarrollando Data Lakes y DataWarehouses con AWS para un cliente relacionado con la organizaci\u00f3n de eventos deportivos a nivel mundial.<\/p>\n<figure><a href=\"https:\/\/www.linkedin.com\/in\/alfonsojerezizquierdo\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/alfonsojerezizquierdo\/\" target=\"_blank\" rel=\"noopener\">Alfonso Jerez<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<p>\t\tApasionado de los datos y las nuevas tecnolog\u00edas, especializado como AWS Cloud Engineer en la optimizaci\u00f3n de DataWarehouses y procesos de ingesta y transformaci\u00f3n de Data Lakes. Motivado por la mejora continua y automatizaci\u00f3n de la integraci\u00f3n de servicios.<\/p>\n<p>Colaborando activamente con el grupo de Pr\u00e1ctica Cloud en investigaciones y desarrollo de blogs de tecnolog\u00edas punteras e innovadoras tales como esta, fomentando as\u00ed el continuo aprendizaje.<\/p>\n<figure><a href=\"https:\/\/www.linkedin.com\/in\/adrianjimenezhernandez\/\" target=\"_blank\" tabindex=\"-1\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2022\/03\/cropped-Isotipo-Bluetab-150x150.png\" alt=\"\" \/><\/a><\/figure>\n<h4><a href=\"https:\/\/www.linkedin.com\/in\/adrianjimenezhernandez\/\" target=\"_blank\" rel=\"noopener\">Adri\u00e1n Jim\u00e9nez<\/a><\/h4>\n<p>AWS Cloud Engineer <\/p>\n<p>Dedicado al aprendizaje constante de nuevas tecnolog\u00edas y su aplicaci\u00f3n, disfrutando de utilizarlas en la resoluci\u00f3n de desaf\u00edos tecnol\u00f3gicos. Desarrollo mi carrera como Cloud Engineer dise\u00f1ando, implementando y manteniendo infraestructura en AWS.<\/p>\n<p>Colaboro activamente en la Pr\u00e1ctica Cloud, donde investigamos y experimentamos con nuevas tecnolog\u00edas, buscando soluciones para los retos que enfrentan nuestros clientes.<\/p>\n<h4>\n\t\t\t\tNavegaci\u00f3n\t\t\t<\/h4>\n<h5>\u00bfQuieres saber m\u00e1s de lo que ofrecemos y ver otros casos de \u00e9xito?<\/h5>\n<p>\t\t\t<a href=\"\/\"><br \/>\n\t\t\t\t\t\tDESCUBRE BLUETAB<br \/>\n\t\t\t\t\t<\/a><\/p>\n<p><b>SOLUCIONES, <\/b>SOMOS EXPERTOS<\/p>\n<p>\t\t\t\t\t<a href=\"\/soluciones\/data-strategy\/\"><\/p>\n<h5>\n\t\t\t\t\t\tDATA STRATEGY\t\t\t\t\t<\/h5>\n<p>\t\t\t\t\t\t<\/a><br \/>\n\t\t\t\t\t<a href=\"\/soluciones\/data-fabric\/\"><\/p>\n<h5>\n\t\t\t\t\t\tDATA FABRIC\t\t\t\t\t<\/h5>\n<p>\t\t\t\t\t\t<\/a><br \/>\n\t\t\t\t\t<a href=\"\/soluciones\/augmented-analytics\/\"><\/p>\n<h5>\n\t\t\t\t\t\tAUGMENTED ANALYTICS\t\t\t\t\t<\/h5>\n<p>\t\t\t\t\t\t<\/a><\/p>\n<p>Te puede interesar<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Alberto Jaen AWS Cloud Engineer Alfonso Jerez AWS Cloud Engineer Adri\u00e1n Jim\u00e9nez AWS Cloud Engineer Introducci\u00f3n Este art\u00edculo es el segundo en una serie de publicaciones que se centran en la creaci\u00f3n de un LakeHouse con Hudi a partir de una ingesta en streaming procesada por una aplicaci\u00f3n Flink. El primer art\u00edculo se centra en [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":20833,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"elementor_header_footer","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[8,9],"tags":[],"class_list":["post-15634","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-practices","category-tech"],"acf":[],"jetpack_featured_media_url":"https:\/\/beta.bluetab.net\/wp-content\/uploads\/2023\/10\/5.png","_links":{"self":[{"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/posts\/15634","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/comments?post=15634"}],"version-history":[{"count":0,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/posts\/15634\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/media\/20833"}],"wp:attachment":[{"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/media?parent=15634"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/categories?post=15634"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/beta.bluetab.net\/en\/wp-json\/wp\/v2\/tags?post=15634"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}