Prácticas recomendadas para las grandes canalizaciones de procesamiento por lotes

En este documento se explica cómo minimizar el impacto de los errores de los trabajos en las canalizaciones de procesamiento por lotes de gran tamaño. Los errores en cargas de trabajo grandes son especialmente perjudiciales debido al tiempo y al dinero que se necesitan para recuperarse de ellos y solucionarlos. Volver a intentar estas canalizaciones desde cero cuando fallan es caro en términos de tiempo y dinero.

Para reducir los errores costosos de las canalizaciones de procesamiento por lotes, sigue las directrices de esta página. Como no siempre se pueden evitar por completo los elementos fallidos y los errores de la canalización, las técnicas proporcionadas se centran en aumentar la resiliencia, reducir el coste de los errores y facilitar la depuración y la comprensión de los errores cuando se producen.

Para consultar las prácticas recomendadas generales de las canalizaciones, consulta Prácticas recomendadas de las canalizaciones de Dataflow.

Realizar experimentos pequeños para tareas grandes

Antes de ejecutar una tarea por lotes grande, ejecuta una o varias tareas más pequeñas en un subconjunto del conjunto de datos. Esta técnica puede proporcionar una estimación de costes y ayudar a encontrar posibles puntos de fallo.

Estimación de costes

Al ejecutar experimentos, se puede obtener un precio mínimo estimado del coste total de la tarea. Normalmente, el cálculo del coste del trabajo es cost of test job*size(full dataset)/size(test dataset). En función de la canalización, el coste puede aumentar de forma superlineal o, con menos frecuencia, de forma sublineal. Sin embargo, este paso suele proporcionar una buena estimación aproximada del coste del trabajo. También puedes probar con diferentes tamaños de entrada para obtener una estimación más precisa de cómo se escalan tus costes. Utiliza esta información para decidir si quieres continuar con la canalización actual o rediseñarla para reducir costes.

Encontrar puntos de fallo

Al realizar experimentos, se pueden detectar errores, posibles puntos de fallo o posibles problemas de configuración y eficiencia. También puede consultar otras métricas de la canalización, como las siguientes:

  • Si tu canalización usa casi toda la memoria disponible, puede experimentar excepciones de falta de memoria (OOM) con una carga mayor o con registros excepcionalmente grandes. Puede que tengas que aprovisionar más memoria para el trabajo final y evitar estos errores de falta de memoria.
  • Si el rendimiento de tu flujo de procesamiento disminuye, examina los registros para determinar el motivo. Puede que encuentres un elemento atascado o una parte de tu conjunto de datos con un rendimiento especialmente bajo. Puede procesar estos puntos de datos por separado o aplicar un tiempo de espera al procesar elementos. Para obtener más información, consulta la sección Tiempo de espera de registros caros de este documento.
  • Si tu flujo de procesamiento tiene un rendimiento mucho peor en una tarea en Dataflow que de forma local, examina la lógica del flujo para averiguar por qué. Por ejemplo, si obtienes el mismo rendimiento con ocho núcleos en Dataflow que con un núcleo localmente, es posible que la tarea esté limitada por la contención de un recurso. Si observas que el rendimiento es peor de lo esperado, puedes probar una o varias de las siguientes opciones:
    • Realiza más experimentos con diferentes configuraciones de software o de máquina.
    • Prueba de forma local con varios núcleos al mismo tiempo.
    • Inspecciona el código para detectar posibles cuellos de botella al implementar a gran escala.

Si tu canalización tiene alguna recomendación de Dataflow, síguela para mejorar el rendimiento.

Usar colas de mensajes fallidos para gestionar datos incorrectos inesperados

Los pipelines suelen funcionar correctamente con la mayoría de los elementos de entrada, pero fallan con un pequeño subconjunto de la entrada. Es posible que no detectes este problema al realizar experimentos pequeños, ya que estos solo prueban un subconjunto de la entrada. De forma predeterminada, Dataflow vuelve a intentar realizar estas tareas fallidas cuatro veces en el modo por lotes y un número ilimitado de veces en el modo de streaming. En el modo por lotes, si se alcanza el límite de reintentos, toda la tarea fallará. En el modo de streaming, puede quedarse bloqueado indefinidamente.

En muchos trabajos, puedes excluir estos elementos fallidos de la canalización y completar el resto del trabajo mediante una cola de mensajes fallidos (cola de mensajes no procesados). La cola de mensajes fallidos envía los registros fallidos a una salida PCollection independiente, que puedes gestionar por separado de la salida principal. Esta configuración le permite diseñar una política para estos registros. Por ejemplo, puedes escribir los registros en Pub/Sub manualmente, inspeccionarlos y limpiarlos, y, a continuación, volver a procesarlos.

Muchas transformaciones de Apache Beam incluyen compatibilidad integrada con colas de mensajes fallidos. En Java, puedes acceder a ellos con un objeto ErrorHandler. En Python, puedes acceder a ellos mediante el método with_exception_handling. Algunas transformaciones tienen formas personalizadas de definir colas de mensajes fallidos, que puedes consultar en la documentación de la transformación. Para obtener más información, consulta Usar colas de mensajes fallidos para gestionar errores.

Para determinar si tu trabajo cumple los criterios de una cola de mensajes fallidos, consulta la sección Limitaciones de este documento.

Limitaciones de las colas de mensajes fallidos

En los siguientes casos, una cola de mensajes fallidos puede no ser útil:

  • Fallos en el ciclo de vida completo del trabajador o de DoFn. Si el procesamiento falla en todo el trabajador o paquete, una cola de mensajes fallidos no puede detectar el error. Por ejemplo, si tu canal se encuentra con una excepción de falta de memoria (OOM), todas las tareas activas de la VM fallarán y se volverán a intentar, sin enviar nada a la cola de mensajes fallidos.
  • Combinaciones u otras agregaciones. Si tu canalización realiza cálculos que requieren que todos los elementos de entrada estén presentes y se procesen como parte del resultado, ten cuidado al usar una cola de mensajes fallidos antes de este paso. Si usas una cola de mensajes fallidos, se excluirá parte de los datos de entrada del resultado. Si añades una cola de mensajes fallidos, es posible que sacrifiques la corrección en favor de la tolerancia a fallos.
  • Errores en la ruta de la cola de mensajes fallidos. Si falla un elemento mientras se envía al receptor de la cola de mensajes fallidos, puede fallar toda la canalización. Para evitar este error, mantén la lógica de la cola de mensajes fallidos lo más básica posible. Puedes añadir un paso de espera (consulta el wait class) para asegurarte de que la entrada principal finalice antes de escribir los elementos de la cola de mensajes fallidos. Esta configuración puede reducir el rendimiento y retrasar las señales de error de tu canal.
  • Elementos transformados parcialmente. Si insertas una cola de mensajes fallidos en mitad de tu canalización, es posible que la cola de mensajes fallidos genere el elemento parcialmente transformado y no tenga acceso al elemento original. Por lo tanto, no puedes limpiar el elemento y volver a ejecutar la canalización en él. En su lugar, es posible que tengas que aplicar una lógica diferente para correlacionar la salida de la cola de mensajes fallidos con el elemento original o interpretar y procesar el elemento parcialmente transformado. También puede dar lugar a resultados incoherentes. Por ejemplo, si los elementos se envían por dos ramas de una canalización y cada rama envía elementos que provocan excepciones a una cola de mensajes fallidos, un solo elemento de entrada puede llegar a una, a otra, a ambas o a ninguna de las ramas.

Tiempo de espera de registros caros

Es posible que las canalizaciones dejen de responder mientras procesan un pequeño subconjunto de elementos que son más caros o que alcanzan una limitación que provoca que no respondan, como un bloqueo. Para mitigar este problema, algunas transformaciones te permiten definir un tiempo de espera y fallar los elementos que superen ese tiempo en cualquier DoFn de código de usuario que se encuentre con este problema. Por ejemplo, puedes usar el método with_exception_handling de Python. Cuando usas tiempos de espera con una cola de mensajes fallidos, tu canalización puede seguir procesando elementos correctos y avanzar, y puedes volver a procesar los elementos costosos por separado. Esta configuración puede suponer un coste en términos de rendimiento.

Para determinar qué operaciones de DoFn es probable que requieran un tiempo de espera, realiza pequeños experimentos antes de lanzar tu canalización completa.

Habilitar el autoescalado vertical

Si no sabes cuánta memoria necesita tu trabajo o crees que corre el riesgo de quedarse sin memoria, habilita el escalado automático vertical. Esta función ayuda a evitar errores de falta de memoria cuando las canalizaciones se ejecutan a mayor escala o cuando se encuentran elementos excepcionalmente grandes.

Como el escalado automático vertical puede aumentar el coste de tu trabajo y no evita todos los errores por falta de memoria, debes solucionar los problemas de consumo excesivo de memoria. El autoescalado vertical también requiere Dataflow Prime, que tiene limitaciones adicionales y un modelo de facturación diferente.

Soluciones alternativas para las canalizaciones propensas a errores

Algunas canalizaciones son especialmente propensas a errores. Aunque es mejor solucionar la causa de estos errores, para reducir el coste de los fallos, puedes probar las siguientes opciones.

Materializar resultados intermedios

Las canalizaciones pueden tener una o varias transformaciones especialmente costosas que dominen el tiempo de ejecución de la canalización. Los errores de la canalización después de esta transformación pueden ser especialmente perjudiciales, ya que se pierde todo el trabajo que ya se ha completado. Para evitar esta situación, puedes escribir los PCollections intermedios generados por pasos costosos en un receptor como Cloud Storage. Esta configuración reduce el coste de un fallo. Debes sopesar esta ventaja con el coste de realizar la escritura adicional. Puedes usar este resultado materializado de una de las siguientes formas:

  1. Divide tu flujo de procesamiento original en dos: uno que escriba el resultado intermedio y otro que lo lea.
  2. Solo si falla la canalización, lee y aplana los resultados de tu fuente original y de tu colección intermedia materializada.

Para asegurarse de que estas materializaciones se escriban antes de que se lleve a cabo el resto del procesamiento, añada un paso de espera (consulte el wait class) antes de cualquier otro paso de procesamiento.