• 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
  • ES
    • EN

Practices

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

mayo 9, 2023 by Bluetab

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

Lucas Calvo

Cloud Engineer

Introducción

En este artículo vamos a hablar de CDKTF y de cómo utilizar todas sus ventajas para desplegar infraestructura de forma programática y reutilizable en GCP. También veremos cómo integrar CDKTF con tus módulos de terraform[1] para desplegar infraestructura más reutilizable bajo la supervisión de tu organización.

CDKTF abre un mundo de posibilidades para llevar a nuestra organización al siguiente nivel de automatización, además de facilitar el despliegue de la infraestructura a las personas más cercanas a la parte de desarrollo. En este artículo daremos algunas indicaciones de cuando es una buena opción utilizar CDKTF y cuando seguir utilizando terraform a través de HCL, ya que no en todos los casos de usos el CDKTF nos aportará un valor añadido.

¿Qué necesitas para entender este artículo?

  • Algunos conceptos sobre Terraform[2].
  • Instalar el CDKTF [3].
  • Algunos conceptos sobre python.
  • Necesitas una cuenta gratuita en GCP.

Todo el código utilizado en este artículo está en el repositorio[4] de Github.

¿Es CDKTF la solución milagrosa para los despliegues en nuestra organización? Veámoslo.

¿Que es el CDKTF?

CDKTF, también llamado Cloud Development Kit for Terraform, permite definir y aprovisionar infraestructura de forma programática. En este artículo utilizaremos python para desplegar algunos recursos en GCP. El punto fuerte de CDKTF es que no necesitas aprender HashiCorp Configuration Language (HCL), sólo necesitas saber Python que es más flexible que HCL porque te permite crear más integraciones con herramientas de tu organización y con otras APIs. Incluso puedes crear algunas clases específicas en Python para hacer tu código más reutilizable.

Primeros pasos con CDKTF

Una vez explicado CDKTF, procederemos a crear nuestro primer proyecto. Para ello desplegaremos un cloud storage y un topic de pubsub en GCP, utilizaremos recursos terraform por simplicidad. Comenzaremos explicando varios comandos del CDKTF:

  • cdktf init –template=python

Este comando crea un nuevo proyecto CDK para Terraform usando una plantilla. Esto es muy útil cuando se quiere empezar a utilizar un nuevo proveedor, en nuestro caso el proveedor de Google.

Una vez ejecutado este comando veremos la siguiente plantilla:

Los ficheros más importantes son `main.py` y `cdktf.json`. Hablemos de ellos.

En el fichero `main.py` es donde se declara toda la infraestructura que vamos a desplegar con su lógica. Haremos uso del proveedor de Google para definir nuestros recursos, `cloud storage` y `pubsub topic`. Luego para definir e importar el proveedor de google y la librería de almacenamiento y pubsub importaremos los siguientes módulos en python:

```python
from imports.google.provider import GoogleProvider
from imports.google.storage_bucket import StorageBucket
from imports.google.pubsub_topic import PubsubTopic
``` 

Estos proveedores se definen en el archivo `cdktf.json`, este archivo es donde puedes proporcionar los ajustes de configuración personalizados para tu aplicación y definir los proveedores y módulos que deseas utilizar. Cuando inicializamos la plantilla con el comando `cdktf init –template=python`, la plantilla genera un archivo `cdktf.json` básico en tu directorio raíz que puedes personalizar para tu aplicación.

Este archivo tiene la siguiente información:

```json
{
  "language": "python",
  "app": "pipenv run python main.py",
  "projectId": "da305019-c0fc-4e47-b4ad-1a705cdd8811",
  "sendCrashReports": "false",
  "terraformProviders": ["google@~> 4.0"],
  "terraformModules": [],
  "codeMakerOutput": "imports",
  "context": {
    "excludeStackIdFromLogicalIds": "true",
    "allowSepCharsInLogicalIds": "true"
  }
}
``` 

En la línea terraformProviders hemos definido el proveedor de google que contiene todos los recursos que necesitamos. En la sección Integración con tus propios módulos aprenderemos a configurar este fichero para utilizar tus propios módulos terraform.

Una vez configurados los proveedores ya podemos definir nuestros recursos con Python:

```python
class MyStack(TerraformStack):
    def __init__(self, scope: Construct, id: str):
        super().__init__(scope, id)

        GoogleProvider(self, "google", region="europe-west4",project="xxxxx")
        length = 5
        suffix = ''.join((random.choice(string.ascii_lowercase) for x in range(length)))
        bucket = StorageBucket(self, "gcs", name = "cdktf-test-1234-bt-"+ str(suffix), location = "EU", force_destroy = True)
        topic = PubsubTopic(self, "topic" ,name = "cdktf-topic", labels={"tool":"cdktf"})
        TerraformOutput(self,"bucket_self_link",value=bucket.self_link)
        TerraformOutput(self,"topic-id",value=topic.id)

app = App()
MyStack(app, "first_steps")

app.synth()
``` 

Estas líneas de código despliegan un cloud storage y un topic como hemos dicho previamente, también hemos creado un `string` aleatorio en python para añadir al cloud storage como sufijo. Para ello hemos añadido dos librerías más: `string` y `random`. Además, hemos añadido a nuestro script algunas salidas para ver alguna información importante sobre nuestro despliegue como `topic_id` o `bucket_self_link`.

El resultado final de nuestros primeros scripts con CDKTF es el siguiente:

```python
from constructs import Construct
from cdktf import App, TerraformStack, TerraformOutput
from imports.google.provider import GoogleProvider
from imports.google.storage_bucket import StorageBucket
from imports.google.pubsub_topic import PubsubTopic
import random
import string

class MyStack(TerraformStack):
    def __init__(self, scope: Construct, id: str):
        super().__init__(scope, id)

        GoogleProvider(self, "google", region="europe-west4",project="xxxxx")
        length = 5
        suffix = ''.join((random.choice(string.ascii_lowercase) for x in range(length)))
        bucket = StorageBucket(self, "gcs", name = "cdktf-test-1234-bt-"+ str(suffix), location = "EU", force_destroy = True)
        topic = PubsubTopic(self, "topic" ,name = "cdktf-topic", labels={"tool":"cdktf"})
        TerraformOutput(self,"bucket_self_link",value=bucket.self_link)
        TerraformOutput(self,"topic-id",value=topic.id)

app = App()
MyStack(app, "first_steps")

app.synth()
``` 

Ahora podemos desplegar nuestra infraestructura, para ello necesitamos ejecutar algunos comandos con CDKTF. En primer lugar, tenemos que descargar los proveedores y módulos para una aplicación y generar las construcciones CDK para ellos. Para ello utilizamos `cdktf get`. Utiliza el archivo de configuración `cdktf.json` para leer la lista de proveedores. Este comando sólo genera los bindings de los proveedores que faltan, por lo que es muy rápido si nada ha cambiado.

```bash
cdktf get
``` 

Esta es la salida del comando:

Usamos el flag –force para recrear todos los bindings. Con el proveedor descargado procederemos al despliegue ejecutando el comando `cdktf deploy`:

```bash
cdktf deploy
``` 

Esta es la salida del comando:

Con todos estos pasos hemos procedido a desplegar nuestra primera aplicación con el CDKTF. Algo bastante sencillo y con código muy reutilizable. Ahora vamos a proceder a la destrucción de la infraestructura para no incurrir en ningún coste. Utilizaremos el comando `cdktf destroy`.

Integraciones con tus propios módulos

Perfecto, una vez comprobado cómo funciona el CDKTF vamos a integrarlo con los módulos terraform que se desarrollan en nuestra empresa. Esto nos permitiría hacer el código mucho más reutilizable permitiendo que todo lo que se despliegue en el CDKTF se despliegue con los patrones que hemos definido en los módulos. Para esta prueba ejecutaremos la misma creación (gcs y topic) pero esta vez haciendo uso de los módulos previamente desarrollados que podéis encontrar en el siguiente repositorio.

  • Cloud Storage[5]
  • Pubsub[6]

Estos módulos han sido desarrollados con HCL y tienen ciertas nomenclaturas y lógica para facilitar al máximo el despliegue al resto de desarrolladores de mi organización.

Así que procedamos a crear otra plantilla con el comando `cdktf init –template=python` pero esta vez para usar nuestros propios módulos.

Una vez ejecutado tenemos la misma plantilla que en el apartado anterior. Ahora vamos a proceder a modificar el `cdktf.json` para añadir los módulos que vamos a utilizar y dos proveedores, google y google-beta, que son necesarios para el uso de estos módulos.

Este es el fichero `cdktf.json`:

```json
{
  "language": "python",
  "app": "pipenv run python main.py",
  "projectId": "f02a016f-d673-4390-86db-65348eadfb3f",
  "sendCrashReports": "false",
  "terraformProviders": ["google@~> 4.0", "google-beta@~> 4.0"],
  "terraformModules": [
    {
      "name": "gcp_pubsub",
      "source": "git::https://github.com/lucasberlang/gcp-pubsub.git?ref=v1.2.0"
    },
    {
      "name": "gcp_cloud_storage",
      "source": "git::https://github.com/lucasberlang/gcp-cloud-storage.git?ref=v1.2.0"
    }
  ],
  "codeMakerOutput": "imports",
  "context": {
    "excludeStackIdFromLogicalIds": "true",
    "allowSepCharsInLogicalIds": "true"
  }
}
```
 

Hemos añadido la línea terraform Modules donde indicamos el nombre del módulo y la fuente, en este caso nuestro repositorio de github. También hemos añadido la línea terraform providers como en el apartado anterior.

Una vez añadidos los proveedores y los módulos terraform vamos a instanciarlos en nuestro main, para ello solo tenemos que añadirlos como librerías y luego invocarlos con los parámetros que estén definidos en nuestro módulo. Puedes ir al readme del módulo que está subido en github para ver que parámetros son obligatorios y cuales son opcionales, también puedes ver salidas de esos módulos.

El código quedaría de la siguiente manera:

```python
#!/usr/bin/env python
from constructs import Construct
from cdktf import App, TerraformStack, TerraformOutput
from imports.google.provider import GoogleProvider
from imports.google_beta.provider import GoogleBetaProvider
from imports.gcp_pubsub import GcpPubsub
from imports.gcp_cloud_storage import GcpCloudStorage
import random
import string

class MyStack(TerraformStack):
    def __init__(self, scope: Construct, ns: str):
        super().__init__(scope, ns)
        GoogleProvider(self, "google", region="europe-west4")
        GoogleBetaProvider(self, "google-beta", region="europe-west4")
        length = 5
        suffix = ''.join((random.choice(string.ascii_lowercase) for x in range(length)))
        tags = {"provider" : "go",
                "region" : "euw4",
                "enterprise" : "bt",
                "account" : "poc",
                "system" : "ts",
                "environment" : "poc",
                "cmdb_name" : "",
                "security_exposure_level" : "mz",
                "status" : "",
                "on_service" : "yes"}

        topic = GcpPubsub(self,"topic",
          name = "cdktf-topic",
          project_id = "xxxxxxx",
          offset = 1,
          tags = tags)
          
        bucket = GcpCloudStorage(self,"bucket",
          name = "cdktf-test-1234-bt-" + suffix,
          project_id = "xxxxxxx",
          offset = 1,
          location = "europe-west4",
          force_destroy = True,
          tags = tags)
        
        TerraformOutput(self,"topic_id",value=topic.id_output)
        TerraformOutput(self,"bucket_self_link",value=bucket.bucket_output)

app = App()
MyStack(app, "cdktf_modules")

app.synth()
```
 

Para invocar nuestros módulos que hemos añadido previamente en el archivo `cdktf.json`, sólo tenemos que añadir este código:

```python
from imports.gcp_pubsub import GcpPubsub
from imports.gcp_cloud_storage import GcpCloudStorage
``` 

El resto del código es la invocación de nuestros módulos con una serie de parámetros para inicializarlos, como región, nombre, etc. También hemos añadido las salidas para tener algo de información sobre la creación de los recursos en GCP. Ahora, vamos a proceder al despliegue de los recursos para comprobar el correcto funcionamiento de CDKTF.

```bash
cdktf get --force
cdktf deploy
``` 

Una vez desplegada, comprobaremos nuestra infraestructura en GCP y procederemos a borrar toda con el comando `cdktf destroy`.

Evoluciones que puedes añadir a tu empresa

Gracias al CDKTF podemos crear nuevos automatismos mucho más nativos que con el HCL tradicional ya que podemos integrarnos con todo tipo de backend en nuestro propio desarrollo. Esto abre todo un nuevo mundo de posibilidades en el despliegue automático de infraestructuras.

Por ejemplo, si en tu empresa siempre te piden el mismo tipo de infraestructura desde los equipos de desarrollo, como una base de datos, un cluster kubernetes y luego los componentes de seguridad y comunicaciones asociados al caso de uso, ¿por qué no automatizar este proceso y no crear proyectos terraform a la carta?.

Podemos evolucionar nuestra plataforma de automatización creando un portal web que invoque a nuestro microservicio hecho con el CDKTF que hará las validaciones oportunas y luego procederá al despliegue. Esto también se podría hacer con terraform pero no de una forma tan nativa como con el CDKTF ya que ahora usando python (u otro lenguaje, Typescript, Go etc…) podemos crear flujos de trabajo mucho más complejos llamando a otros backends y haciendo todo tipo de integraciones con nuestras herramientas corporativas. Podríamos generar una plataforma de despliegue para automatizar todos nuestros despliegues genéricos que nos solicitan desde otros equipos como aplicaciones, analítica de datos, reporting, etc. Podríamos crear la siguiente arquitectura para resolver este problema:

Conclusiones

Después de haber trabajado varios años con terraform creo que el CDKTF es su evolución natural, aunque todavía está en una fase prematura. No cuenta con una comunidad tan grande como la que terraform tiene con HCL, lo que hace difícil iniciarse con esta herramienta. Depurar el código suele ser complicado y no tan fácil como con HCL. Los tutoriales oficiales no son muy completos por lo que muchas veces tendrás que encontrar tu propio camino para resolver algunos problemas derivados del uso de CDKTF. También creo que el CDKTF está en un punto de madurez como lo estaba terraform hace años en la versión inferior a la 0.11.0, es decir, funciona bien aunque todavía le queda mucho camino por recorrer.

Creo que si tu empresa ya utiliza terraform (HCL) de forma madura, cambiar el modelo a CDKTF no va a suponer grandes beneficios. El único beneficio de usar CDKTF es en un caso de uso como el mencionado en la sección anterior, donde puedes mezclar el uso de tus módulos ya desarrollados con HCL y CDKTF para llevar la automatización de cierta infraestructura a un nivel superior.

Por otro lado, CDKTF es una herramienta que podría recomendar si conoces python (u otros lenguajes) y no quieres aprender un lenguaje específico como HCL. CDKTF puede ser una buena herramienta si tu empresa no está en un punto de madurez avanzado con terraform o cualquier herramienta de IaC. El CDKTF te permite desarrollar de una forma más sencilla tu infraestructura como código, las integraciones con otras herramientas dentro de tu organización serán mucho más sencillas ya que podrás utilizar tu lenguaje de programación favorito para realizarlas. Puede crear clases y módulos reutilizables de forma sencilla, creando una comunidad de desarrollo CDKTF dentro de su propia empresa y permitiendo a los desarrolladores estar más apegados a la infraestructura, lo que siempre es un reto. También la parte de pruebas de tu código CDKTF será mucho más fácil y nativa haciendo uso de pytest u otros frameworks [7]. Probar con terraform (HCL) es más tedioso y ya tienes que usar frameworks como terratest para integrarlos en tu código.

En general creo que CDKTF es una buena herramienta y es la evolución natural de Terraform. Si queremos llevar nuestra automatización a otro nivel e integrarla con portales web o herramientas organizativas, CDKTF es la herramienta que necesitamos. También abre un mundo de posibilidades para los equipos de desarrollo, ya que podrán desplegar cualquier tipo de infraestructura utilizando un lenguaje de programación. Habrá que ver cómo evoluciona para ver cómo encaja en nuestras organizaciones y si alcanza el punto de madurez que ha alcanzado Terraform.

Referencias

[1] Ques es terraform.[link]

[2] Módulos de Terraform. [link]

[3] Guía de instalación del CDKTF. [link]

[4] Repositorio de CKDTF GitHub. [link]

[5] Repositorio de Cloud storage GitHub. [link]

[6] Repositorio de Pubsub GitHub. [link]

[7] Frameworks de testing.. [link]

Navegación

Lucas Calvo

Cloud Engineer

¿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

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

febrero 23, 2023
LEER MÁS

Detección de Fraude Bancario con aprendizaje automático

septiembre 17, 2020
LEER MÁS

KubeCon 2023: Una mirada hacia el futuro de Kubernetes

abril 26, 2023
LEER MÁS

Espiando a tu kubernetes con kubewatch

septiembre 14, 2020
LEER MÁS

Serverless Microservices

octubre 14, 2021
LEER MÁS

Guía avanzada sobre almacenamiento en Snowflake

octubre 3, 2022
LEER MÁS

Publicado en: Blog, Practices, 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

¿Existe el Azar?

noviembre 10, 2021
LEER MÁS

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

marzo 6, 2023
LEER MÁS

La gestión del cambio: El puente entre las ideas y el éxito

febrero 5, 2025
LEER MÁS

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

abril 7, 2021
LEER MÁS

Usando los Grandes Modelos de Lenguaje en información privada

marzo 11, 2024
LEER MÁS

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

junio 4, 2024
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

DataOps

octubre 24, 2023
LEER MÁS

MODELOS DE ENTREGA DE SERVICIOS EN LA NUBE

junio 27, 2022
LEER MÁS

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

junio 7, 2023
LEER MÁS

Detección de Fraude Bancario con aprendizaje automático II

septiembre 17, 2020
LEER MÁS

MDM como ventaja competitiva en las organizaciones

junio 18, 2024
LEER MÁS

Introducción a los productos de HashiCorp

agosto 25, 2020
LEER MÁS

Publicado en: Blog, interes, Practices, Tech

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

febrero 23, 2023 by Bluetab

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

Roberto García Parra

Technical Delivery Manager

Gabriel Gallardo Ruiz

Senior Data Architect

Introducción a Snowflake

Este artículo supone una continuación del artículo inicial que hicimos sobre el almacenamiento en Snowflake, y será el primero de una serie donde entraremos a fondo en las características más diferenciadoras de Snowflake. El primer artículo se puede consultar aquí.

Recordar que una de las características principales del almacenamiento en Snowflake es la inmutabilidad de los archivos: Cuando hay una operación DML sobre una tabla, los ficheros donde están los datos nunca se modifican, sino que se van creando nuevas versiones de los mismos, archivando todas las versiones anteriores por las que han ido pasando los ficheros durante el tiempo de retención establecido en el parámetro DATA_RETENTION_TIME_IN_DAYS parámetro que se puede establecer a nivel base de datos, esquema o tabla.

Este archivado es lo que posibilita las dos funcionalidades avanzadas de Snowflake que se van a ver en este artículo: El Time Travel y el Fail-Safe.

¿Qué es el Time Travel?

El Time Travel es una funcionalidad que permite acceder a versiones históricas por las que han ido pasando los datos en las tablas. Por ejemplo, si tenemos un proceso de carga diaria de una tabla de movimientos contables, podríamos lanzar una consulta de cuál era el estado de los movimientos contables tres días atrás.

¿Qué es el Fail-Safe?

Es un periodo adicional de siete días por el que Snowflake almacena las versiones de los datos para una posible recuperación. Este periodo no es configurable, siempre es de siete días, y únicamente aplica en un tipo de tablas: Las permanentes. 

Los objetos con Fail-Safe son las bases de datos, esquemas y tablas.

¿Qué se puede hacer con el Time Travel?

  • Consultar una foto estática de cualquier momento del pasado hasta un máximo de 90 días. Por ejemplo, de una tabla de movimientos contables, podríamos sacar un balance con los movimientos congelados a una fecha.
  • Recuperar tablas que se hayan borrado accidentalmente de forma muy sencilla mediante un simple comando SQL (UNDROP).
  • Recovery point-in-time: Recuperar datos en un punto concreto, dentro del plazo de los 90 días máximo del time travel.
  • Poder sacar snapshots de los datos para guardarlos permanentemente → Para esto podríamos combinar dos funcionalidades: El time travel y el zero-copy cloning, que veremos más adelante.

¿Cómo utilizar el Fail-Safe?

El Fail-Safe permite recuperar datos hasta siete días máximo después de la expiración del Time Travel. Esta recuperación solamente puede ser hecha a través del equipo de soporte de Snowflake, a diferencia del Time Travel, y se debe hacer vía petición. El Fail-Safe es un mecanismo para poder recuperar datos en caso de emergencia, no está pensado para hacer queries históricas, etc. para eso hay que usar el Time Travel.

No hay un SLA asociado a la recuperación de datos en Fail-Safe: Snoflake habla de horas incluso días para recuperar estos datos.

¿Cómo se configura el Time Travel?

Es un servicio que nos proporciona Snowflake y no hay que hacer nada adicional, más allá de configurar el número de días que queremos que nuestros objetos lo tengan activo. Hay que tener en cuenta lo siguiente:

  • Dependiendo de la edición que tengamos contratada de Snowflake, el número de días permitido de Time Travel puede diferir. A día de hoy, en la edición Standard solamente se puede habilitar hasta un día de Time Travel, mientras que a partir de la edición Enterprise podemos habilitar hasta 90 días de Time Travel.
  • El Time Travel de hasta 90 días solamente está habilitado en las tablas permanentes. Resto de tablas, un día máximo de Time Travel. Si quieres saber más sobre los tipos de tablas, hablamos sobre ellas en nuestro anterior artículo sobre almacenamiento, en la sección DML’s en Snowflake. El parámetro que configura el número de días de Time Travel en las tablas es el DATA_RETENTION_TIME_IN_DAYS. Este valor está por defecto a 1, pero podemos especificar un valor distinto a nivel base de datos o esquema, para que todos los objetos por debajo hereden dicho valor. También es posible configurar un tiempo mínimo de retención a nivel de cuenta, mediante el parámetro MIN_DATA_RETENTION_TIME_IN_DAYS. Este parámetro solamente es configurable por el rol ACCOUNTADMIN, y en caso de tener un valor, el tiempo de retención de una tabla sería el máximo del valor MIN_DATA_RETENTION_TIME_IN_DAYS a nivel cuenta y el DATA_RETENTION_TIME_IN_DAYS de la propia tabla.
  • Si queremos deshabilitar el TIME TRAVEL, simplemente tenemos que establecer un valor cero al parámetro DATA_RETENTION_TIME_IN_DAYS.

¿Cómo se configura el Fail-Safe?

El Fail-Safe no es configurable. Es un periodo fijo de siete días que se activa automáticamente en tablas permanentes sin necesidad de intervención alguna por parte del usuario, una vez que finaliza el periodo de Time Travel, o si se reduce este periodo, y hay datos con antigüedad superior al nuevo periodo definido, los cuales pasarían también automáticamente a Fail-Safe.

Consideraciones a tener en cuenta en el Time Travel y el Fail-Safe

¿Es posible modificar el Time Travel de un objeto?

Sí, es posible, pero hay que tener en cuenta el impacto que tiene dicha modificación:

  • Si se incrementa, la extensión solamente afecta a datos que estén archivados en ese momento, no así a datos que ya hayan pasado a Fail-Safe. Imaginemos que tenemos una tabla con un Time-Travel de 5 días y la modificamos a 10 días, los datos dentro de los 5 días sí se les extendería su periodo a 10, pero los datos con una antigüedad mayor a 5 días que hayan pasado al Fail-Safe, seguirían en el Fail-Safe, incluso si solo ha pasado por ejemplo un día desde que están en el Fail-Safe.
  • Si se disminuye, solamente los datos dentro del nuevo periodo de Time Travel permanecen ahí, mientras que el resto pasa a Fail-Safe. Si reducimos por ejemplo de 20 días a dos días, solamente se mantendrán los datos que se hayan generado en estos últimos dos días, mientras que los datos con antigüedad mayor o igual a 3 días pasan a Fail-Safe.

La modificación del Time Travel de un objeto se hace mediante una sentencia ALTER TABLE, modificando el parámetro DATA_RETENTION_TIME_IN_DAYS al nuevo tiempo en días deseado.

¿Qué pasa cuando el periodo de retención de un contenedor y un objeto chocan y el contenedor es borrado?

El contenedor se refiere a un objeto Snowflake que a su vez contiene 1..n objetos. Dos claros ejemplos son una base de datos, que a su vez contiene 1..n esquemas, y un esquema que a su vez contiene 1..n objetos de esquema tales como tablas, vistas o procedimientos almacenados entre otros.

Cuando una base de datos o esquema tiene definido un periodo de retención, y los objetos hijos tienen definidos un periodo de retención propio, cuando se borra el contenedor padre todo lo que esté contenido se retiene por el periodo definido en el padre, incluso si algunos de los objetos hijo tiene su propio periodo de retención y es diferente al del padre.

Esto quiere decir que si tenemos una base de datos con un periodo de retención de 5 días, y uno de los esquemas contenidos tiene definido un periodo de 10 días, si hay un borrado de la base de datos solamente tendríamos 5 días para recuperar no solo la base de datos sino también cualquiera de los esquemas. Esto aplica también a cuando tenemos un periodo de retención a nivel de objetos, y borramos el esquema que los contiene. En ese caso, el periodo de retención que cuenta siempre es el del esquema.

Si se desea mantener un periodo de retención diferente para alguno de los hijos, estos deben ser borrados previamente a la eliminación del contenedor. Por ejemplo, se borran primero las tablas en las que quiero mantener su periodo propio de retención, y posteriormente se borra el esquema.

Costes del Time Travel y el Fail-Safe

El Time Travel y el Fail Safe aumentan nuestra factura de almacenamiento. Todas las versiones históricas que se vayan archivando de nuestros datos, ocupan un almacenamiento que tendremos que pagar, aunque hay que tener en cuenta que Snowflake, cómo vimos en el artículo de almacenamiento, gestiona esto de la manera más eficiente posible, con lo que si por ejemplo, modificamos datos que afectan a una única micropartición, solo esta micropartición es archivada, pero no archivaría microparticiones no afectadas por la modificación.

Hay que tener cuidado en los siguientes supuestos, que sobre todo en tablas de alto volumen, pueden incrementar considerablemente los costes:

  • Truncados-borrados e inserciones continuos en tablas de alto volumen. Imaginemos que tenemos una tabla de varios gigas, que continuamente borramos y volvemos a cargar. En estos casos, cada vez que hiciéramos esa operación de borrado-inserción, estaríamos archivando varios gigas de tabla, y eso si se multiplica varias veces por el número de días, puede ser importante en la factura.
  • Actualizaciones masivas de datos con frecuencia. Imaginemos que tenemos un proceso que actualiza una columna después de cada inserción. Esto también generaría el archivado de toda la tabla entera.
  • Drops de tablas. Por el mismo motivo que un truncate, esto genera que se archive la tabla completa. Si hacemos continuos drops y recreaciones de la tabla con datos nuevos, una tabla permanente puede disparar los costes de almacenamiento.

Se recomienda para controlar los costes derivados del Time Travel y el Fail-Safe lo siguiente:

  • Si tenemos tablas que son fácilmente reproducibles desde fuera de Snowflake, mejor utilizar tablas transitorias que permanentes. De esta manera, nos ahorraremos los siete días de Fail-Safe y como máximo tendremos un día de Time Travel. Por ejemplo, tablas de lookup, o tablas de apoyo-staging para ciertos procesos ETL’s que no son esenciales. En este último caso, si no es necesario que la tabla persista más allá de la vida de la sesión, se puede configurar incluso como tabla temporal y ahorrar más, ya que en cuanto termina la sesión la tabla desaparece y no se puede recuperar.
  • Las tablas de hechos normalmente deberían ser tablas permanentes, pero si de igual manera las podemos recuperar fácilmente desde el sistema origen en caso de desastre, nos podemos plantear generar algunas como transitorias, y sacar backups periódicos con zero-copy cloning, característica que también se desarrollará en este artículo.

¿Cómo utilizar el Time Travel? Casos de uso prácticos

En nuestro ejemplo, tenemos una tabla donde se carga un stock diario. Lo que hemos hecho, ha sido el día 10 de noviembre cargar el stock de esa fecha, y el día 11 de noviembre hemos machacado el stock del 10 de noviembre por el actual a 11 de noviembre. Fijamos un Time Travel de treinta días a nivel base de datos (que es el que aplicaría por defecto a los objetos por debajo). Pasan 19 días desde la última carga.

Casos de uso que se plantean:

  • Un usuario quiere recuperar mediante una consulta la foto del 10 de noviembre.
  • Por error, uno de nuestros analistas borró la tabla. Es necesario recuperar el stock que teníamos de producto lo más rápido posible.
  • Un usuario nos pide que guardemos una foto del estado del stock a 10 de noviembre, por si nos lo piden en alguna auditoría.
  • Un analista necesita actualizar el stock de un producto concreto en el día 11 de noviembre, pero se equivoca y actualiza todos los productos. Restaurar la tabla al punto de antes del error.

Partimos ya de un stage interno creado en Snowflake donde hemos volcado los ficheros del 10 y el 11 de noviembre, y lanzamos el COPY INTO para insertarlos en la tabla cada día.

Primer caso de uso: Consulta de un estado anterior de la tabla

Si hacemos una consulta sobre la tabla, lo que obtenemos es el stock a día 11 de noviembre:

Para el usuario poder consultar la información a 10 de noviembre en esta tabla, tendría tres opciones:

  • Consulta con un timestamp fijo. Es decir, consultamos la tabla tal cual estaba en un momento específico del tiempo. En nuestro caso, la consultamos a 10 de noviembre:
  • Mediante un offset en segundos. Aquí lo que hacemos es decir que queremos consultar la información al estado de hace 19 días (cuando hacemos la consulta es 29 de noviembre, y queremos los datos del 10 de noviembre). Para ir 19 días hacia atrás, como el offset es en segundos, multiplicamos 60*60*24 (con esto pasamos los segundos a días) y por 19 (que son los días que queremos viajar hacia atrás):
  • Con un ID de query. Ojo con esta opción porque también puede dar problemas. En nuestro caso, cuando la ejecutamos, da el siguiente error:

Nos cercioramos de que ese ID de query sí que existe en el historial completo (Base de datos SNOWFLAKE, esquema ACCOUNT_USAGE, tabla QUERY_HISTORY:

Vemos que el ID es correcto y es justo cuando hicimos el truncate de la tabla para borrar los datos del día 10. El motivo por el que creemos que viene el error es porque el detalle del historial de queries solamente se guarda durante 14 días, con lo cual, este método no es recomendable para lanzar consultas pasado este periodo. Aunque nuestro Time Travel sea mayor (como en este caso, 30 días) el detalle de datos de la query no es accesible.

Segundo caso de uso: Recuperación de una tabla borrada por error

Imaginemos que algún usuario de manera accidental borra del todo la tabla:

drop table stock_diario

Los usuarios empiezan a quejarse que hay aplicaciones que han dejado de funcionar, tardaríamos bastante tiempo en reprocesar el archivo en origen, dependemos de un equipo que nos lo haga…

Snowflake facilita la recuperación de una tabla borrada durante el tiempo del Time Travel con una simple instrucción. Undrop la cual al ser una operación de metadata se ejecuta inmediatamente. No es necesario tener que localizar un backup donde estaba esa tabla ok, restaurarlo, sacar la tabla… simplemente ejecutar esta sentencia.

Demostración a continuación, borramos la tabla:

Ejecutamos una query y nos devuelve el siguiente error:

Ejecutamos la sentencia undrop:

Y vemos que Snowflake nos devuelve el mensaje de que la tabla ha sido correctamente restaurada.

Y comprobamos que podemos volver a hacer queries. Por supuesto, el Time Travel después de la recuperación se mantiene, pudiendo también consultar fotos anteriores de la tabla tal y como vemos en la captura:

Importante a tener en cuenta: El UNDROP siempre restaura la última versión de los datos que hubiese en el momento del borrado.

Tercer caso de uso: Sacar una foto estática de un estado de la tabla

Ya se ha visto que durante el periodo de Time Travel podemos consultar el estado anterior de una tabla. Pero, ¿y si un usuario pidiera guardar el estado de esa tabla de forma permanente? Este caso de uso es frecuente en el mundo financiero y de la auditoría para cosas tales como poder sacar un estado de cuentas con los movimientos a una determinada fecha, o que un regulador nos pida sacar instantáneas de los datos a determinados momentos para una consulta posterior.

La opción más inmediata para satisfacer este requerimiento sería combinar las funcionalidades de zero-copy cloning y time travel. Las ventajas que nos ofrece esta opción sería:

  • No duplicamos almacenamiento por la instantánea. Durante el tiempo de Time Travel, tenemos un único fichero, y nuestro clon apuntaría a esa versión de los datos. Cuando el Time Travel expire, Snowflake sabrá que hay un clon apuntando a esos datos y por tanto no los borrará. Si lo hiciésemos insertando los datos en una nueva tabla, durante el Time Travel de esa versión de los datos se estaría duplicando el almacenamiento.
  • Creamos todo en una simple sentencia.

A continuación se muestra el clonado de nuestra tabla de stock con la foto del 10 de noviembre:

Imaginemos que pasa el time travel de esta tabla. Podemos simularlo haciendo un ALTER TABLE y poniendo la tabla a 10 días (han pasado más de 10 días desde la última modificación):

Si se intenta sacar la foto a 10 de Noviembre desde la tabla original, Snowflake devuelve el siguiente error:

Ya que ese estado de los datos tenían una antigüedad mayor a 10 días, Snowflake lo ha llevado directamente a Fail-Safe.

Si consultamos el clon que se acaba de generar:

Se ve que a pesar de que el Time Travel ha expirado, mantenemos la foto del 10 de noviembre, y esta foto persistirá salvo que borremos el clon.

Cuarto caso de uso: Restaurar la tabla a un estado anterior

Imaginemos que le piden a un usuario actualizar el stock de impresoras de 15 a 14 unidades. Para ello el usuario genera la siguiente consulta:

El usuario se ha olvidado de un pequeño detalle y es aplicar un where para únicamente actualizar la línea de las impresoras, con lo que ahora todo el stock está a 14 unidades de forma errónea.

Para recuperar la tabla, podríamos recrearla gracias al Time Travel, mediante una sentencia create or replace:

Lo que estamos haciendo es sustituir la tabla al estado al que estaba ayer (que es el correcto).

IMPORTANTE: Hay que tener en cuenta que cuando hacemos un REPLACE TABLE como en este caso, se genera una nueva tabla con una metadata limpia, con lo cual perdemos el Time Travel en esa tabla. Si por ejemplo, intentamos recuperar la información 5 minutos atrás, nos dirá que no hay Time Travel de ese momento:

Cuando hagamos estas restauraciones debemos estar muy seguros. Una opción recomendable sería antes de machacar la tabla original, hacer el replace en una tabla nueva y revisar que todo esté ok.

Conclusiones

El Time Travel y el Fail-Safe son dos funcionalidades que nos proporciona Snowflake sin tener que mantener ni configurar prácticamente nada, y que cubren gran cantidad de casos de uso cómo consultas de histórico, recuperación rápida en caso de error o problema y la posibilidad de sacar instantáneas a un momento determinado en combinación con el zero-copy cloning.

Es importante tener muy claro los tiempos de retención de cada una de las bases de datos-esquemas tablas, y seleccionar el tipo de tabla adecuado en consecuencia, para optimizar al máximo el coste de almacenamiento.

Navegación

Introducción

¿Qué es el Time Travel?

¿Qué es el Fail-Safe?

¿Qué se puede hacer con el Time Travel?

¿Cómo utilizar el Fail-Safe?

¿Cómo se configura el Time Travel?

¿Cómo se configura el Fail-Safe?

Consideraciones a tener en cuenta en el Time Travel y el Fail-Safe

Costes del Time Travel y el Fail-Safe

¿Cómo utilizar el Time Travel? Casos de uso prácticos

Principales 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

Senior Data Architect

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

El futuro del Cloud y GenIA en el Next ’23

septiembre 19, 2023
LEER MÁS

Big Data e IoT

febrero 10, 2021
LEER MÁS

Databricks sobre Azure – Una perspectiva de Arquitectura (parte 1)

febrero 15, 2022
LEER MÁS

Domina los Costos en la Nube: Optimización de GCS y BigQuery en Google Cloud

marzo 17, 2025
LEER MÁS

Bluetab se certifica como AWS Well Architected Partner Program

octubre 19, 2020
LEER MÁS

Potencia Tu Negocio con GenAI y GCP: Simple y para Todos

marzo 27, 2024
LEER MÁS

Publicado en: Blog, Practices, Tech

Guía avanzada sobre almacenamiento en Snowflake

octubre 3, 2022 by Bluetab

Guía avanzada sobre almacenamiento en Snowflake

Roberto García Parra

Technical Delivery Manager

Introducción a Snowflake

Snowflake es una plataforma avanzada de datos que se consume en modalidad SaaS 100% en cloud. El principal factor diferenciador de Snowflake es que proporciona capacidades avanzadas para todas las necesidades de datos de las compañías (Almacenamiento, procesamiento, explotación y soluciones de analítica avanzada) de una manera más flexible y sencilla que las soluciones de Datawarehouse tradicionales. 

El motor de queries y procesamiento de Snowflake está basado 100% en SQL para facilitar el acceso a la mayoría de los profesionales de datos, aunque Snowflake está haciendo esfuerzos por ampliar las posibilidades de desarrollo (Por ejemplo, recientemente ha sacado Snowpark, una API que permite a los desarrolladores que estén habituados a trabajar con Spark tanto en Scala cómo en Java y recientemente en Python, a poder migrar sus códigos de forma sencilla a Snowflake). Además, dispone de conectores nativos con una serie de partners que abarca todas las fases de la ingeniería de datos, cómo por ejemplo partners de integración de datos tan importantes cómo Matillion, Informatica, DBT o DataStage; de Business Intelligence cómo Domo, Cognos o Looker; o de Machine Learning cómo Alteryx, Dataiku o AWS Sagemaker.

La otra ventaja diferenciadora de Snowflake es que tiene unas capacidades de optimización que no requieren apenas de mantenimiento y cubren un abanico muy amplio de casos de uso, entre las que se podrían destacar la clusterización automática, el cacheo y el search optimization service, elementos en los que ahondaremos en detalle en futuros artículos, ya que en éste nos vamos a centrar sobre todo en las capacidades de almacenamiento.

Principales características diferenciadoras de Snowflake:

  • Pone al alcance de los usuarios funcionalidades avanzadas que se gestionan de forma sencilla, abstrayendo a los usuarios de lo que se maneja por debajo.
  • Multi-cloud: Se puede desplegar en cualquiera de los tres clouds más importantes (Amazon, Azure y Google) e incluso permite implementar una estrategia multi-cloud dónde la mayoría de la administración y operación corre por cuenta de Snowflake.
  • No hay que mantener ni hardware ni software. Todo gestionado por Snowflake y sin pérdida de servicio.
  • Gestión sencilla de las unidades de procesamiento (Llamadas Virtual Warehouses). Es muy sencillo subir o bajar la talla del procesamiento (a golpe de click o una sencilla sentencia SQL), y los cluster se pueden configurar para que se bajen automáticamente tras un tiempo de inactividad, y vuelvan a levantarse de forma rápida cuándo entre una nueva petición (en menos de un segundo la mayor de las veces). Dado que una de las variables que marcan el coste es el tiempo de actividad de un warehouse, esto permite eficientar los costes, sin tener que preocuparnos de estar bajando-levantando instancias en función del uso de la plataforma.

La arquitectura de Snowflake está basada en tres principales capas:

  1. La capa de almacenamiento, que es en la que nos centraremos en este artículo. Esta capa basada en microparticiones es la base de algunas de las funcionalidades más disruptivas de Snowflake cómo por ejemplo el Zero-copy cloning o el Time-to-Travel, que veremos también en futuros artículos.
  2. Capa de procesamiento.
  3. Cloud Services, que es la capa con la que se interactúa con Snowflake y es el cerebro que gestiona y coordina el resto de capas y componentes.

Objetivo del artículo

Vamos a entender en profundidad cómo funciona Snowflake en la capa de almacenamiento. A grandes líneas, veremos:

  • Cómo se almacenan, distribuyen y comprimen los datos.
  • La importancia de los metadatos a la hora de escanear de forma eficiente el almacenamiento cuándo se hace tanto una consulta, cómo una operación DML de inserción, actualización o borrado.
  • Cómo es este proceso de búsqueda en los datos, para reducir al máximo el número de bytes a escanear (y por tanto, la reducción en los tiempos de consulta).

Esto será la base para entender varias de las funcionalidades diferenciales que ofrece Snowflake:

  • A nivel rendimiento: Clustering, caching, search optimization service y query acceleration service (Recientemente liberada). Estos servicios-funcionalidades ayudan a optimizar diferentes casos de uso dónde lo proporcionado por el almacenamiento no sea suficiente para obtener el rendimiento deseado.
  • Data Sharing, sin necesidad de replicar los datos físicamente.
  • Resiliencia: Zero-copy cloning, Time Travel y Fail Safe.

Introducción al almacenamiento

El almacenamiento en Snowflake se basa en la generación de ficheros comprimidos con un tamaño máximo aproximado de 16MB y que se almacenan en un repositorio orientado a objetos tipo el S3 de AWS. Estos ficheros son inmutables, y cualquier operación de inserción-borrado-actualización siempre se hace generando un nuevo fichero de datos y actualizando los metadatos para saber cuáles son los ficheros que están activos en cada momento, además de otros metadatos que veremos más adelante en profundidad para eficientar la cantidad de bytes escaneados a la hora de ejecutar una query.

Objetivos del almacenamiento Snowflake

La forma en la que almacena los datos Snowflake está enfocada a dos objetivos principales:

  • Optimizar el rendimiento de las consultas, con una combinación de organización automática de los datos, almacenamiento columnar y el mantenimiento de una metadata.
  • Posibilitar varias de las características diferenciales que tiene Snowflake frente a otros Datawarehouse tradicionales, cómo por ejemplo:
    • Zero-copy cloning.
    • Time Travel.
    • Data Sharing sin necesidad de replicar el dato físicamente.

Principales características del almacenamiento en Snowflake

Compresión columnar: Snowflake analiza y comprime automáticamente los datos durante la carga de la tabla, agrupándolos por columnas. En función del tipo de datos de cada una de las columnas, selecciona el esquema de compresión más óptimo para cada una de ellas: Cada columna puede tener su propio esquema de compresión y aumentar-reducir de forma independiente. Gracias a esta eficiencia en la compresión, se obtiene una mejora significativa en los rendimientos al reducir la cantidad de datos a escanear, además de un ahorro en costes de almacenamiento, ya que Snowflake factura por la cantidad almacenada ya comprimida.

Microparticiones: Son unidades de almacenamiento contiguo en las que Snowflake va almacenando los datos en el orden de la ingesta. A diferencia de otros motores de bases de datos, en Snowflake no es necesario declarar una forma de particionar los datos por una o más columnas, sino que él ya lo hace de manera automática de la siguiente forma: Por un lado, va insertando los datos según le llegan en bloques de almacenamiento que oscilan entre los 50 y los 500MB antes de compresión (16MB aprox comprimidos). Cuándo se llena un bloque, pasa al siguiente, y así sucesivamente hasta que todos los datos son insertados. Snowflake también encripta tanto en tránsito cómo en destino todos los datos.

Cada una de estas particiones son inmutables: en el caso en el que haya una actualización en alguna de las microparticiones, lo que se hace es crear una nueva versión de la misma, y se mantienen las versiones antiguas por el tiempo parametrizado en el time travel (propiedad DATA_RETENTION_TIME_IN_DAYS en la tabla Snowflake). La inmutabilidad permite cosas cómo por ejemplo poder acceder a versiones de los datos en diferentes momentos del tiempo o hacer clonados de tablas sin tener que replicar los datos.

Metadatos en las microparticiones Snowflake

Para cada micropartición, Snowflake genera una metadata con la siguiente información:

A nivel columna

  • El rango de valores para cada una de las columnas de la micropartición.
  • Valores mínimo y máximo.
  • Conteo de valores diferentes.
  • Conteo de nulos.

A nivel tabla

  • Tamaño de tabla (en bytes).
  • Referencias de archivos y extensiones de tabla.
  • Conteo de filas.
  • Otras propiedades adicionales usadas tanto para la optimización cómo para el procesamiento de las queries.

Principales características del microparticionamiento de Snowflake

  • Automático y transparente para el usuario: A diferencia de otros sistemas tradicionales, no hay que declarar previamente un campo de partición, ni hacer un mantenimiento posterior.
  • Asegura la eficiencia en el podado tanto en las consultas, cómo en las operaciones DML.
  • Todas las particiones tienen un tamaño similar: En otros sistemas, el tamaño de las particiones depende del campo elegido, y puede haber un claro desbalance de particiones en función del número de ocurrencias que tenga cada valor del campo particionado (Hot partition Keys). El trade-off para tener estos tamaños similares es que pueden solaparse valores: Un determinado valor de columna (por ejemplo una fecha) puede estar en más de una micropartición. Cuánto mayor es el solapamiento en las particiones de un valor, menor será el podado, ya que habrá que recorrer más particiones para filtrar los valores correctos en una búsqueda.
  • Según Snowflake, este método de particionado automático sería suficiente para tablas con tamaños de hasta 1TB sin tener que plantearse otras opciones cómo por ejemplo el clusterizado.
  • En campos secuenciales cómo fechas o numéricos es dónde más vemos que se puede obtener un beneficio en esta forma de particionar, ya que si la inserción de los datos está ordenada por dichos campos, el podado (pruning) será altamente eficiente, y en consecuencia la cantidad de datos a escanear y la rapidez en la resolución de las queries.
  • El almacenamiento columnar permite que Snowflake solamente escanee aquellas columnas incluídas en la consulta. De ahí que sea importante incluir solamente las columnas que realmente necesitemos y evitar queries del tipo SELECT * si no es necesario consultar todas las columnas.

Entendiendo la organización de datos en Snowflake

Partiendo de los siguientes datos de ejemplo:

Ordenados por fecha. Al insertarlos en Snowflake, para ilustrar este ejemplo se supone que se generan dos microparticiones, que se van llenando en el orden en el que entran los datos:

Si por ejemplo, hacemos la siguiente query:

Select Fecha, sum(importe)

From ventas

Where fecha = ‘01/01/2022’

Snowflake recorrería los siguientes datos:

  • Primero se podan las microparticiones que no estén en el rango. En este caso, cómo estamos buscando el 1 de Enero, ignorará la segunda micropartición.
  • Dentro de la primera micropartición, dado que en la query solamente se están seleccionando las columnas fecha e importe de venta, no recorre la parte de los datos del cliente. Esto es posible gracias al almacenamiento columnar.

Si se buscan las ventas de un cliente específico:

Select sum(importe)

From ventas

Where cliente = ‘C2’

En este ejemplo, recorre las dos microparticiones, ya que C2 está dentro del rango de valores de ambas, aunque realmente C2 no está en la micropartición 1. Esto es lo que se comentaba en el apartado anterior de la posible dependencia que puede haber en la búsqueda de rangos en cada micropartición de cómo están distribuidos los datos.

DML’s en Snowflake

Para ver cómo funcionan las principales operaciones de DML en Snowflake, hemos reproducido el siguiente experimento: Creamos una nueva tabla, partiendo de una tabla origen que tiene las ventas de varios días de 60 call centers, seleccionando solamente los Call Center 1 y 20. Lo que haremos será operaciones atómicas de inserción, actualización y borrado para ver cómo se gestionan tanto los datos cómo los metadatos.

  • Inserción: Para comprobar cómo funciona la inserción insertamos dos nuevos registros con Call Center que no existen: El 10 y el 11.
    Los ficheros que componen las microparticiones son inmutables, por lo que Snowflake en la inserción puede ejecutar dos posibles acciones:
    • Crear un nuevo fichero con los registros existentes más el nuevo, y archivar el antiguo.
    • Crear una nueva partición para ese dato.
  • Actualización: Las acciones que realiza Snowflake para ejecutar una actualización son:
    • Identificar las microparticiones afectadas por la actualización.
    • Generar nuevos ficheros de micropartición que incluyan las modificaciones.
    • Archivar las versiones anteriores de los ficheros durante el tiempo marcado por el DATA_RETENTION_TIME_IN_DAYS.

Para verificar esto, partiendo del ejemplo anterior hemos lanzado una consulta que actualice los call center 10 y 11 a 15 por ejemplo. Comprobamos que efectivamente Snowflake solamente recorre esa partición, y genera un nuevo fichero con los nuevos valores, archivando el anterior:

Si se actualiza alguno de los otros dos call center, el número de particiones recorridas sería mayor, lo cuál implica que el coste de las operaciones DML también se ve afectado por la manera en que estén organizados los datos.

  • Borrado: Snowflake procede de manera similar a la actualización:
    • Identifica las microparticiones afectadas por el borrado.
    • Genera nuevos ficheros de micropartición dónde no aparezcan los registros eliminados.
    • Archiva las versiones anteriores de los ficheros durante el tiempo marcado por el DATA_RETENTION_TIME_IN_DAYS.

La importancia de entender cómo gestiona Snowflake estas operaciones es por las implicaciones que tiene a nivel rendimiento y almacenamiento. Sobre todo en el segundo caso, hay que tener en cuenta que si tenemos un alto número de días de retención en tablas (DATA_RETENTION_TIME_IN_DAYS) que se modifican frecuentemente, estaremos archivando muchas versiones de los datos que pueden incrementar considerablemente nuestro almacenamiento.

La principal ventaja es que Snowflake se encarga de todo este complejo mantenimiento siendo la gestión del almacenamiento transparente para el usuario.

En estos casos, para eficientar el almacenamiento es fundamental conocer los tres tipos principales de tablas que pone a nuestra disposición Snowflake, así cómo el concepto de Fail-Safe y Time-Travel:

Time-Travel: Periodo que, en función de la edición de Snowflake, (hasta un día en Standard y hasta 90 días en tablas permanentes a partir de edición Enterprise) permite almacenar todas las versiones por las que pasa una tabla, y habilita funcionalidades cómo poder restaurar datos en cualquier punto dentro de ese periodo, o hacer queries sobre un estado específico de los datos.

Fail-Safe: período de siete días durante el cuál se almacena cada versión de los datos en la que ha expirado su DATA_RETENTION_TIME_IN_DAYS y que permite la restauración de los mismos durante ese periodo pero solamente a través del soporte de Snowflake (Los usuarios no tienen acceso directo al Fail-Safe). Este periodo no es configurable y solamente está disponible en las tablas permanentes, cómo veremos a continuación.

Con estos dos conceptos claros, pasamos a describir los tres tipos principales de tablas en Snowflake:

  • Temporales: Solamente persisten durante la sesión, y no tienen Fail-Safe. Se puede definir Time-Travel de cero o 1 día.
  • Transitorias: A diferencia de las temporales, sí pueden persistir más allá de la sesión, pero solo permiten tener Time-Travel de hasta un día y tampoco incorporan Fail-Safe.
  • Permanentes: Igual que las transitorias, persisten más allá de una única sesión, pero permiten extender el Time-Travel hasta 90 días (siempre y cuándo se esté trabajando en una edición Enterprise o superior) e incorporan de caja el Fail-Safe (No configurable ni removible).

Por la naturaleza de cada una de las tablas, vemos que por ejemplo debemos tener en cuenta que si nuestra tabla se puede ver afectada por continuas operaciones DML de actualización-inserción, en el caso que tengamos una tabla permanente con un alto número de días de Time-Travel, nuestros costes de almacenamiento pueden verse incrementados.

La recomendación general para optimizar el almacenamiento es que se utilicen tablas temporales para tablas que simplemente utilicemos cómo tablas intermedias o staging, las transitorias para tablas permanentes que puedan ser fácilmente reproducibles desde fuera, y las permanentes para tablas críticas que tengan que estar siempre disponibles y que el coste de reprocesamiento en caso de desastre sería elevado.

Aspectos a tener en cuenta respecto al almacenamiento

  • Consultas por columnas no ordenadas en la inserción: Esta forma de particionar proporcional implica que haya solapes de valores en las diferentes microparticiones. En columnas de baja cardinalidad (por ejemplo con 2-3 valores diferentes) si los datos no están ordenados por esa columna y hacemos un filtro exclusivamente por dicha columna, hay que controlar el nivel de podado de microparticiones, porque puede pasar que esos 2-3 valores se encuentren en todas las particiones y que Snowflake no pueda podar ninguna. En estos casos, se recomienda para solucionarlo bien añadir al filtro un campo tipo fecha o numérico por el que estén ordenados los datos, o plantear la posibilidad de añadir una cluster key por dicho campo, que es uno de los servicios de optimización con los que cuenta Snowflake. Otra opción sería crear una vista tanto standard cómo materializada que ordene por ese campo.

    Ejemplo dónde queda evidenciado esto, es, lanzamos una consulta sobre una gran tabla de unos 14.000 millones de filas, cuyos datos están ordenados por fecha y cliente. En esta tabla, queremos consultar los diferentes tipos de envío que se han hecho. Si lanzamos la consulta sin filtro:

Primero vemos que se escanean las 49.448 microparticiones, lo cuál es lógico ya que no hemos incluído filtro alguno. Por otro lado, se escanean 13,58GB de los 770GB que tiene la tabla. Esto se debe a que en la query hemos incluído una única columna, y ya que Snowflake cómo hemos comentado almacena los datos de forma columnar y comprimida, solamente accede a los datos de la columna que consultamos.

Si aplicamos un filtro sobre la columna Call Center, que es un numérico que toma valores entre 1 y 60, y es un campo por el que no se ha ordenado en la inserción de los datos, y buscamos por ejemplo el call center número 20:

select distinct cr_ship_mode_sk from «SNOWFLAKE_SAMPLE_DATA».»TPCDS_SF100TCL».»CATALOG_RETURNS» where cr_call_center_sk = 20 

Vemos que efectivamente, apenas se han podado valores: De las 49,448 microparticiones, 49.447 tenían en su rango de call center el 20, con lo cuál ha habido que recorrerlas igualmente.

Sin embargo, si incluímos en el filtro uno de los campos de clusterizado, por ejemplo el código de cliente:

Vemos que sólo se ha recorrido un 10% aprox de las microparticiones, y el tiempo de query ha bajado de 1 minuto 45 segundos a 12 segundos. 

Con esto se puede concluir que el principal factor de rendimiento en las consultas es el número de bytes que tenga que escanear Snowflake el cuál viene principalmente determinado por el número de particiones a escanear, y la cantidad de datos de cada columna, y que si solamente incluimos en el filtro columnas por las que no estén ordenados los datos o no estén incluídos en la cluster key, en tablas de gran tamaño el rendimiento puede verse afectado. Es recomendable incluir en los filtros al menos uno de los campos de ordenación o de las cluster key para que las queries sean eficientes, o de no poder ser así, Snowflake nos proporciona otras alternativas para mejorar el rendimiento cómo las vistas materializadas, el cacheo o el search optimization service.

  • Búsqueda por rangos en las microparticiones: A la hora de podar microparticiones, Snowflake busca en la metadata si el valor buscado está en el rango de valores mínimo-máximo de la columna filtrada en la micropartición. Esto genera una dependencia a la hora de podar valores en base a cómo estén distribuidos dichos rangos en las microparticiones, lo cuál puede afectar a la cantidad de microparticiones podadas cuándo buscamos por columnas por las que no estén ordenados o clusterizados los datos: Por ejemplo, nos podemos encontrar casos dónde busquemos un valor que no existe, pero que por estar dentro del rango de valores en la metadata, obligue a Snowflake a recorrer igualmente todas las microparticiones.

En estos casos, Snowflake dice que en tablas con tamaños por debajo de 1TB la organización automática de datos debe ser suficiente para obtener buen rendimiento en las consultas.

Pruebas con Snowflake para entender cómo funciona el microparticionado y los metadatos asociados a las microparticiones

La tabla que se ha utilizado para estas pruebas contiene 100 millones de registros y seis columnas, dónde los datos se han distribuido en 49 particiones ocupando un total de 708MB (unos 14,5MB de media por micropartición). Los datos están ordenados por un campo de fecha.

Comentar que para estas pruebas, se ha utilizado la herramienta de Profiling de Snowflake, que está disponible desde el historial de queries. Hemos encontrado esta herramienta muy completa e intuitiva, y permite de un solo vistazo encontrar dónde se están generando los cuellos de botella en las queries, todo el plan de ejecución por el que pasa una query, así cómo las filas que salen de cada paso (lo cuál nos permite por ejemplo detectar cosas habituales de mal rendimiento cómo joins explosivos) y las microparticiones que se van podando en cada estado. Gracias a esta herramienta, hemos podido entender qué es lo que pasaba exactamente en cada una de las situaciones que hemos querido investigar y entender la gestión de Snowflake del almacenamiento.

Esta herramienta de profiling está disponible en el menú History de la UI, pinchando en la query que queramos analizar.

El objetivo de estas pruebas es entender la forma en la que Snowflake selecciona las microparticiones a recorrer y cómo de importante es la forma en la que se insertan los datos para mejorar el rendimiento en nuestras consultas, así cómo las columnas por las que se filtre.

En la tabla existe una columna, Call Center, dónde hay diferentes valores entre el 1 y el 60 pero con saltos (no están todos los posibles valores). Si hacemos una búsqueda por un call center específico de los que están:

Apreciamos que sea cuál sea el Call Center que incluyamos en el filtro siempre se recorren todas las microparticiones. La explicación es que Snowflake para determinar las microparticiones a recorrer, mira en la metadata de la columna Call Center si el valor buscado está dentro del rango, y en este caso, dónde los datos están ordenados por fecha, siempre se cumple que el valor está dentro del rango, por lo que tiene que recorrer todas las microparticiones.

Probamos a meter un nuevo registro de un Call Center con ID 11 que se sabe no aparece en los datos. Tras la inserción, el número de microparticiones se mantiene en 49, por lo que Snowflake ha debido generar un nuevo archivo que incluye el nuevo registro, y ha archivado la versión anterior de la micropartición.

Hacemos una búsqueda por ese Call Center, que a priori está en una única micropartición, y al revisar el Profile:

Se aprecia que Snowflake ha tenido que escanear las 49 microparticiones aunque se sabe que el valor 11 está en una micropartición específica. Esto confirma que Snowflake busca en base a rangos de valores por columna, y no conoce los valores específicos de una columna que hay en cada micropartición.

Para evidenciar aún más este hecho, insertamos un nuevo registro de Call Center que esté fuera del posible rango de búsqueda: Call Center con ID 61. Tras la inserción, verificamos que el número de particiones se mantiene, pero cuando se hace una búsqueda por ese valor:

Únicamente ha escaneado una micropartición. Esto se debe a que el 61 es un valor que está fuera del rango de la metadata del resto de las microparticiones, con lo cuál, ha podido saber que el Call Center 61 estaba en una única micropartición.

La siguiente comprobación es ver cómo Snowflake ejecuta la búsqueda de un valor de la columna Call Center que no está en los datos, pero sí en los posibles rangos de valores de la columna en las microparticiones. Por ejemplo, tenemos Call Centers 10, 11 y 13, pero no el 12. Si buscamos por el 12:

Cómo era de esperar, recorre todas las microparticiones, ya que el 12 entra en todos los posibles rangos de valores.

Para terminar de confirmar si Snowflake busca exclusivamente por rangos de valores, se crea una nueva tabla únicamente con los Call Center 1, 10 y 11. Esta nueva tabla tiene 8 microparticiones.

Si buscamos por el Call Center 5 (dentro de rango), recorre las 8 microparticiones aunque el Call Center no exista.

Si buscamos por el Call Center 12, directamente la metadata devuelve que ese Call Center no existe, y por tanto, no recorre ninguna micropartición.

Pero ahora, si buscamos por el valor 11, que recordemos fue una nueva inserción que metimos y justo está en el final del rango, en este caso Snowflake sí es capaz de podar el resto de microparticiones dónde no está el valor:

El motivo está en que se sabe que el resto de microparticiones tienen un rango 1-10, con lo cuál, la única que cumple estar en rango 1-11 es dónde verdaderamente está el valor. Sin embargo, en la otra tabla dónde era altamente probable que todas las microparticiones en la columna Call Center estuviesen en rango 1-60, ahí sí que tuvo que recorrerlas todas para saber dónde estaba el Call Center 11.

Conclusión de las pruebas:

Cuándo tengamos bajo rendimiento en consultas, hay dos indicadores principales a revisar en el profiling: Número de particiones escaneadas y cantidad de datos procesados.

Para mejorar la consulta, el objetivo es reducir el número de ambas: Para recorrer menos particiones hay que añadir filtros por campos en base a los cuáles se estén ordenando los datos (generalmente fechas o id’s numéricos) o replantearnos si ese campo es importante a la hora de filtrar, que los datos estén ordenados por dicho campo. Por supuesto, revisar también si las columnas que utilizamos en la consulta se pueden reducir. 

Si esto no es posible, tendríamos que plantearnos otras estrategias de optimización, cómo clusterizar la tabla en base a ese campo, utilización de cachés, ver si el caso de uso se ajusta a la utilización del search optimization service, o la utilización de vistas materializadas que pueden a su vez estar clusterizadas o no. El detalle de estas estrategias queda fuera del alcance de este artículo.

Principales conclusiones del funcionamiento del almacenamiento en Snowflake

  • El orden de inserción de los datos importa. Es recomendable insertar los datos ordenadamente en base a los filtrados más frecuentes que se vayan a hacer en la explotación.
  • Al almacenar de forma columnar los datos, el solamente seleccionar las columnas necesarias para la consulta reduce el número de bytes escaneados y por tanto el tiempo de resolución de consulta. Es recomendable evitar los SELECT * o añadir columnas innecesarias en las queries.
  • Es muy importante de cara al rendimiento seleccionar el tipo de datos más adecuado para cada columna, ya que Snowflake podrá reducir de manera más eficiente el tamaño de los datos, y esto se traduce en menores tiempos de escaneo, y por tanto de respuestas en las queries.
  • Para que las queries tengan un buen rendimiento, es aconsejable incluir un filtro de la columna por la que estén ordenados-clusterizados los datos y revisar en el profile de la query que tenga un buen porcentaje de poda de particiones.
  • En columnas de cardinalidad muy baja (1-10 valores diferentes), si hacemos búsquedas exclusivamente por ellas, y los datos no están ordenados o clusterizados por estas columnas, puede que no se poden particiones en las búsquedas. Con volúmenes de GB, el recorrer todas las particiones incluso con la talla más pequeña no perjudica el rendimiento y Snowflake maneja perfectamente, pero en volúmenes en el rango de centenas de GB, la diferencia entre tener o no la cluster key para buscar un valor en concreto, sí puede afectar en el número de bytes a escanear y por tanto en los tiempos de respuesta, con lo cuál es importante hacer un estudio de tiempos de consulta, para lo cuál Snowflake nos proporciona una potente herramienta de profiling, que a nosotros particularmente nos ha sido de gran utilidad para poder elaborar este artículo.

Entendiendo cómo Snowflake gestiona el almacenamiento a nivel inserción, actualización y borrado de datos y cómo se gestionan estos datos a la hora de realizar consultas, estaríamos en disposición de dar el siguiente paso que es entender todas las funciones avanzadas que proporciona Snowflake a nivel de optimización, compartición y seguridad-resiliencia en los datos. Éste será el objetivo de siguientes artículos.

Referencias

Documentación oficial de Snowflake https://docs.snowflake.com/en/

Navegación

Introducción

Objetivo

Introducción al almacenamiento

Objetivos del almacenamiento

Principales características del almacenamiento

Metadatos en las microparticiones

Principales características del microparticionamiento

Entendiendo la organización de datos

DML’s en Snowflake

Aspectos a tener en cuenta respecto al almacenamiento

Pruebas con Snowflake

Principales conclusiones

Referencias

Autores

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

Roberto García Parra

Technical Delivery Manager

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Los Incentivos y el Desarrollo de Negocio en las Telecomunicaciones

octubre 9, 2020
LEER MÁS

Bluetab se incorporará a IBM

julio 9, 2021
LEER MÁS

LakeHouse Streaming en AWS con Apache Flink y Hudi

abril 11, 2023
LEER MÁS

Cambios de liderazgo en Bluetab EMEA

abril 3, 2024
LEER MÁS

Hashicorp Boundary

diciembre 3, 2020
LEER MÁS

Gobierno de Datos: ¿tendencia o necesidad?

octubre 13, 2022
LEER MÁS

Publicado en: Blog, Practices, Tech

Databricks sobre Azure – Una perspectiva de Arquitectura (parte 2)

marzo 24, 2022 by Bluetab

Databricks sobre Azure - Una perspectiva de arquitectura (parte 2)

Francisco Linaje

AWS Solutions Architect

Gabriel Gallardo Ruiz

Senior Data Architect

En esta segunda entrega nos centraremos en analizar los diferentes servicios que ofrece Databricks para asegurar el escalado de nuestros servicios y la recuperación ante fallas del sistema, así como otros aspectos relativos a la seguridad como encriptación de los datos tanto reposo como en tránsito.

Primera entrega (link):

  • Arquitectura alto nivel
  • Planes y tipos de carga de trabajo
  • Networking
  • Identidad y Gestión de accesos

Segunda entrega:

  • Disaster Recovery
  • Escalabilidad
  • Seguridad
  • Logging y monitorización

Glosario

  • All Purpose Compute: Diseñado para entornos colaborativos en los que se recurra de forma simultánea al clúster por parte de Data Engineers y Data Scientist
  • Azure Data Lake: Permite almacenar múltiples formatos de datos en un mismo lugar para su explotación y análisis, actualmente Azure dispone la versión Gen2 .
  • Azure Key Vault: Servicio administrado de Azure que permite el almacenamiento seguro de secretos.
  • Azure Virtual Network (VNET): Red virtual aislada lógicamente en Azure.
  • DBFS (Databricks File Systen): Sistema de archivos de Databricks que se monta sobre los sistema de archivos distribuido de los Cloud Providers.
  • Data Lake: Paradigma de almacenamiento distribuido de datos provenientes de multitud de fuentes y formatos, estructurados, semi estructurados y sin estructurar.
  • Identity Provider (IdP): Entidad que mantiene la información de identidad de los individuos dentro de una organización.
  • Infraestructura como código o IaC: gestión y aprovisionamiento de la infraestructura a partir de código declarativo.
  • Jobs Compute: Enfocado a procesos orquestados mediante pipelines gestionados por data engineers que puedan conllevar autoescalado en ciertas tareas
  • Jobs Light Compute: Diseñado para procesos cuya consecución no sea crítica y no conlleve una carga computacional muy elevada
  • Network Security Group o NSG: Especifican las reglas que regulan el tráfico de entrada y salida de la red y los clusters en Azure
  • Private Link: Permite el acceso privado (IP privada) a Azure PaaS a través de tu VNET, de la misma forma que los service endpoints el tráfico se enruta a través del backbone de Azure.
  • SQL Compute: Cluster reservados a queries para la visualización de la información almacenada en el Data Lake
  • Secret scope: Colección de secretos identificados por un nombre.
  • Secure Cluster Connectivity (SCC):  Comunicación a través de túnel inverso SSH entre Control Plane y cluster. Permite no tener puertos abiertos ni IPs públicas en las instancias.
  • Security Assertion Markup Language (SAML): Estándar abierto utilizado para la autenticación. Basado en XML, las aplicaciones web utilizan SAML para transferir datos de autenticación entre dos entidades, el Identity Provider y el servicio en cuestión.
  • Service endpoints: Componente de red que permite conectar una VNET con los diferentes servicios dentro de Azure a través de la propia red de Azure.
  • TLS/ TLS1.2 (Transport Layer Security): es un protocolo de cifrado y comunicación que proporciona comunicaciones seguras por una red, comúnmente Internet.
  • Workspace: Entorno compartido para acceder a todos los activos de Databricks. En este se organizan los diferentes objetos (notebooks, librerias, etc…) en carpetas y se administran los accesos a recursos computacionales como clusters y jobs.

Disaster Recovery

Entendemos por Disaster Recovery al conjunto de políticas, herramientas y procedimientos que permiten la recuperación de la infraestructura cuando el sistema en su conjunto cae, como por ejemplo una caída de una región de Azure.

No debemos confundir estas políticas y herramientas con las empleadas en materia de alta disponibilidad de nuestro sistema (mínimo nivel de servicios).

Para ello, cuando implementamos una solución en la nube, una de las principales preguntas que debemos plantearnos a la hora de diseñar e implementar nuestra solución es:

  • ¿Qué piezas son críticas en nuestro sistema?
  • ¿Qué daños pueden provocar en el servicio?
  • ¿Cómo puede el sistema adaptarse y recuperarse ante estos errores?

Dar respuesta a estas preguntas es de vital importancia si deseamos que nuestra solución pueda cumplir adecuadamente el estándar de calidad que hayamos planteado.

Para este punto debemos analizar en que ámbito de nuestra solución opera Databricks y que herramientas o pautas debemos seguir para que la plataforma pueda cumplir con su servicio.

Debemos recordar que Databricks ofrece soluciones en materia de transformación y almacenamiento de datos tanto batch como en streaming, utilizando Azure Blob storage como capa de persistencia de datos no estructurados, como asimismo diferentes herramientas relacionadas con orquestación de jobs o análisis ad-hoc de datos vía SQL como servicio de analitica. Por lo tanto en este punto veremos que diferentes herramientas pueden ser propuestas para sincronizar nuestros workspaces,activos/recursos involucrados entre nuestras regiones.


Conceptos DR

Para poder comprender que es Disaster Recovery, deberemos primero comprender dos conceptos importantes:

Recovery Point Objective (RPO)

Hace referencia a la cantidad de datos máxima pérdida (medida en minutos) aceptable después de una caída del sistema. En este caso al disponer de Azure Blob Storage como sistema de persistencia distribuido, el concepto aplicaría a los datos de usuario temporales almacenados por Databricks, como por ejemplo cambios realizados en nuestros notebooks.

Recovery Time Objective (RTO)

Entendemos por RTO al periodo de tiempo desde la caída del sistema hasta la recuperación del nivel de servicio marcado.

En la siguiente imagen, podemos observar ambos conceptos de una forma visual:

Esquema conceptual sobre los conceptos RPO/RTO (fuente: Databricks)

Es importante indicar que la corrupción existente en los datos no se verá mitigada por las políticas asociadas a DR, sin embargo Databricks ofrece Delta time travel como sistema de versionado.

Tipos de región y redundancia

Una vez comprendido los conceptos de RPO y RTO, deberemos comprender los diferentes tipos de regiones en los que operará nuestra solución:

  • Región primaria: Región principal donde opera el sistema de forma normal.
  • Región secundaria: Región alternativa que entrará en operativa en caso de caída de la región primaria.

En nuestro caso de uso, estamos implementando un workspace de Databricks, por lo tanto emplearemos como capa de persistencia principal Blob Storage. Este servicio ofrece diferentes posibilidades a la hora de replicar nuestros datos entre regiones, vamos a verlas.

Region primaria

  • Almacenamiento con redundancia local (LRS): se realizan tres copias síncronas dentro de una única ubicación física en la región primaria, reduciendo así el coste, pero afectando a la disponibilidad y durabilidad (once nueves) de los datos.
Diagrama de replicación LRS (fuente: Azure)
  • Almacenamiento con redundancia de zona (ZRS): copia síncrona de los datos en tres zonas de alta disponibilidad en la región primaria (doce nueves).
Diagrama de replicación ZRS (fuente: Azure)

Region primaria y secundaria

  • Almacenamiento con redundancia geográfica (GRS): Se realiza una copia LRS en la región primaria y secundaria.
Diagrama de replicación GRS (fuente: Azure)
  • Almacenamiento con redundancia de zona geográfica (GZRS): Se realiza una copia con ZRS en la región primaria y mediante LRS en la región secundaria.
Diagrama de replicación GZRS (fuente: Azure)

En ambos casos, el acceso a los datos en la región secundaria no estará disponible salvo activación de la opción de lectura RA.

Dadas estas configuraciones, en la siguiente imagen se pueden ver los escenarios planteados en los que nuestros datos dejarían de ser accesibles.

Disponibilidad y acceso al dato según la redundancia configurada (fuente: Azure)

Deberemos configurar el nivel de replicación y redundancia entre zonas con el fin de disponer de nuestros datos sincronizados y disponibles en las regiones secundarias con el fin de que estás puedan estar operativas.


Tipos de despliegue

Dentro de los tipos de despliegue, podemos encontrar diferentes combinaciones según la necesidad de respuesta y los costes que deseamos asumir por su disponibilidad.

  • Activo: Despliegue principal que ejecuta las funcionalidad y servicios propios del sistema.
  • Pasivo: Procesos que no operan en el despliegue principal y permanecen inactivos/pasivos hasta que el despliegue activo deje de funcionar por una caída.

Es posible encontrar combinaciones de estos: activo-pasivo, activo-activo. De forma general:

Backup Restore
Es la estrategia más económica y lenta que podemos implementar. El objetivo principal es tener un conjunto de puntos de restauración en ambas regiones que podamos emplear para recuperar el servicio, sin necesidad de aprovisionar elementos core del sistema en otras regiones. 

Pilot Light 
Las piezas más importantes de nuestro sistema se encuentran desplegadas de forma activa pero bajo mínimos dentro de nuestra región secundaria, de forma que ante una caída del sistema los servicios principales podrían estar operativos y podrían escalarse de forma gradual (activo-pasivo).

Warn Standby
Estaríamos en un escenario muy similar a Pilot Light pero donde no solo tendríamos activos nuestros sistemas principales sino también una buena parte de los secundarios funcionando bajo mínimos pero listos para ser escalados (activo-pasivo).

Multi-site
Este plan ofrece el mayor grado de respuesta ya que implica disponer de forma activa todas nuestras piezas en una región secundaria, listas para dar servicio en caso de caída de la región principal (activo-activo)

Deberemos elegir la estrategia que mejor se adapte a nuestro caso de uso que dependerá principalmente del nivel de respuesta y coste asumible.


Workflow típico de recuperación

Dentro de los diferentes procedimientos, encontramos la estrategia activa-pasiva como la solución más sencilla y barata pero a la vez efectiva a la hora de ofrecer respuesta y servicio en el caso donde tras una caída del sistema en la región principal, el sistema pasivo entra en funcionamiento dando soporte al servicio.

La estrategia podría ser implementada de forma unificada para toda la organización o por grupos/departamentos de forma independiente basados en sus propias reglas y procedimientos.

De una forma global nos encontraremos que el procedimientos típico a alto nivel sería el siguiente:

  • Caída de un servicio crítico en la región primaria: red, origen de datos, etc
  • Se levanta el servicio en la segunda región si ésta no está afectada.
    • Se deben parar todas las actividades relacionadas con el workspace que sigan en funcionamiento en la región primaria y realizar un backup de los cambios recientes si es posible.
    • Se inicia el proceso de recuperación de los servicios sobre la región secundaria. Actualizando el enrutamiento y direcciones de dominio a la nueva región.
  • Se verifica que el servicio funciona correctamente y con normalidad.
  • En algún punto, la incidencia en la región primaria se ve resuelta y los servicios de Azure vuelven a un funcionamiento normal. Por lo tanto se deberá restablecer el sistema sobre la región primaria.
    • De forma idéntica al punto 2.a se deben parar todos los servicios y cargas de trabajo en la región secundaria.
    • Además se deben de volver a actualizar el enrutamiento y las direcciones de dominio a la región primaria.
    • Por último se debe de realizar un backup de los datos generados durante la caída de la región primaria para ser replicados en esta.
  • Finalmente se verifica que el servicio vuelva a funcionar correctamente y con normalidad en la región primaria.

Una vez nos hacemos una idea general de como sería un workflow típico de recuperación activo-pasivo, estudiaremos como podemos aplicarlo dentro de Databricks en nuestros workspaces.


Disaster Recovery en Azure Databricks

Databricks como plataforma de Data Analytics, tiene los datos como principal activo. Por ello se deben de definir las estrategias que permitan no solo poder seguir operando los servicios de la plataforma y workflows productivos en la región de soporte, sino la estrategia que permita generar consistencia en la propia replicación de los diferentes data sources.

En la siguiente imagen se especifican a modo de diagrama los diferentes activos que se verían involucrados en la replicación del plano de control o de datos.

Estrategia y herramientas en la sincronización.

Una vez realizado un análisis de nuestro sistema, deberemos analizar pieza por pieza como podemos realizar el procedimiento de réplica y sincronización.

Existen dos principales estrategias:

  • Un cliente que sincroniza los datos productivos y activos de la región primaria a la secundaria en un flujo programado.
  • Herramientas de integración/despliegue continuo (CI/CD) para el despliegue de forma paralela de la infraestructura, código y otros recursos principales del sistema en ambas regiones, de forma que la región secundaria se encuentre sincronizada con todos los cambios y desarrollos para ser operativa en caso necesario.
Esquema de sincronización vía CI/CD (fuente: Databricks)

Herramientas

Databricks ofrece en la siguiente tabla un resumen del conjunto de estrategias que se podrían aplicar según el recurso/activo involucrado de nuestro workspace. 

Es importante señalar que a día de hoy no hay ningún servicio oficial por parte de Databricks que permita administrar e implementar una política activa-pasiva de los workspaces en Azure.

Herramientas de replicación
FEATURE
Sync Client
CI/CD
Código fuente, notebooks, librerías
Sincronización con la región secundaria
Despliegue en ambas regiones
Usuarios y grupos
Empleo SCIM para la sincronización en ambas regiones
Control de los metadatos de los usuarios y grupos a través de GIT.
Configuración de los pools
Empleo del CLI o API para la creación en la segunda región
Empleo de templates. Configurar la región secundara con min_idle_instances a 0
Configuración de los jobs
Empleo del CLI o API para la sincronización con la segunda región
Empleo de templates. Configurar la región secundaria con concurrencia a 0
ACLs
Mediante la API de Permisos 2.0 es posible replicar los controles de acceso sobre los recursos copiados
Empleo de templates.
Librerias
DBFS
Repositorio central
Scripts de inicialización del cluster
Replicar de una región a otra a través del almacenamiento en el workspace
Repositorio central
Metadata
Incluir las DDL en el código fuente.
Secretos
Replicacion via API o CLI en el momento de creación
Configuraciones del cluster
Replicacion via API o CLI en el momento de creación
Empleo de templates en GIT.
Permisos de Notebooks, jobs y directorios
Replicación mediante la API de Permisos 2.0
Empleo de templates en GIT.

Implementación

Una vez, tenemos clara nuestra estrategia deberemos estudiar como podemos implementarla, para ello disponemos un conjunto de herramientas que van desde IaC, librerías de sincronización de data sources y migración de workspaces. Sin embargo, ninguna de las librerías de sincronizado/migración es oficial y aún se encuentran en desarrollo.

  • Módulo Databricks de Terraform [1]: para replicar la infraestructura, workspaces, metadatos, etc
  • Databricks Workspace Migration Tools [2]: paquete de librerías para generar un punto de restauración y migración de nuestros workspaces en otras regiones e incluso otros proveedores cloud.
  • Databricks Sync (DBSync) [3]: especializado en la sincronización, creación de copias de seguridad y  restauración de workspaces.

Escalabilidad

En este punto, veremos las diferentes opciones que ofrece Databricks en materia de escalabilidad, debido a que este punto ya ha sido tratado profundamente por nuestros compañeros dentro de la entrada Databricks sobre AWS – Una perspectiva de arquitectura (parte 2), nos limitaremos a comentar las características equivalentes en Azure.

Auto Escalado de workers

De la misma forma que en AWS, Databricks ofrece sobre Azure la posibilidad de escalar horizontalmente de una forma dinámica el número de workers dependiendo el mínimo y máximo que hayamos definido, permitiendo mejorar el tiempo de los trabajos sin sobre asignar recursos y por lo tanto reduciendo el coste global por trabajo en hasta un 30%.

Por lo general, en la forma tradicional cuando se definían las políticas de escalado para nuestros clusters se tenían que establecer una serie de umbrales estáticos donde si estos son rebasados se aprovisionan recursos extra, en forma de nodos de cómputo de bajo coste y efímeros (Spot). En muchos casos el escalado in/out de estos recursos no es lo suficientemente rápido, generando una ralentización global del job y una utilización subóptima de los recursos.

Para ello Databricks propone un  nuevo tipo de escalado optimizado [6], donde a partir de la información de los ejecutores es capaz de adaptar rápidamente los recursos del trabajo a sus necesidades de una forma rápida y eficiente, sin necesidad de esperar a que el trabajo completo termine para comenzar el desescalado.

Auto escalado tradicional: Ejecutores activos vs total de ejecutores (fuente: Databricks)
Auto escalado optimizado de Databricks: Ejecutores activos vs total de ejecutores (fuente: Databricks)

Caracteristicas:

  • Posibilidad de escalado desde el mínimo al máximo en dos pasos.
  • Posibilidad de desescalado aun cuando el cluster no está en idle viendo el shuffle file
  • Desescalado en base al porcentaje de nodos trabajando
  • En cluster del tipo job, el desescalado puede producirse si estos están infrautilizados tras 40 segundos, en all-purpose tras 150 segundos. 
  • Posibilidad de configurar la frecuencia de escalado mediante la propiedad spark.databricks.agressiveWindowDownS


Pools

Para reducir al máximo el tiempo de lanzamiento de una nueva instancia, Databricks permite mantener un set de clusters o pool pre-inicializado en estado idle listo para su empleo en nuestros trabajos o en los procesos de escalado. Si se llega al caso de que todo el pool de instancias se ha consumido, de forma automática se asignarán nuevas instancias al pool.

De la misma forma al escalado de los clusters, podremos definir un número máximo y mínimo de instancias que el pool podrá tener en estado idle para su posterior asignación al trabajo demandante y el tiempo que estas pueden permanecer desasignadas hasta su eliminación.

Respecto al tipo de instancias asignado al pool, no podrán cambiarse, tanto el driver como los workers del trabajo consumirán el mismo tipo de instancias.


Auto escalado del almacenamiento

Databricks ofrece la posibilidad de asignar un auto escalado en el almacenamiento local en disco del cluster con el fin de acotar la necesidad de dimensionado de estos. 

Databricks monitoriza el espacio libre en el disco de forma que en caso necesario se montará un disco externo sobre éste. Es importante señalar que estos discos una vez asignados no podrán desmontarse hasta que el cluster no sea eliminado, por ello se recomienda emplearlos en instancias Spot o que en instancias tengan una política de auto finalizado

Seguridad

Encriptación de datos databricks

Uno de los aspectos más importantes cuando vamos a seleccionar una plataforma para  el tratamiento de datos es la seguridad de los mismos. Debe ofrecer mecanismos de encriptación de datos tanto en los sistemas de almacenamiento, comúnmente conocido como datos en reposo (at rest), como cuando están en movimiento (in-transit).


En transito

Databricks encripta todos los datos que circulan por cada uno de sus diferentes componentes  y orígenes con TLS.  Además de la encriptación de datos, se encriptan con TLS todas las comunicaciones que se realizan entre el plano de control y el plano de datos, por tanto los comandos, consultas y meta-data viajan también encriptados.

Para plataformas que requieran un nivel alto de protección, se puede realizar la encriptación entre los nodos del cluster utilizando la encriptación RPC de Spark [7]. Está se realiza con cifrado AES de 128 bits a través de una conexión TLS 1.2. Está opción solo está disponible con el plan premiun y es necesario establecer los parámetros de configuración de Spark en el script de init del cluster o en el global si necesitamos que se aplique a todos los cluster del workspace. Es importante que tengamos en cuenta que la encriptación entre los nodos del cluster puede suponer una disminución en el rendimiento de los procesos y dado que la red privada de los nodos suele estar aislada, en la mayoría de los casos no será necesario este tipo de encriptación.

 
En reposo

Para el cifrado de los datos en reposo se utiliza SSE [8] (server-side encryption), cifra automáticamente los datos cuando se guardan en el almacenamiento distribuido (blob storage, ADLS y ADLS2).

Por defecto DBFS está encriptado usando claves administradas por Microsoft pero también permite la opción de usar claves administradas por el cliente, comúnmente conocidas como (CMK), permitiendo de este modo utilizar tu propia clave de cifrado para cifrar la cuenta de almacenamiento del DBFS. Además, tanto si se usa clave administradas como tu propia clave, también se ofrece la posibilidad de una capa adicional de cifrado utilizando un algoritmo/modo de cifrado diferente en la capa de infraestructura utilizando claves de cifrado administradas por la plataforma.

Para tener un completo cifrado de los datos en reposo, además del cifrado datos en el almacenamiento distribuido, se puede habilitar la encriptación de los disco locales de los nodos del clúster con lo que se permite la encriptación de los datos temporales que se guardan en las ejecuciones de los procesos. Actualmente está característica se encuentra en en versión preliminar pública y sólo está disponible para la creación del cluster desde el api REST utilizando la configuración siguiente:

{"enable_local_disk_encryption": true} 

También hay que tener en cuenta que activar esta opción puede suponer cierto impacto en el rendimiento de los procesos.

Diagrama de Arquitectura Databricks (fuente: Azure)

Logging

Para el correcto gobierno de una plataforma de ejecución de datos es necesario disponer de las herramientas necesarias para poder realizar el seguimiento y comprobación de ejecución de los workloads. Databricks integra en su plataforma todos elementos necesarios para realizar el mismo en un entorno de Spark. A continuación, vamos a resumir las opciones que integra Databricks out of the box aunque se pueden realizar monitorizaciones más avanzadas utilizando otras herramientas o servicios.

 

Cluster logs

Para cada uno de los cluster o job cluster creados en la plataforma podemos consultar de forma visual:

Captura Workspace - Sección Clusters

Event log: Se muestran todos los eventos relacionados con el ciclo de vida del cluster que han sucedido, como pueden ser, creación, terminación, cambios en la configuración…

Spark UI: Permite el acceso a la GUI ofrecida por Spark. Esta GUI es fundamental para poder detectar y solventar los problemas de performance en las aplicaciones de Spark.

Driver Logs : Permite ver los logs de ejecución tanto de la salida estándar , error y  log4j. Databricks también permite que se realice el volcado de logs en un filesystem determinado, para ellos es necesario configurarlo en las opciones avanzadas del cluster o indicándolo en la creación del cluster si se realiza desde crea desde API o CLI.

Metrics: Databricks proporciona acceso a Ganglia Metrics para obtener un mayor detalle del rendimiento que está ofreciendo el cluster

Captura Workspace - Ganglia Metrics

Registro de diagnóstico en Azure Databricks 

Azure Databricks nos ofrece la posibilidad de descargar los registros de las actividades realizadas por los usuarios a través del registro de diagnóstico [9]. Activando esta opción se enviarán los registros de la actividad de usuario a un destino seleccionado, Azure tiene disponibles 3 opciones para el envío de los registros: Cuenta de Almacenamiento, Event y Log Analytics.

Estos son los servicios que se pueden seleccionar para obtener registros de diagnóstico.

SERVICIOS DISPONIBLES PARA DIAGNÓSTICO
DBFS
sqlanalytics
modelRegistry
clusters
genie
repos
accounts
globalInitScripts
unityCatalog
jobs
iamRole
instancePools
notebook
mlflowExperiment
deltaPipelines
ssh
featureStore
sqlPermissions
workspace
RemoteHistoryService
databrickssql
secrets
mlflowAcledArtifact

La activación se puede realizar desde Azure Portal, API REST, CLI, ó powershell. Los registros están disponibles en un plazo de 15 minutos después de la activación.

Este sería el esquema de un registro de diagnóstico de salida 

Campo Descripción
operationversion
Versión del esquema del formato del registro de diagnóstico.
time
Marca de tiempo UTC de la acción.
properties.sourceIPAddress
Dirección IP de la solicitud de origen.
properties.userAgent
Explorador o cliente de API usado para realizar la solicitud.
properties.sessionId
Identificador de sesión de la acción.
identities

Información sobre el usuario que realiza las solicitudes:
* * : dirección de correo electrónico del usuario.

category
Servicio que registró la solicitud.
operationName
La acción, como el inicio de sesión, el cierre de sesión, la lectura, la escritura, etc.
properties.requestId
Identificador de solicitud único.
properties.requestParams

Pares clave-valor de parámetro usados en el evento.

El requestParams campo está sujeto a truncamiento. Si el tamaño de su representación JSON supera los 100 KB, los valores se truncan … truncated y la cadena se anexa a las entradas truncadas. En raras ocasiones, cuando un mapa truncado sigue siendo mayor que 100 KB, TRUNCATED en su lugar hay una sola clave con un valor vacío.

properties.response
Respuesta a la solicitud: * * : mensaje de error si se ha producido un error. * * : resultado de la solicitud. * * : código de estado HTTP que indica si la solicitud se realiza correctamente o no.
properties.logId
Identificador único de los mensa jes de registro.

Tabla Esquema Registro Salida (fuente: Azure)

Para la explotación de los registros, si se ha seleccionado la opción de Logs Analytics, podremos explotarlos de forma sencilla utilizando Azure Monitor. Pero si lo que se desea es explotar estos registros con cualquier otra plataforma, servicio o herramienta es posible tomando estos registros JSON del lugar del envio seleccionando en la activación.

Referencias

[1] Databricks Terraform Provider. [link]

[2] Databricks Workspace Migration Tools. [link]

[3] Databricks Sync. [link]

[4] Databricks Disaster Recovery [link]

[5] Cifrado entre nodos de trabajo[link]

[6] Optimized AutoScaling [link]

[7] Spark Security [link]

[8] Azure encriptación discos [link]

[9] Registro de diagnostico [link]

Navegación

Glosario

Disaster Recovery

Escalabilidad

Seguridad

Logging

Referencias

Autores

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

Francisco Linaje

AWS Solutions Architect

Gabriel Gallardo Ruiz

Senior Data Architect

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Data Mesh

julio 27, 2022
LEER MÁS

Databricks sobre Azure – Una perspectiva de Arquitectura (parte 2)

marzo 24, 2022
LEER MÁS

Análisis de vulnerabilidades en contenedores con trivy

marzo 22, 2024
LEER MÁS

PERSONAL MAPS: conociéndonos más

octubre 24, 2023
LEER MÁS

LakeHouse Streaming en AWS con Apache Flink y Hudi (Parte 2)

octubre 4, 2023
LEER MÁS

Data-Drive Agriculture; Big Data, Cloud & AI aplicados

noviembre 4, 2020
LEER MÁS

Publicado en: Blog, interes, Practices, Tech

  • « Ir a la página anterior
  • Página 1
  • Página 2
  • Página 3
  • Página 4
  • Ir a la página siguiente »

Footer

LegalPrivacidadPolítica de cookies

Patrono

Patrocinador

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