En ocasiones, al ejecutar un paquete SSIS que tiene como origen nuestro flamante servidor con mucha RAM y un muy buen disco vemos que no funciona tan rápido como podríamos esperar. De hecho, nosotros hemos diseñado bien el paquete y todas las transformaciones funcionan, no estamos utilizando transformaciones bloqueantes porque sabemos que penalizan mucho el rendimiento, y hemos intentado optimizar el rendimiento pero aún así no hemos conseguido mejorarlo… ¡la culpa es del origen de datos! ¡Nos han estafado con el servidor! Tomemos la situación con un poco de calma antes de culpar a nuestro origen de datos porque probablemente estemos delante de un caso de backpressure. El backpressure es un fenómeno que ocurre en Integration Services cuando tenemos una o varias transformaciones que trabajan con los datos más lentamente que el origen que las provee de datos.Para entender el concepto pensemos en una tubería de agua. Si tenemos una boca de riego que nos da cierto caudal y la tubería está intacta, es recta y sin ningún tipo de obstáculo, el agua saldrá por el otro extremo de la tubería con la misma presión y caudal con el que entró en la misma. Ahora bien, imaginemos que tenemos algún obstáculo intermedio, como puede ser un recodo en el camino o residuos acumulados a lo largo del tiempo. Si recordamos las lecciones de física del instituto o la universidad donde nos contaban que los líquidos eran incompresibles concluiremos que el flujo de agua se ralentizará desde el mismo origen porque no puede fluir con el máximo caudal posible. Ahora se entiende que el por qué del nombre del fenómeno, pues podríamos decir que se produce una “presión hacia atrás” desde el obstáculo que ralentiza el flujo hacia el origen de donde viene el mismo.
Pasemos este concepto ahora a nuestro flujo de datos de SSIS. Tendremos un origen muy rápido y “obstáculos” en el camino, es decir, transformaciones que no pueden trabajar con los datos tan rápido como les son servidos. Cuando se produce esta situación, SSIS la detecta y lee más lentamente de los orígenes de datos para adaptar la velocidad de proceso de los datos a la transformación más lenta. Ahora os podréis preguntar ¿y por qué no se limita a simplemente leer todos los datos y dejarlos en el buffer de entrada de la tarea más lenta para que los vaya tratando y se despreocupa? Pues esto es porque el equipo de diseño de SSIS vio que esta alternativa sólo produciría una carga excesiva e innecesaria de memoria, así que se optó por ajustar la velocidad global para permitir que se vayan liberando la mayor cantidad de buffers posibles durante la ejecución del flujo de datos (siempre y cuando no tengamos transformaciones totalmente bloqueantes.
Demostración
Basta de teorías y vamos a lo que nos interesa, la demostración práctica. Tenemos un paquete de ejemplo con 4 Script Component simulando 4 transformaciones diferentes. A saber:
- Un origen de datos muy rápido.
- Una transformación igual de rápida que el origen.
- Una transformación lenta que penaliza el flujo completo.
- Un destino trash.
Las funciones sobre las que haremos override en cada una de las transformaciones son:
Origen rápido
public override void CreateNewOutputRows() { for (int i = 0; i < 1000000; i++) { Salida0Buffer.AddRow(); } }
Transformacion estandar
public override void Entrada0_ProcessInputRow(Entrada0Buffer Row) { Salida0Buffer.AddRow(); }
Transformacion costosa
public override void Entrada0_ProcessInputRow(Entrada0Buffer Row) { System.Threading.Thread.SpinWait(10000); }
La clave está en forzar la simulación de 10.000 iteraciones con el comando SpinWait en el componente “Transformación Costosa” para ralentizar el flujo de datos.
En este caso concreto, cuando sabemos dónde se encuentra el elemento que causa el backpressure, podríamos verlo claramente simplemente eliminando el componente del flujo y ejecutando para comprar tiempos. En entornos reales, esto no es viable ya que probablemente tengamos un paquete de carga de nuestra tabla de hechos con, pongamos, 50 componentes. Si tuviésemos que quitarlos uno a uno para ir probando ejecuciones sería una auténtica locura.
Por suerte, en SSIS 2008 podemos detectar el backpressure utilizando los elementos del registro de eventos. Para activar el registro de eventos:
- Situados en el Control Flow, click derecho sobre el fondo y pinchamos en Registro (o Logging si tenemos la versión en inglés)
- Una vez aquí, seleccionamos nuestro DataFlow donde sospechamos que podemos tener backpressure y seleccionamos el objeto de evento PipelineComponentTime.
Ahora ejecutamos nuestro paquete y, a su finalización, examinamos lo que tenemos en el log de eventos:
Marcados en rojo tenemos los dos mensajes que nos indican que tenemos en nuestro paquete SSIS un caso de backpressure. Uno de los dos mensajes dice:
“Durante la última ejecución, la canalización suspendió salida “Salida 0” (26) de componente “Origen rapido” (23) durante 51761 milisegundos para limitar el número de búferes en memoria.”
Refleja exactamente lo que comentábamos con anterioridad, la ralentización que SSIS aplica al flujo completo para evitar sobrecargas innecesarias de datos en memoria. También podemos ver aquí qué componente está causando el backpressure, en este caso aquel que esté después del último componente que aparezca con su salida ralentizada. Como vemos en la captura, será el componente que posterior en el flujo de datos a “Transformación Estándar”, es decir, “Transformación Costosa”.
Esto, que nosotros ya sabíamos porque partíamos con la ventaja de provocar el fenómeno intencionadamente, lo tenemos ahora evidenciado en el registro de tal manera que podremos aplicar este método de detección a cualquier otro paquete aunque tenga una lógica mucho más compleja.
La reducción o eliminación de este fenómeno pasa por un rediseño del paquete, ya sea aplicando una lógica diferente (dividiendo en varios pasos, optimizando la configuración del componente que causen el backpressure, etc.) o aplicando técnicas de paralelismo a nivel de DataFlow Task, ya que son justamente estas circunstancias (origen muy rápido, transformaciones costosas que no trabajan al mismo ritmo que el origen) las más susceptibles a beneficiarse del paralelismo que SSIS puede proporcionar.
Feliz tuning de cargas 🙂