Skip to main content

Command Palette

Search for a command to run...

Fabric Apache Spark Diagnostic Emitter: captura logs y métricas en tiempo real

Cómo configurar un Fabric Environment para emitir telemetría de Spark directamente hacia un Eventhouse.

Published
13 min read
Fabric Apache Spark Diagnostic Emitter: captura logs y métricas en tiempo real

Cuando un notebook de Fabric falla a las 3 de la madrugada, o cuando un Spark job tarda el doble de lo esperado sin razón aparente, la primera pregunta es siempre la misma: ¿qué estaba haciendo exactamente el motor en ese momento?

El Fabric Apache Spark Diagnostic Emitter responde a esa pregunta capturando logs de driver y executors, event logs de Spark y métricas JVM en tiempo real, enviándolas a un destino externo durante la ejecución de la aplicación. No hay que esperar a que el job termine ni bucear en el Spark UI histórico.

En este artículo vamos a construir el siguiente flujo: el emitter envía los datos directamente al Custom Endpoint de un Eventstream, que los enruta hacia un Eventhouse (KQL Database) en Fabric. El resultado es telemetría de Spark consultable en KQL en menos de un minuto desde que ocurre.

Arquitectura: por qué Eventstream como intermediario

La documentación oficial describe el flujo directo Spark → Azure Event Hub. Aquí usamos una variante más nativa de Fabric: el emitter apunta al Custom Endpoint de un Eventstream, que internamente es un Event Hub compatible.

Esto tiene ventajas claras sobre conectar directamente a un Event Hub de Azure externo:

  • Todo en el mismo workspace: Eventstream y Eventhouse viven en Fabric, sin salir al portal de Azure.

  • Enrutamiento flexible: El Eventstream puede enviar los datos simultáneamente a varias salidas — Eventhouse para consultas KQL, Lakehouse para retención histórica, Activator para alertas.

  • Coste simplificado: No pagas por un namespace de Event Hub de Azure dedicado si ya tienes capacidad Fabric.

  • Connection string compatible: El Custom Endpoint expone una connection string con el formato Endpoint=sb://...EntityPath=... que el emitter acepta de forma nativa.

Compatibilidad del protocolo: El Fabric Apache Spark Diagnostic Emitter habla el protocolo AMQP de Azure Event Hubs. Cualquier endpoint compatible con ese protocolo funciona como destino, incluyendo el Custom Endpoint del Eventstream de Fabric.


Configuración completa

1 Crear el Eventstream con Custom Endpoint

En tu workspace de Fabric, crea un nuevo Eventstream. En la configuración de origen, selecciona Custom Endpoint (también llamado Custom App).

Una vez creado y publicado, accede a la sección Keys del Custom Endpoint. Copia la Connection string–primary key — la necesitarás en el paso 3.

2 Crear el Fabric Environment con las propiedades Spark

Ve a tu workspace → New item → Environment. En la sección Spark properties, añade las siguientes propiedades:

Property Value
spark.synapse.diagnostic.emitters SparkEmitter
spark.synapse.diagnostic.emitter.SparkEmitter.type AzureEventHub
spark.synapse.diagnostic.emitter.SparkEmitter.categories Log,EventLog,Metrics
spark.synapse.diagnostic.emitter.SparkEmitter.secret
spark.fabric.pools.skipStarterPools true

La propiedad SparkEmitter.categories es opcional, puedes especificar los valores o no. Entre los valores disponibles se incluyen: DriverLog, ExecutorLog, EventLog y Metrics. Si no se especifica, se establece en todas categorías.

Haz click en Save y luego en Publish. El publish puede tardar varios minutos. La integración no estará activa hasta que el environment esté en estado Published.

💡
Alternativa segura con Key Vault: Para entornos de producción, no incluyas la connection string directamente. En su lugar usa spark.synapse.diagnostic.emitter.SparkEmitter.secret.keyVault apuntando a tu Azure Key Vault URI, y .secret.keyVault.secretName con el nombre del secreto.

3 Asociar el environment al notebook o workspace

Tienes dos opciones según el alcance que necesites:

  • Por notebook: en la pestaña Home del notebook, menú Environment, selecciona el environment publicado. Se aplica en el siguiente arranque de sesión.

  • A nivel de workspace (recomendado en producción): Workspace Settings → Data Engineering/Science → Spark settings → pestaña Environment → selecciona el environment y guarda. Todos los notebooks y Spark Job Definitions del workspace usarán este environment por defecto.

4 Verificar la llegada de datos al Eventstream

Ejecuta cualquier celda del notebook para iniciar la sesión Spark. Una vez arrancado el driver, el emitter empieza a enviar eventos.

Ve al Eventstream y observa el panel de Data preview. Deberías ver mensajes JSON llegando en tiempo real. Si tras 3 minutos no ves nada, revisa que el environment esté en estado Published y que la connection string incluya EntityPath.

5 Configurar el destino Eventhouse en el Eventstream

Con el origen Custom Endpoint ya definido, añade un destino Eventhouse al Eventstream. Selecciona tu KQL Database y define la tabla de destino. Puedes usar una tabla existente o dejar que Eventstream la cree automáticamente con el schema inferido del primer mensaje.


Más allá de la configuración manual: Fabric Spark Monitoring

Todo lo que hemos visto hasta aquí — la configuración del Environment, el Eventstream, el Eventhouse y las queries KQL — es el camino manual. Es útil para entender exactamente qué ocurre en cada capa, pero en la práctica existe una solución lista para usar que automatiza toda la infraestructura y añade un dashboard de observabilidad completo.

El equipo de Fabric CAT (Customer Advisory Team) de Microsoft ha publicado Fabric Spark Monitoring, un acelerador dentro del repositorio fabric-toolbox que despliega automáticamente todo el pipeline — tablas, update policies, funciones KQL y dashboard — con la arquitectura que hemos descrito en este artículo.


Qué despliega automáticamente

La solución configura en el Eventhouse una tabla RawLogs como punto de entrada del Eventstream, y seis funciones con Update Policy que materializan los datos en tablas derivadas especializadas en el momento de la ingesta:

Tabla derivada Contenido
SparkDriverLogs Logs del proceso driver filtrados por executorId == "driver"
SparkExecutorLogs Logs de todos los executores
SparkEventLogs Ciclo de vida completo: jobs, stages, tasks con métricas raw
SparkDerivedTaskMetrics Métricas calculadas por tarea: EfficiencyRatio, GcOverheadRatio, ShuffleOverheadRatio, WasSpilled
SparkMetrics Métricas JVM con estadísticas completas: percentiles P50–P999, tasas M1/M5/M15
SparkSQLExecutionEvents Eventos SQL con plan físico de ejecución (PhysicalPlanDescription)

La clave de esta arquitectura es que el parseo del JSON ocurre una sola vez durante la ingesta, no en cada consulta del dashboard. Las tablas derivadas tienen columnas tipadas que el motor KQL puede consultar directamente sin transformaciones en tiempo de consulta.


El dashboard: tres perspectivas de observabilidad

1. Application meters — el estado en tiempo real

La vista principal agrupa en una sola pantalla los indicadores más importantes de una ejecución Spark.

Los paneles superiores muestran los contadores de resumen — stages distintos ejecutados, fallos de tareas y distribución de tareas por executor — junto con una tabla de Important Spark Properties que muestra el valor real de las propiedades de configuración durante esa ejecución (AQE habilitado, High Concurrency, Delta Optimizer, etc.).

El panel Skew per Stage visualiza los percentiles de duración de tarea (P25, P50, P75) por cada stage. Cuando el P75 es significativamente mayor que el P50, hay skew: un subconjunto de tareas tarda mucho más que el resto, señal de particiones desiguales.

Los gráficos de CPU Efficiency Ratio y Executor Memory muestran la evolución temporal de las métricas derivadas calculadas por Update_SparkDerivedTaskMetrics. El ratio de eficiencia indica qué porcentaje del tiempo de ejecución el executor pasó realmente en CPU vs esperando I/O o shuffle.

Los gráficos de Driver Mem Utilization % y Executor Mem Utilization % en la parte inferior son la respuesta visual directa a la pregunta de sizing. El gráfico superpone jvm.heap.usage y jvm.non-heap.usage. El indicador relevante para sizing es exclusivamente heap.usage — el non-heap aparece sistemáticamente cerca del 100% en todas las aplicaciones Spark por diseño de la JVM, ya que refleja las clases del framework cargadas al inicio y que permanecen en memoria durante toda la sesión. Un heap.usage sostenido por encima del 75–80% es la señal real de que el cluster está bajo presión de memoria.

jvm.heap.usage jvm.non-heap.usage Interpretación
< 40% sostenido ~100% Cluster sobredimensionado. Non-heap normal, heap con mucho margen
40–70% ~100% Bien dimensionado. Margen saludable para picos
70–85% ~100% Ajustado. Posibles GC frecuentes en picos de carga
> 85% sostenido ~100% Riesgo OOM. Reducir datos por partición o aumentar memoria del executor

2. Side by side application comparison — comparativa entre ejecuciones

Esta es la vista que implementa directamente el análisis de trending que hemos discutido. Permite seleccionar dos aplicaciones (o dos ejecuciones del mismo notebook) y comparar en paralelo todos sus indicadores.

Los paneles que se comparan simultáneamente son:

  • Driver Memory Used y Executors Memory — evolución del heap a lo largo del tiempo para detectar si una ejecución consume más memoria que la anterior con los mismos datos.

  • Executors By Time — número de executores activos en cada momento. Un pico brusco seguido de caída indica que Spark tuvo que replanificar stages por fallos.

  • Bytes Read Over Time — volumen de lectura de Delta acumulado. Si este valor crece entre ejecuciones con los mismos datos, indica que algo ha cambiado en el particionado o que hay más archivos pequeños.

  • Shuffle Metrics — tres series en el mismo gráfico: BytesRead, TotalShuffleRead y TotalShuffleWrite. La diferencia entre TotalShuffleRead y BytesRead es el multiplicador de shuffle: cuántos bytes se mueven en red por cada byte leído de la fuente.

  • GC Overhead Ratio — porcentaje del tiempo de tarea consumido en Garbage Collection. En el ejemplo se aprecia cómo este ratio arranca elevado al inicio de la sesión (JVM recién iniciada, heap aún sin calentar) y estabiliza a medida que el GC optimiza su comportamiento.

La comparativa lado a lado es especialmente útil después de aplicar cambios de optimización — aumentar spark.sql.shuffle.partitions, cambiar una estrategia de join, habilitar AQE — para cuantificar el impacto real antes de promover el cambio a producción.

3. SparkLens — recomendaciones automáticas y simulación

SparkLens es la parte más diferencial de la solución. Analiza los patrones de uso de la aplicación y genera dos tipos de salida: recomendaciones textuales sobre antipatrones detectados, y predicciones numéricas sobre el impacto de cambiar la configuración del cluster.

Información de contexto de la aplicación:

El panel superior muestra los metadatos de la ejecución — Spark Version, ApplicationId, LivyId, fabricTenantId, fabricWorkspaceId — que permiten correlacionar esta ejecución con otros sistemas de monitoreo de Fabric.

Las métricas de tiempo muestran el desglose entre Executor Wall Clock Time y Driver Wall Clock Time, y sus porcentajes sobre el tiempo total de la aplicación. En el ejemplo de la captura, el driver consume el 100% del tiempo de la aplicación con 0 tiempo de executor — una señal inequívoca de que el notebook está ejecutando código Python nativo en el driver sin distribuir trabajo a los executores.

Performance Analysis — diagnóstico con scoring:

SparkLens no solo lista recomendaciones, produce un análisis priorizado con puntuación de impacto que permite decidir qué problema abordar primero. El resumen de cabecera muestra el número de issues detectados, el tipo de job identificado y una puntuación global:

PERFORMANCE ANALYSIS: 2 Issue(s) Detected | Job Type: STREAMING
✅ OVERALL PERFORMANCE: GOOD (Score: 66/100)
CPU Efficiency: 50.7% | Parallelism: 100.0% | GC Overhead: 1.5% | Task Skew: 29.7x

El score global (66/100) integra todas las métricas en un único indicador comparable entre ejecuciones. Las cuatro métricas del pie son los ejes del análisis:

  • CPU Efficiency (50.7%): el executor pasa casi la mitad de su tiempo esperando — I/O, shuffle o bloqueado — en lugar de ejecutando código. Correlaciona directamente con el EfficiencyRatio de SparkDerivedTaskMetrics.

  • Parallelism (100%): todas las tareas disponibles se están ejecutando en paralelo, el cluster no está infrautilizado en ese sentido.

  • GC Overhead (1.5%): tiempo de JVM en Garbage Collection sobre el tiempo total de tarea. Por debajo del 5% es saludable — no hay presión de heap.

  • Task Skew (29.7x): la tarea más lenta tarda 29,7 veces más que la mediana. Es el problema dominante de esta ejecución.

Issues detectados — PRIMARY e SECONDARY:

SparkLens clasifica los problemas por severidad e impacto calculado, no por orden de aparición. Cada issue incluye causa raíz, impacto medido y acciones concretas:

🔴 PRIMARY — Data Skew en archivos de entrada (Impact Score: 240.310)

Root Cause: Landing zone has inconsistent file sizes
           64x variation (max: 109.4MB, avg: 1.72MB)
Impact:    30x task duration variance across 1887 tasks

El landing zone tiene archivos con tamaños muy dispares — la mayoría pequeños (media 1,72MB) y algunos grandes (máximo 109,4MB). En un job de streaming, Spark asigna un archivo por tarea. Las tareas con archivos grandes tardan 30 veces más que las que procesan archivos pequeños, creando un cuello de botella que bloquea la finalización del micro-batch.

Las acciones recomendadas son escalonadas por coste de implementación:

  1. Upstream: estandarizar tamaños de archivo a 128–512MB antes de que lleguen a la landing zone. Es la solución más eficaz pero requiere cambios en el productor de datos.

  2. Config: establecer maxFilesPerTrigger=50 y maxBytesPerTrigger='512MB' en el readStream para controlar el tamaño de cada micro-batch independientemente del tamaño de los archivos.

  3. Post-read: añadir .repartition(16) después del readStream para redistribuir los datos uniformemente antes de las transformaciones.

  4. Advanced: habilitar la compactación de Auto Loader si se usa el formato cloudFiles, que consolida los archivos pequeños automáticamente.

🟡 SECONDARY — Data Skew en shuffle partitions (Impact Score: 13.557)

128x variation in shuffle partition sizes
Fix: Apply salting technique to distribute hot keys

Las particiones de shuffle tienen distribución muy desigual — hay "hot keys" que concentran muchos registros en pocas particiones. La diferencia de 18x entre el impact score del issue primario (240.310) y el secundario (13.557) ilustra la utilidad del scoring: aunque ambos son problemas reales, el skew de archivos tiene 18 veces más impacto sobre la duración total y debe abordarse primero.

Predictions — simulación de cambio de configuración:

La tabla de predicciones es la funcionalidad más práctica para decisiones de sizing. Para cada combinación de número de executores y multiplicador de recursos, calcula el Estimated Executor WallClock y el Estimated Total Duration proyectados. En el ejemplo, con 1 executor al 100% la duración estimada es 22 minutos y 26 segundos — lo que permite responder directamente "¿cuánto tiempo ahorraría si duplico los executores?" sin necesidad de ejecutar el job.


Cuándo usar la solución automatizada vs la configuración manual

La configuración manual que hemos descrito en este artículo tiene sentido cuando necesitas integrar la telemetría Spark con otras fuentes de datos ya existentes en tu Eventhouse, cuando quieres personalizar el schema de las tablas derivadas o añadir columnas propias, o cuando el Eventstream tiene múltiples destinos además del Eventhouse de monitoreo.

La solución de Fabric Spark Monitoring es la opción correcta cuando el objetivo es tener observabilidad operativa desde el primer día, sin necesidad de construir la infraestructura de queries y visualización desde cero. El dashboard cubre los tres vectores de análisis que importan en producción — estado en tiempo real, comparativa entre ejecuciones y recomendaciones de sizing — con las queries ya optimizadas contra el schema de tablas derivadas.

Ambas aproximaciones son complementarias: puedes usar la solución automatizada para el dashboard de operaciones y construir queries adicionales sobre las mismas tablas derivadas para análisis específicos de tus notebooks.