• Skip to primary navigation
  • Skip to main content
  • Skip to footer
Bluetab

Bluetab

an IBM Company

  • SOLUTIONS
    • DATA STRATEGY
    • Data Readiness
    • Data Products AI
  • Assets
    • TRUEDAT
    • FASTCAPTURE
    • Spark Tune
  • About Us
  • Our Offices
    • Spain
    • Mexico
    • Peru
    • Colombia
  • talent
    • Spain
    • TALENT HUB BARCELONA
    • TALENT HUB BIZKAIA
    • TALENT HUB ALICANTE
    • TALENT HUB MALAGA
  • Blog
  • EN
    • ES

Tech

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

May 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

Incentives and Business Development in Telecommunications

October 9, 2020
LEER MÁS

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

November 17, 2021
LEER MÁS

El futuro del Cloud y GenIA en el Next ’23

September 19, 2023
LEER MÁS

5 common errors in Redshift

December 15, 2020
LEER MÁS

Oscar Hernández, new CEO of Bluetab LATAM.

May 16, 2024
LEER MÁS

Mi experiencia en el mundo de Big Data – Parte I

October 14, 2021
LEER MÁS

Filed Under: Blog, Practices, Tech

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

April 11, 2023 by Bluetab

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

Alberto Jaen

AWS Cloud Engineer

Alfonso Jerez

AWS Cloud Engineer

Adrián Jiménez

AWS Cloud Engineer

Introduction

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

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

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

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

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

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

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

In future articles

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

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

Architecture

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

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

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

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

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

Locust

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

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

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

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

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

Kinesis Data Analytics

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

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

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

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

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

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

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

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

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

Figure 1. KDA configuration with Parallelism 4 and ParallelismPerKPU 2

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

Flink

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

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

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

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

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

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

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

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

Hudi

Concepts

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

Hudi’s features are as follows:

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

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

Table Types and Queries

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

Copy on Write (COW)

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

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

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

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

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

Merge On-Read (MOR)

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

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

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

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

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

COW MOR
Writing cost

Higher

Lower

Latency

Higher

Lower

Query Performance

Lower

Slower before compaction

Igual tras compactación

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

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

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

Conclusions

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

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

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

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

References

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

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

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

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

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

Autores

Alberto Jaen

AWS Cloud Engineer

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

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

Alfonso Jerez

AWS Cloud Engineer

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

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

Adrián Jiménez

AWS Cloud Engineer

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

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

Navegation

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

SOLUCIONES, SOMOS EXPERTOS

DATA STRATEGY
DATA FABRIC
AUGMENTED ANALYTICS

Te puede interesar

Desplegando una plataforma CI/CD escalable con Jenkins y Kubernetes

September 22, 2021
LEER MÁS

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

April 11, 2023
LEER MÁS

Myths and truths of software engineers

June 13, 2022
LEER MÁS

Introduction to HashiCorp products

August 25, 2020
LEER MÁS

Serverless Microservices

October 14, 2021
LEER MÁS

Starburst: Construyendo un futuro basado en datos.

May 25, 2023
LEER MÁS

Filed Under: Blog, Practices, Tech

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

February 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

Boost Your Business with GenAI and GCP: Simple and for Everyone

March 27, 2024
LEER MÁS

How much is your customer worth?

October 1, 2020
LEER MÁS

Bank Fraud detection with automatic learning

September 17, 2020
LEER MÁS

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

May 9, 2023
LEER MÁS

Bluetab is certified under the AWS Well-Architected Partner Program

October 19, 2020
LEER MÁS

¿Existe el Azar?

November 10, 2021
LEER MÁS

Filed Under: Blog, Practices, Tech

Data Governance: trend or need?

October 13, 2022 by Bluetab

Data Governance: trend or need?

Alvar Noe Arellanos

Business & IT Strategy Professional

En los últimos años la implementación de un gobierno de datos corporativo dentro de las diferentes organizaciones, independientemente de la industria a la que pertenezca. En cada una de estas implementaciones surge una pregunta recurrente “El Gobierno de Datos es una necesidad o una tendencia”. Realmente no es una pregunta fácil de contestar ya que deben considerarse varios aspectos para poder contestarla.

Con la llegada de la pandemia, las organizaciones tuvieron que evolucionar de manera acelerada a un esquema digital en el cual los datos, las personas, la escalabilidad de tecnología y la evolución de procesos, juegan un rol esencial para la evolución y trascendencia de las empresas

Si los datos se posicionan como un pilar esencial dentro de la evolución de las organizaciones, tiene sentido que el control y aprovechamiento total de estos requiera la necesidad de un gobierno de datos.

El Gobierno de Datos, según el marco metodológico DAMA®, es definido de la siguiente forma:

"El ejercicio de autoridad compartida, control y toma de decisiones (planificación, seguimiento y aplicación) a través de la gestión de los activos de datos"

Hasta este momento hemos identificado que el Gobierno de Datos es necesario para la evolución de una organización, aun no determinamos en que aspectos se estaría se centraría. Estos aspectos los listamos a continuación:

Organización

Colaboradores que interactúan en la gestión y administración de los activos de datos de la empresa relacionados con el Gobierno de Datos.

Procesos

Las tareas y actividades que conforman los procesos de gestión del Gobierno de Datos

Políticas y Estándares

Las políticas, estándares y lineamientos que permitan gestionar, controlar y estandarizar el Gobierno de Datos.

Tecnología

Tecnología, arquitectura, herramientas que se utilizan para la administración de la información relacionada con el Gobierno de Datos

Si bien estos pilares del Gobierno de Datos permitirán que los datos soporten la evolución digital de la organización, es importante aclarar que para que esto funcione es necesario mantener un modelo alineado a la estrategia de negocio, que sea sustentable y flexible, permitiendo identificar y ajustar de forma activa nuevas fuentes de información, SLAs, entre otros requerimientos que soporten los objetivos de negocio.

Con la implementación de un Gobierno de Datos dentro de las organizaciones se podrán obtener beneficios asociados directamente a las áreas de negocio, por ejemplo:

La obtención de estos beneficios permitirá que la evolución de las organizaciones frente a los retos globales y de las industrias, sea posible.

Dicho lo anterior se pude inferir que el gobierno de datos configura la gestión general de la disponibilidad, usabilidad, integridad y seguridad de los datos usados en una organización, permitiendo a las organizaciones eliminar una administración ineficiente de la información que afectaría a las organizaciones. Especialmente si miramos desde la perspectiva financiera y consideramos que el flujo de datos ha aumentado de forma exponencial en los últimos años a raíz del desarrollo de nuevas tecnologías y del crecimiento del mercado.

Tener una buena gestión de datos significa tomar las mejores decisiones para el negocio, lo que resulta en el aumento de la productividad y de la eficiencia operacional y, consecuentemente, en un incremento en los ingresos empresariales.

Una vez identificada la importancia y los beneficios que el gobierno de datos puede presentar podemos llegar a la conclusión que la implementación de un Gobierno de Datos dentro de una empresa que esta evolucionando a una cultura digital y data driven, es necesaria y no solo una tendencia a implementar según la industria a la cual la organización pertenece.

Alvar Noe Arellanos

Business & IT Strategy Professional

¿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

$ docker run 2021

February 2, 2021
LEER MÁS

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

October 4, 2023
LEER MÁS

Big Data and loT

February 10, 2021
LEER MÁS

Using Large Language Models on Private Information

March 11, 2024
LEER MÁS

Gobierno del Dato: Una mirada en la realidad y el futuro

May 18, 2022
LEER MÁS

Cómo depurar una Lambda de AWS en local

October 8, 2020
LEER MÁS

Filed Under: Tech

Snowflake Advanced Storage Guide

October 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

Databricks on AWS – An Architectural Perspective (part 2)

March 5, 2024
LEER MÁS

Essential features to consider when adopting a cloud paradigm

September 12, 2022
LEER MÁS

CLOUD SERVICE DELIVERY MODELS

June 27, 2022
LEER MÁS

MDM as a Competitive Advantage in Organizations

June 18, 2024
LEER MÁS

Container vulnerability scanning with Trivy

March 22, 2024
LEER MÁS

Spying on your Kubernetes with Kubewatch

September 14, 2020
LEER MÁS

Filed Under: Blog, Practices, Tech

Essential features to consider when adopting a cloud paradigm

September 12, 2022 by Bluetab

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

Alejandro León

Delivery Manager

El NIST (National Institute of Standards and Technology), habla de las 5 características esenciales para una buena administración e implementación del paradigma en la nube. En este artículo se revisarán estas características en profundidad, ya que son aspectos importantes para tener en cuenta al momento adoptar el cómputo en la nube.

Características esenciales

Existe una variedad de servicios diferentes que se ofrecen bajo la modalidad de cómputo en la nube, y cada uno de los servicios ofrecidos tiene un fin único. Sin embargo, existe una serie de características comunes que define al cómputo en la nube, y que hace posible identificarlo como tal.

Según el NIST, las 5 características esenciales del cómputo en la nube son:

  • Autoservicio bajo demanda
  • Despliegue de infraestructura desde la red
  • Agrupación de recursos
  • Elasticidad
  • Medir un servicio

Para entenderlas mejor, echemos un vistazo al detalle de cada uno de estos puntos.

Autoservicio bajo demanda

En estos casos, cada uno de los usuarios u organizaciones que opta por utilizar alguna de las ofertas de servicios de cómputo en la nube es responsable de la configuración de los recursos y el despliegue de estos.

De esta forma, el usuario final es quien decide que recursos quiere o necesita utilizar y cuál será la capacidad asignada a cada uno de los recursos, y es el mismo usuario quien puede configurar estas opciones desde un centro de administración de dichos recursos.

Despliegue de infraestructura desde la red

Todos los servicios ofrecidos bajo el paradigma de cómputo en la nube deben de ser accesibles a través de internet, de forma que un usuario puede hacer uso de ellos en cualquier momento de acuerdo con sus necesidades, y, muy importante desde cualquier parte del mundo, sin necesidad de tener acceso físico a la infraestructura que brinda soporte.

Agrupación de recursos (Disposición de infraestructura)

Cada proveedor de servicios de cómputo en la nube mantiene un gran número de recursos de hardware disponibles para sus clientes. Cada que uno de ellos realiza una solicitud y el proveedor asigna los recursos mediante un modelo de múltiples tenencias. Esto, en esencia significa que todos sus clientes están haciendo uso de la una infraestructura compartida. Además, todos los recursos disponibles se agrupan por cliente, al cual se le asigna un acceso único para cada uno de ellos. De esta forma, cada cliente solo puede ver sus recursos y no tiene conocimiento de los recursos asignados a otros clientes.

Elasticidad

Sin importar cual sea el proveedor de cómputo en la nube, el usuario cuenta con una flexibilidad en el despliegue de los recursos. Esta flexibilidad es una abstracción del despliegue de la infraestructura física que el proveedor de servicios debe realizar para satisfacer las necesidades del cliente.

La infraestructura que soporta los centros de datos de los proveedores de los servicios generalmente hace uso de técnicas de cómputo distribuido o virtualización, que son transparentes para el usuario final.

De esta forma, el usuario tiene el control sobre los recursos que necesita, por lo que puede realizar peticiones para aumentar o disminuir las cantidades y/o capacidades de los recursos contratados, y el proveedor debe ser el encargado de administrar ese cambio en su infraestructura de forma transparente y sencilla para dar una respuesta rápida y satisfactoria a las solicitudes de sus usuarios.

Maneras de medir el servicio

Los proveedores de servicios de cómputo en la nube establecen controles para poder realizar una medición de los servicios utilizados por los usuarios. Dependiendo del tipo de recurso ofrecido, se acuerda y establece con el usuario un método de medición de uso de este, por lo general es por uso, o por servicio.

Por ejemplo, en un servicio de almacenamiento de datos en la nube el proveedor puede establecer un precio fijo para los archivos almacenados, o por el tiempo de almacenamiento, o por el espacio de almacenamiento utilizando, o una combinación de 3 factores.

 

Conclusiones

El cómputo en la nube representa una evolución con respecto a un modelo de cómputo tradicional, en el cual particulares u organizaciones necesitan adquirir todos los elementos necesarios para construir una infraestructura tecnológica capaz de soportar sus operaciones o nuevos proyectos.

La oferta de servicios de cómputo en la nube hace más sencillo la implementación de sistemas de información, sin la necesidad de contar con espacio físico para la instalación de equipos físicos, y con un potencial ahorro al hacer uso de modelos de cobro como son las suscripciones de pago por uso.

Es importante subrayar que el cómputo en la nube no es un reemplazo directo para la implementación de un centro de datos en una organización, sino que representa una alternativa con un diferente modo de operación y un potencial ahorro en costos. Queda como responsabilidad de las organizaciones realizar un estudio para verificar la factibilidad en la contratación de servicios de cómputo en la nube y el modelo de servicios requerido según sus necesidades.

Alejandro León

Delivery Manager

¿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

Databricks on AWS – An Architectural Perspective (part 1)

March 5, 2024
LEER MÁS

Snowflake Advanced Storage Guide

October 3, 2022
LEER MÁS

Databricks on Azure – An Architecture Perspective (part 1)

February 15, 2022
LEER MÁS

Databricks on Azure – An architecture perspective (part 2)

March 24, 2022
LEER MÁS

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

June 7, 2023
LEER MÁS

Basic AWS Glue concepts

July 22, 2020
LEER MÁS

Filed Under: Blog, Tech

  • « Go to Previous Page
  • Page 1
  • Page 2
  • Page 3
  • Page 4
  • Page 5
  • Interim pages omitted …
  • Page 7
  • Go to Next Page »

Footer

LegalPrivacy Cookies policy

Patron

Sponsor

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