Capítulo 4. Apache Spark como motor de procesamiento de flujos

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

En el Capítulo 3, en dibujamos un diagrama arquitectónico general de una plataforma de streaming de datos e identificamos dónde encaja Spark, como motor de procesamiento distribuido, en un sistema de big data.

Esta arquitectura nos informó sobre lo que podíamos esperar en cuanto a interfaces y enlaces con el resto del ecosistema, especialmente al centrarnos en el procesamiento de datos en flujo con Apache Spark. El procesamiento en flujo, ya sea en su encarnación Spark Streaming o Structured Streaming, es otro modo de ejecución de Apache Spark.

En este capítulo, hacemos un recorrido por las principales características que hacen que Spark destaque como motor de procesamiento de flujos.

La historia de dos API

Como mencionamos en "Presentación de Apache Spark", Spark ofrece dos API de procesamiento de flujos diferentes, Spark Streaming y Structured Streaming:

Spark Streaming

Este es una API y un conjunto de conectores, en los que a un programa Spark se le sirven pequeños lotes de datos recogidos de un flujo en forma de microlotes espaciados a intervalos de tiempo fijos, realiza un cálculo determinado y, finalmente, devuelve un resultado en cada intervalo.

Streaming estructurado

Este es una API y un conjunto de conectores, construidos sobre el sustrato de un optimizador de consultas SQL, Catalyst. Ofrece una API basada en DataFrames y en la noción de consultas continuas sobre una tabla ilimitada que se actualiza constantemente con registros frescos del flujo.

La interfaz que ofrece Spark en estos frentes es particularmente rica, hasta el punto de que este libro dedica grandes partes a explicar esas dos formas de procesar conjuntos de datos en streaming. Un punto importante que hay que tener en cuenta es que ambas API se basan en las capacidades básicas de Spark y comparten muchas de las características de bajo nivel en términos de computación distribuida, almacenamiento en caché en memoria e interacciones de clúster.

Como salto adelante respecto a su predecesor MapReduce , Spark ofrece un rico conjunto de operadores que permite al programador expresar procesamientos complejos, incluido el aprendizaje automático o las manipulaciones en tiempo de eventos. Examinaremos más concretamente las propiedades básicas que permiten a Spark realizar esta hazaña dentro de un momento.

Sólo nos gustaría destacar que estas interfaces son, por su diseño, tan sencillas como sus homólogas por lotes: operar en un DStream es como operar en un RDD, y operar en un Dataframe de streaming se parece inquietantemente a operar en uno por lotes.

Apache Spark se presenta como un motor unificado, que ofrece a los desarrolladores un entorno consistente siempre que quieran desarrollar una aplicación batch o de streaming. En ambos casos, los desarrolladores tienen a mano toda la potencia y velocidad de un marco distribuido.

Antes de implementar una aplicación de procesamiento de flujos completa, los programadores y analistas primero intentan descubrir ideas en entornos interactivos con un rápido bucle de retroalimentación. Spark ofrece un shell integrado, basado en el REPL de Scala (abreviatura de Read-Eval-Print-Loop) que puede utilizarse como base para la creación de prototipos. Hay varias implementaciones de cuadernos disponibles, como Zeppelin, Jupyter o el cuaderno Spark, que llevan esta experiencia interactiva a una interfaz web fácil de usar. Esta fase de creación de prototipos es esencial en las primeras fases del desarrollo, y también lo es su velocidad.

Si vuelves al diagrama de la Figura 3-1, te darás cuenta de que lo que llamamos resultados en el gráfico son conocimientos procesables -que a menudo significan ingresos o ahorro de costes- que se generan cada vez que se recorre por completo un bucle (que empieza y termina en el problema empresarial o científico). En resumen, este bucle es una burda representación del método experimental, que pasa por la observación, la hipótesis, el experimento, la medida, la interpretación y la conclusión.

Apache Spark, en sus módulos de streaming, siempre ha optado por gestionar cuidadosamente la carga cognitiva de cambiar a una aplicación de streaming. También tiene otras opciones de diseño importantes que influyen en sus capacidades de procesamiento de streaming, empezando por su almacenamiento en memoria.

Uso de memoria de Spark

Spark ofrece almacenamiento en memoria de trozos de un conjunto de datos, que deben cargarse inicialmente desde una fuente de datos. La fuente de datos puede ser un sistema de archivos distribuido u otro medio de almacenamiento. La forma de almacenamiento en memoria de Spark es análoga a la operación de almacenar datos en caché.

Por tanto, un valor en el almacenamiento en memoria de Spark tiene una base, que es su fuente de datos inicial, y capas de operaciones sucesivas que se le aplican.

Recuperación de fallos

¿Qué ocurre en caso de fallo? Dado que Spark sabe exactamente qué fuente de datos se utilizó para ingerir los datos en primer lugar, y dado que también conoce todas las operaciones que se realizaron sobre ella hasta ese momento, puede reconstituir desde cero el segmento de datos perdidos que se encontraba en un ejecutor averiado. Obviamente, esto va más rápido si esa reconstitución(recuperación, en la jerga de Spark), no tiene que ser totalmente desde cero. Así pues, Spark ofrece un mecanismo de replicación, de forma bastante similar a los sistemas de archivos distribuidos.

Sin embargo, como la memoria es un bien tan valioso aunque limitado, Spark hace (por defecto) que la caché dure poco.

Evaluación perezosa

Como verás con más detalle en en capítulos posteriores, buena parte de las operaciones que pueden definirse sobre valores del almacenamiento de Spark tienen una ejecución perezosa, y es la ejecución de una operación de salida final, ansiosa, la que desencadenará la ejecución real de la computación en un clúster Spark. Merece la pena señalar que si un programa consiste en una serie de operaciones lineales, en las que la anterior alimenta a la siguiente, los resultados intermedios desaparecen justo después de que dicho paso siguiente haya consumido su entrada.

Sugerencias para la caché

Por otro lado, en, ¿qué ocurre si tenemos que realizar varias operaciones sobre un único resultado intermedio? ¿Deberíamos calcularlo varias veces? Afortunadamente, Spark permite a los usuarios especificar que un valor intermedio es importante y cómo debe salvaguardarse su contenido para más adelante.

La Figura 4-1 presenta el flujo de datos de una operación de este tipo.

spas 0401
Figura 4-1. Operaciones con valores almacenados en caché

Por último, Spark ofrece la posibilidad de derramar la caché al almacenamiento secundario en caso de que se quede sin memoria en el clúster, extendiendo la operación en memoria al almacenamiento secundario -y significativamente más lento- para preservar los aspectos funcionales de un proceso de datos cuando se enfrenta a picos temporales de carga.

Ahora que tenemos una idea de las principales características de Apache Spark, vamos a dedicar algo de tiempo a centrarnos en una elección de diseño interna de Spark, a saber, el equilibrio entre latencia y rendimiento.

Comprender la latencia

Spark Streaming, como mencionamos en, opta por el microbatching. Genera un trozo de elementos en un intervalo fijo, y cuando transcurre ese "tick" de intervalo, comienza a procesar los datos recogidos en el último intervalo. Structured Streaming adopta un enfoque ligeramente diferente, en el sentido de que hará que el intervalo en cuestión sea lo más pequeño posible (el tiempo de procesamiento del último microbatch), y proponiendo, en algunos casos, también un modo de procesamiento continuo. Sin embargo, hoy en día, el microbatching sigue siendo el modo de ejecución interna dominante del procesamiento de flujos en Apache Spark.

Una consecuencia de la micromezcla es que cualquier micromezcla retrasa el procesamiento de cualquier elemento concreto de un lote al menos el tiempo del intervalo del lote.

En primer lugar, los microlotes crean una latencia de referencia. El jurado aún no ha decidido hasta qué punto es posible reducir esta latencia, aunque aproximadamente un segundo es una cifra relativamente común para el límite inferior. Para muchas aplicaciones, una latencia de unos minutos es suficiente; por ejemplo:

  • Disponer de un panel de control que te refresca los indicadores clave de rendimiento de tu sitio web en los últimos minutos

  • Extraer los trending topics más recientes en una red social

  • Cálculo de las tendencias de consumo energético de un grupo de hogares

  • Introducir nuevos medios en un sistema de recomendación

Mientras que Spark es un procesador de igualdad de oportunidades y retrasa todos los elementos de datos durante (como máximo) un lote antes de actuar sobre ellos, existen algunos otros motores de flujo que pueden acelerar algunos elementos que tienen prioridad, garantizando una respuesta más rápida para ellos. Si tu tiempo de respuesta es esencial para estos elementos específicos, los procesadores de flujo alternativos, como Apache Flink o Apache Storm, podrían ser más adecuados. Pero si sólo te interesa un procesamiento rápido de media, como cuando monitorizas un sistema, Spark es una propuesta interesante.

Procesamiento orientado al rendimiento

En definitiva, en, donde Spark destaca realmente en el procesamiento de flujos es en el análisis de datos orientado al rendimiento.

Podemos comparar el enfoque de microlote con un tren: llega a la estación, espera a los pasajeros durante un periodo de tiempo determinado y luego transporta a todos los pasajeros que subieron a su destino. Aunque coger un coche o un taxi para la misma trayectoria podría permitir a un pasajero viajar más rápido de puerta a puerta, el lote de pasajeros del tren garantiza que lleguen a su destino muchos más viajeros. El tren ofrece un mayor rendimiento para la misma trayectoria, a costa de que algunos pasajeros deban esperar hasta que el tren parta.

El motor central de Spark está optimizado para el procesamiento distribuido por lotes. Su aplicación en un contexto de streaming garantiza que se puedan procesar grandes cantidades de datos por unidad de tiempo. Spark amortiza la sobrecarga de la programación de tareas distribuidas al disponer de muchos elementos para procesar a la vez y, como vimos anteriormente en este capítulo, utiliza técnicas en memoria, optimizaciones de consultas, almacenamiento en caché e incluso generación de código para acelerar el proceso de transformación de un conjunto de datos.

Cuando se utiliza Spark en una aplicación de extremo a extremo, una restricción importante es que los sistemas descendentes que reciben los datos procesados también deben ser capaces de aceptar la salida completa proporcionada por el proceso de streaming. De lo contrario, corremos el riesgo de crear cuellos de botella en la aplicación que podrían causar fallos en cascada cuando se enfrenten a picos de carga repentinos.

La API políglota de Spark

Ya hemos esbozado los principales fundamentos de diseño de Apache Spark en lo que afecta al procesamiento de flujos, a saber, una rica API y un modelo de procesamiento en memoria, definido dentro del modelo de un motor de ejecución. Hemos explorado los modos específicos de procesamiento de flujos de Apache Spark, y aún a alto nivel, hemos determinado que el predominio del microbatching nos hace pensar que Spark está más adaptado a tareas orientadas al rendimiento, para las que más datos producen más calidad. Ahora queremos llamar nuestra atención sobre un aspecto adicional en el que Spark brilla: su ecosistema de programación.

Spark se codificó en un principio como un proyecto exclusivo de Scala. A medida que aumentaba su interés y adopción, también lo hacía la necesidad de dar soporte a distintos perfiles de usuarios, con diferentes antecedentes y conocimientos de lenguajes de programación. En el mundo del análisis científico de datos, Python y R son posiblemente los lenguajes predominantes, mientras que en el entorno empresarial, Java ocupa una posición dominante.

Spark, lejos de ser sólo una biblioteca para distribuir computación, se ha convertido en un marco políglota con el que el usuario puede interactuar utilizando Scala, Java, Python o el lenguaje R. El lenguaje de desarrollo sigue siendo Scala, y aquí es donde aparecen las principales innovaciones.

Precaución

La cobertura de la API de Java ha estado durante mucho tiempo bastante sincronizada con Scala, debido a la excelente compatibilidad con Java que ofrece el lenguaje Scala. Y aunque en Spark 1.3 y versiones anteriores Python iba a la zaga en cuanto a funcionalidades, ahora se ha puesto al día en su mayor parte. La última incorporación es R, para el que la compleción de funciones es un entusiasta trabajo en curso.

Esta versátil interfaz ha permitido que programadores de diversos niveles y formación acudan en masa a Spark para implementar sus propias necesidades de análisis de datos. La asombrosa y creciente riqueza de las contribuciones al proyecto de código abierto Spark son un testimonio de la fuerza de Spark como marco federador.

Sin embargo, el enfoque de Spark para atender mejor la informática de sus usuarios va más allá de dejarles utilizar su lenguaje de programación favorito.

Implementación rápida del análisis de datos

Las ventajas de Spark en el desarrollo de una canalización de análisis de datos en flujo van más allá de ofrecer una API concisa y de alto nivel en Scala y API compatibles en Java y Python. También ofrece el modelo sencillo de Spark como un atajo práctico a lo largo del proceso de desarrollo.

Reutilización de componentes con Spark es un activo valioso, como lo es el acceso al ecosistema Java de bibliotecas para el aprendizaje automático y muchos otros campos. Como ejemplo, Spark permite a los usuarios beneficiarse, por ejemplo, de la biblioteca Stanford CoreNLP con facilidad, permitiéndote evitar la penosa tarea de escribir un tokenizador. En definitiva, esto te permite crear rápidamente un prototipo de tu solución de canalización de datos en flujo, obteniendo los primeros resultados con la rapidez suficiente para elegir los componentes adecuados en cada paso del desarrollo de la canalización.

Por último, el procesamiento de flujos con Spark te permite beneficiarte de su modelo de tolerancia a fallos, que te da la confianza de que las máquinas defectuosas no van a poner de rodillas la aplicación de flujo. Si has disfrutado del reinicio automático de trabajos Spark fallidos, apreciarás doblemente esa capacidad de recuperación al ejecutar una operación de flujo 24/7.

En conclusión, Spark es un marco que, aunque hace concesiones en cuanto a latencia, optimiza la construcción de un canal de análisis de datos con agilidad: la creación rápida de prototipos en un entorno rico y el rendimiento estable en tiempo de ejecución en condiciones adversas son problemas que reconoce y aborda de frente, ofreciendo a los usuarios ventajas significativas.

Más información sobre Spark

Este libro de se centra en el streaming. Como tal, nos movemos rápidamente a través de los conceptos centrados en Spark, en particular sobre el procesamiento por lotes. Las referencias más detalladas son [Karau2015] y [Chambers2018].

En un enfoque de más bajo nivel, la documentación oficial de la guía de programación de Spark es otra lectura obligada accesible.

Resumen

En este capítulo has aprendido sobre Spark y su origen.

  • Ya has visto cómo Spark amplía ese modelo con mejoras clave en el rendimiento, sobre todo en la computación en memoria, así como cómo amplía la API con nuevas funciones de orden superior.

  • También consideramos cómo se integra Spark en el ecosistema moderno de soluciones de big data, incluido el menor espacio que ocupa, en comparación con su hermano mayor, Hadoop.

  • Nos hemos centrado en las API de streaming y, en particular, en el significado de su enfoque de micromezcla, para qué usos son adecuadas, así como las aplicaciones a las que no servirían bien.

  • Por último, consideramos el procesamiento de flujos en el contexto de Spark, y cómo la construcción de una canalización con agilidad, junto con una implementación fiable y tolerante a fallos es su mejor caso de uso.

Get Procesamiento de flujos con Apache Spark now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.