El lenguaje de consulta SQL sigue más vivo que nunca y se confirma que sigue siendo un lenguaje de primer nivel para el acceso a datos de todo tipo. Con la llegada de los Data Lake surge la necesidad de ejecutar consultas SQL sobre los datos de nuestro Data Lake, y no solamente grandes operaciones, sino también operaciones más ligeras e interactivas, que puedan proceder por ejemplo de herramientas de visualización como Tableau, PowerBI, etc.

En este artículo vamos a comparar Databricks Photon, un nuevo engine vectorizado escrito en C++, con Synapse y su modo de ejecución Batch e índices columnares.

En estos últimos meses existe un enorme crecimiento en las necesidades de explotación de la información que durante estos años se ha ido almacenando en los Data Lakes de muchas compañías. Esta información se enriquecía habitualmente con los Data Warehouses existentes también en las compañías dando lugar al escenario denominado “Modern Data WareHouse” donde ambas fuentes de datos se combinaban para servir a las capas analíticas.

El problema de este tipo de soluciones es que tienden a complicar la solución final por lo que surge con fuerza la posibilidad de utilizar una única plataforma para cubrir todas las necesidades. De ahí surgen iniciativas como el Delta Lake que intenta añadir ciertas características típicas de los motores relacionales como son las transacciones sobre un Data Lake.

Llegados a este punto cuando buscamos la forma de acceder a esta información de forma ágil e interactiva el lenguaje SQL aparece como una alternativa natural, bien comprendida y compatible con muchas herramientas de visualización como Tableau, PowerBI, etc.

Desde el mundo Spark, Spark SQL era el componente capaz de añadir esa capa de forma que pudiéramos acceder a nuestros datos mediante este lenguaje. Esta capa lo que conseguía era mediante el optimizador Catalyst generar un “plan de ejecución” lo más optimo posible utilizando un sistema híbrido de optimización rule-based y cost-based:

rule based

Las similitudes con cualquier sistema de optimización de un motor relacional son evidentes y es que en el fondo se está tratando de abordar problemas prácticamente idénticos.

Sin embargo Spark SQL no era todo lo rápido que uno desearía, lo cual lo hacía poco viable para operaciones interactivas o de las que se esperara un tiempo de respuesta muy rápido. Fruto de esta necesidad nace Photon que es un nuevo engine vectorial completo enfocado al uso sobre Delta Lakes y que complementa a Catalyst para hacer las operaciones mucho más eficientes:

submit sql query

Tenemos que tener en cuenta que actualmente Photon no soporta todas las características de Spark por lo que durante la ejecución podemos acabar teniendo una mezcla de operadores Photon y Spark. Cuanta más parte ejecutemos en Photon mejor rendimiento obtendremos.

Poniéndonos en marcha

Vamos a configurar un pequeño entorno de prueba para poder realizar una pequeña prueba con Photon y poder compararla con Synapse. Para ello comenzaremos creando un grupo de recursos y desplegando ambas soluciones:

Databricks Photon vs Azure Synapse

Cuando despleguemos Databricks deberemos tener en cuenta que la versión del cluster a utilizar sea al menos la 8.3 o superior. En nuestro caso utilizaremos la última versión estable correspondiente al Runtime 9.1 que utiliza la versión 3.1.2 de Spark:

Databricks Photon vs Azure Synapse

Para el despliegue de Synapse no tenemos que elegir ninguna versión ya que por defecto vamos a crearla con la última disponible.

Carga de datos

Para poder realizar alguna consulta necesitamos algunos datos que tengan cierta volumetría. Entre los conjuntos de datos más habituales encontramos los de los taxis de Nueva York. Por variar un poco utilizaremos datos de SynthCity: https://www.synthcity.xyz/

El total de datos son aproximadamente 27.5 GB en formato parquet y que incluye nueve áreas distintas. Concretamente utilizaremos el fichero del area1 que contiene aproximadamente 40 millones de filas y ocupa aproximadamente 2.4 GB en formato parquet. Cargaremos el fichero en la cuenta ADLS Gen2 asociada a Synapse:

Databricks Photon vs Azure Synapse

Una vez cargados intentamos hacer una consulta sencilla para verificar que podíamos leer el fichero y nos encontramos con este error:

Started executing query at Line 1

File ‘https://testsynapsephotonverne.dfs.core.windows.net/data/area1.parquet’ cannot be opened because it does not exist or it is used by another process.
Visit this article to learn more about this error

Total execution time: 00:00:01.028

Para solucionar este error tenemos que asignar los permisos necesarios tanto a nivel de contenedor como de carpeta y ficheros. Es decir, tenemos que editar los permisos de toda la jerarquía hasta llegar al fichero. Aquí os dejo un enlace donde se explican claramente los permisos a asignar a nuestro usuario:

https://docs.microsoft.com/en-us/azure/synapse-analytics/sql/resources-self-help-sql-on-demand#query-fails-because-file-cannot-be-opened

 

Databricks Photon vs Azure Synapse

Podemos ver que el primer acceso al fichero no es especialmente rápido, necesitando 16 segundos. Realizaremos un conteo inicial y vemos que tenemos algo más de 46 millones de registros:

Databricks Photon vs Azure Synapse

Estas cifras realmente son irrisorias para lo que habitualmente se mueven en estos entornos, donde cifras de decenas de miles de millones o incluso centenas de decenas de miles de millones son cifras habituales.

Ponemos a trabajar al motor

Vamos a realizar un tipo de consulta muy habitual consistente en una agrupación con un cálculo agregado filtrando los valores más representativos (mayores). La primera ejecución directa sobre el fichero parquet, utilizando el serverless pool nos da un nada interesante tiempo de 41 segundos para esta consulta:

Databricks Photon vs Azure Synapse

Una segunda ejecución rebaja este tiempo a la mitad aproximadamente, lo cual tampoco es un tiempo especialmente adecuado para una consulta interactiva debido a la mala experiencia de usuario que se ofrecería:

Databricks Photon vs Azure Synapse

A continuación probaremos a realizar esta operación desde un pool dedicado de recursos de tamaño DW1000c:

dedicated sql pool

Mapearemos una tabla externa al fichero parquet para utilizarla más fácilmente:

fichero parquet

Al lanzar la consulta nos encontramos unos resultados aún más decepcionantes, con más de un minuto y medio de ejecución:

run

Una segunda ejecución no redujo el tiempo, por lo que claramente esta opción es excesivamente lenta como plantearse un uso interactivo. No olvidemos tampoco que este es un conjunto de datos pequeño, por lo que es doblemente decepcionante:

Databricks Photon vs Azure Synapse

Aprovechando que tenemos un pool dedicado, vamos a crear una copia de los datos a una tabla de SQL Server. Para ello vamos a cargar en una tabla llamada area1_cci los datos del fichero parquet que quedarán almacenados en formato Columnar con distribución Round Robin:

CREATE TABLE [dbo].[area1_cci]
 
WITH
 
(
 
DISTRIBUTION = ROUND_ROBIN
 
,CLUSTERED COLUMNSTORE INDEX
 
)
 
AS
 
SELECT *
 
FROM [dbo].[area1];
 

Una vez cargada, pasaremos a lanzar de nuevo la consulta de nuevo pero atacando a la tabla con formato columnar:

select top 10

En esta ocasión tenemos un tiempo de 9 segundos que empieza a ser más razonable. Una segunda ejecución reduce este tiempo a poco más de 2.5 segundos:

executing query

Respecto al tamaño de esta tabla vemos que es similar al fichero Parquet original, ocupando únicamente un poco más:

fichero parquet original

Por tanto podemos decir que “zapatero a tus zapatos”. En este escenario claramente el motor SQL Server rinde mucho más cuando trabaja con índices columnares respecto a trabajar con ficheros parquet externos.

Como referencia, vamos a escalar el tamaño del pool desde DWU1000c (~13€/h) a DWU400c (~5€/h) y DWU200c (~2.5€/h) para comparar el rendimiento:

duracion consulta

Es decir, en este caso con una volumetría tan pequeña no está en absoluto justificado utilizar un tamaño de pool de DWU1000c, siendo DWU200c más que suficiente.

Para decidir el tamaño no tenemos que tener en cuenta únicamente el rendimiento individual, ya que hay otros factores a tener en cuenta. Por ejemplo los slots de concurrencia, que limitarán cuantas consultas podemos ejecutar concurrentemente, por lo que el tamaño adecuado podría ser mayor en función de los picos de carga.

Para finalizar con las pruebas en Synapse vamos a proceder a crear un pool de Spark y vamos a probar que tal se comporta:

new apache spark pool

Una vez tenemos el cluster en marcha vamos a crear un notebook e iniciar la sesión. La realidad es que creación de una sesión puede ser algo lenta (diría que  desesperantemente lenta), pero solo tendremos que hacerlo una vez mientras estemos interactuando con el notebook (aunque consumiremos ciertos recursos por tenerla abierta):

Databricks Photon vs Azure Synapse

Una vez la sesión arranca podemos lanzar una consulta para mostrar los primeros registros de nuestro fichero parquet:

primeros registros ficheros parquet

El tiempo de esta operación inicial es menor que en la prueba desde el serverless SQL pool.

Una vez comprobado que tenemos acceso al fichero, vamos a escribir código PySpark equivalente a la consulta SQL. Podemos ver que los resultados son prácticamente idénticos, existiendo únicamente diferencias de redondeo en las últimas cifras si lo comparamos con los resultados que teníamos con SQL:

codigo PySpark
view table

Un detalle que debemos tener en cuenta es que si tenemos una nueva ejecución, la caché de resultados de Spark nos devolverá el dato muy rápidamente, sin tener que realizar de nuevo los cálculos al no haber cambiado absolutamente nada:

Databricks Photon vs Azure Synapse

Una de las funcionalidades de Spark, que también tendríamos disponible en Spark SQL, son sus mecanismos de caché, como los métodos .cache() y el .persist() (en memoria y disco) o la funcionalidad CACHE TABLE. Este tópico daría para un artículo completo y es algo muy interesante y necesario para maximizar el rendimiento de Spark. En este enlace se explican estas capacidades más en detalle,

Por recapitular, en Synapse, cuando realizamos el procesamiento sobre el fichero parquet de forma directa los tiempos que hemos obtenido en una primera ejecución en frío han sido los siguientes:

duracion consulta s

De nuevo se confirma la misma línea que hemos comentado anteriormente: cada tipo de motor funciona mejor con el almacenamiento para el que fue diseñado (bases de datos vs ficheros).

Una vez que tenemos claro más o menos que podemos esperar de Synapse, vamos a cambiar a Databricks para explorar el nuevo motor de ejecución Photon.

Saltando a Databricks

Comenzaremos cargando el mismo fichero de pruebas que hemos usado con Synapse. Inicialmente lo intentamos con la opción de subida de ficheros nativa del portal, pero nos encontramos con un error al superar el fichero los 2 GB:

Synapse

Debido a esto subiremos el fichero a una cuenta de storage en Azure y posteriormente lo importaremos desde ahí. Para ello en un notebook configuraremos primero los datos de la cuenta de almacenamiento:

Databricks Photon vs Azure Synapse

A continuación fijaremos la ruta al contenedor y fichero que hemos subido previamente, así como su formato:

file location

A continuación verificamos que podemos leer el fichero y cargarlo en un dataframe:

dataframe

En realidad como lo que queremos es leerlo para volcarlo de nuevo en Databricks, podemos hacerlo directamente así:

databricks read

Una vez cargados los datos, podemos probar a acceder desde el notebook usando el lenguaje SQL y verificar que los datos están accesibles:

lenguaje sql

A continuación lo que haremos es crear un Databricks SQL endpoint que será el que utilizaremos para las pruebas. Este tipo de endpoints viene habilitado con Photon por defecto:

databricks sql endpoints

Podemos ver que tenemos varias e importantes limitaciones por ahora, como el no soportar operaciones de windowing. Indicar también que cuando estamos creando este tipo de endpoints nos aparece un “warning” un tanto curioso:

Databricks Photon vs Azure Synapse

Es decir, que la recomendación de Databricks para crear un “medium endpoint” implica tener disponibles, al menos, 350 cores en nuestra subscripción de Azure disponibles. Esto ya nos da una pista de que en este tipo de entornos el uso de la fuerza bruta está en su ADN.

Para nuestras pruebas crearemos un endpoint de tamaño pequeño de momento y verificaremos que esté habilitado Photon:

sql endpoints

Sobre este endpoint “starter” vamos a lanzar la consulta que hemos utilizado en las pruebas sobre Synapse para comprobar que podemos acceder a los datos:

endpoint starter

A continuación lanzaremos la consulta que lanzamos en Synapse (modificando únicamente el TOP por el LIMIT):

starter endpoints

Podemos ver que en este caso, con una operación en frío, hemos necesitado menos de 12 segundos utilizando Photon.

Si volvemos a lanzar la consulta, en caliente, vemos que obtenemos el resultado en 1.85 segundos siendo esta de momento la respuesta más rápida que hemos tenido hasta ahora:

starter endpoints s

Sin embargo, a diferencia de lo que veíamos cuando lanzamos la operación vía pySpark, cuando hacemos cambios en la consulta y, por ejemplo, cambiamos la agregación a R y G únicamente y a devolver los top 20 grupos con mayor valor, el rendimiento sigue siendo muy bueno desde la primera ejecución:

Databricks Photon vs Azure Synapse

Por tanto, podemos ver cómo Photon es competitivo en rendimiento con Synapse con almacenamiento columnar y el modo Batch de ejecución. Además la caché de datos en memoria funciona muy bien y permite obtener muy buenos resultados ante ligeros cambios que podemos hacer interactivamente.

Con estos tiempos de ejecución y funcionalidades como el “dual queue” que permite que las peticiones “pequeñas” tengan su cola dedicada, creemos que con Photon hay una alta probabilidad de poder utilizar directamente nuestro Data/Delta Lake para realizar consultas interactivas.

Para quien desee entrar más en detalle del funcionamiento de Photon os dejo algunos enlaces a sesiones donde se explica más en detalle su funcionamiento:

https://www.youtube.com/watch?v=oz7XNx0YUw8

https://databricks.com/session_eu20/photon-technical-deep-dive-how-to-think-vectorized

https://databricks.com/session_na21/radical-speed-for-sql-queries-on-databricks-photon-under-the-hood?itm_data=product-resources-sqlQueriesPhoton

 

Hablemos de costes

Respecto al tema de costes, tenemos que el consumo por DBU es más elevado con Photon si lo comparamos con Spark SQL, y el coste es de aproximadamente 0.19€ por DBU:

pay as you go

En nuestra prueba inicial hemos usado un enpoint pequeño con 12 DBUs:

enpoint pequeño

Para este endpoint estaríamos hablando de un coste aproximado de 2.26€/hora, que sería similar al que teníamos con Synapse con un pool dedicado y DWU200c.

Aunque no tenemos el dato de los recursos asignados, de media podemos considerar que un DBU equivale aproximadamente a 4 cores y 30 GB de RAM, por lo que con 12 DBUs podríamos estar gestionando una cantidad de recursos de aproximadamente 48 cores y 360 GB de memoria, más que suficiente para la tarea que estamos abordando en realidad.

Si bajamos a un tamaño 2X-Small de solo 4 DBUs el rendimiento de la primera consulta en “frio” queda reducido a más o menos la mitad (24 segundos vs 12 segundos):

starter endpoint consulta

Y en caliente también el rendimiento es algo menor, pero aun así sigue siendo muy bueno:

rendimiento

En Synapse, tenemos también cierta información respecto a la cantidad de memoria que se nos dedica en cada nivel de rendimiento:

Databricks Photon vs Azure Synapse

Y también, aproximadamente, podemos calcular de cuántos cores disponemos en base a ciertas “pistas” que tenemos en la documentación:

sql pool in azure

Es decir, para Synapse Gen1 (DWUs) tenemos un ratio de 7.5 respecto a las DTUs y en Synapse Gen2 un ratio de 9 respecto a las DTUs. Si aplicamos los ratios de conversión para BC (Business Critical) de aproximadamente 125 DTUs = 1 vCore BC tenemos que:

DW200c à ~14 cores físicos, 28 lógicos y 120 GB de RAM à 2.5€/h

DW400c à ~28 cores físicos, 56 cores lógicos y 240 GB de RAM à 5€/h

DW1000c à 3 nodos (1 de control y 2 workers) cada uno con 37 cores físicos, 74 cores físicos y 300 GB de RAM  à 13€/h

Teniendo en cuenta todo esto, si comparamos estos valores los costes de SQL Server funcionando sobre una simple VM con 16 cores lógicos y 128 GB de RAM vemos que serían de casi 7€/h para Enterprise y unos 3€/h para Standard. Esto son cifras aproximadas, que podrían rebajarse por ejemplo preservando compute.

Sin embargo si las comparamos con la cantidad de recursos que tenemos con el pool reservado de Synapse podemos ver que los precios están en niveles de SQL Server Standard, mientras que para manejar los tamaños de datos que manejamos en un DWH o en un Data/Delta Lake normalmente estaríamos hablando de Enterprise Edition el licenciamiento que necesitaríamos. Dicho de otra forma, si lo que necesitamos realmente es un SQL Server DWH MPP para trabajar en formato columnar, los precios de Synapse son muy competitivos.

Por último, si tenemos en cuenta el estudio realizado por Databricks en lo que se refiere a precios, vemos que el coste/rendimiento con Photon viene a ser prácticamente la mitad al que tendríamos con otras alternativas.

Aunque Databricks no desvele los nombres de los proveedores con los que está comparando, en base a los datos que hemos obtenido nos cuadra perfectamente que Synapse sea bien el Cloud Data Warehouse 1 o 2 en el gráfico:

3otb

Conclusión

Con la inclusión de Photon, Databricks ha reforzado uno de los puntos donde existía una buena oportunidad de mejora para esta plataforma, haciéndola muy competitiva en rendimiento y coste cuando queremos utilizar SQL. Esto hace que si nos plantemos seriamente explotar mediante este lenguaje un Delta Lake, tengamos con Databricks la combinación ganadora.

Si comparamos Databricks con Synapse, la sensación que tenemos es la de enfrentar un producto maduro con un producto relativamente inmaduro. Pero obviamente también tenemos puntos fuertes en Synapse por lo que realmente lo que debemos hacer es analizar cada caso de uso y determinar qué plataforma es mejor caso a caso.

De hecho existen escenarios donde la mejor opción es optar por una combinación de ambas, utilizando por un lado Delta Lake, Spark y ML en Databricks, trabajando con los datos en crudo, enriqueciéndolos, etc. generando como resultado una capa curated que sería servida por un Synapse DWH MPP el cual con su modo batch y columnstore brillaría incluso en las consultas SQL analíticas más complejas.

¡Sigue Aprendiendo!

Si quieres que te ayudemos a poner en marcha este tipo de proyecto, no dudes en contactar con nosotros. También puedes aprovechar las formaciones existentes para ampliar tus conocimientos 👇🏼

>> Más info
0 Shares:
Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

You May Also Like
Leer más

Azure Stream Analytics serie. Parte 1: Uso e implementación de funciones en JavaScript en un job de ASA

En esta serie de posts vamos a comentar diferentes aspectos de Azure Stream Analytics (ASA de ahora en adelante), que pueden resultarnos útiles en nuestros desarrollos del día a día. Sino conoces Azure Stream Analytics puedes ver una introducción en este enlace. Parte 1: Uso e implementación de funciones en JavaScript en un job de ASA