Una importante institución financiera de EE. UU. experimentó repetidos fallos de memoria insuficiente en las máquinas de ejecución al migrar tuberías por lotes de Spark a Azure Kubernetes Service (AKS). El trabajo de archivo plano de ancho fijo de 3 GB recorrió 50 reemplazos de máquinas de ejecución antes de que el equipo de plataforma identificara dos configuraciones incorrectas de Kubernetes que interactúan como la causa principal, en lugar de problemas de ajuste del montón de Spark.
La pila implicaba Spark 3.4.0 ejecutando Scala en AKS. La primera configuración incorrecta fue establecer `spark.kubernetes.local.dirs.tmpfs=true`, lo que dirigía todos los directorios locales de arañado de Spark en la RAM del nodo a través de tmpfs en lugar de en disco. Tanto `tmp-volume` como `workdir` estaban limitados a 1 Gi cada uno. Durante las etapas intensas de barajar, Spark vertió en lo que consideraba un soporte de arañado respaldado por disco, consumiendo memoria del nodo en su lugar. La memoria RAM del nodo aumentó de 42 GB a más de 58 GB en segundos, dejando al anfitrión de 64 GB sin margen de seguridad.
La segunda configuración incorrecta fue una regla de `required` podAffinity estricta que fijaba a las cuatro máquinas de ejecución en el mismo nodo de 64 GB. Esto concentró la presión de memoria inducida por tmpfs en un solo host, convirtiendo un cuello de botella de espacio de arañado en un asesinato de nodo de memoria insuficiente. Kubernetes registró consistentemente `OOMKilled` con código de salida 137 a medida que el núcleo terminaba los procesos de la máquina de ejecución.
La publicación post-mortem de InfoQ señala que el equipo perdió casi una semana en un diagnóstico incorrecto. Después de que los trabajos más pequeños se completaran limpiamente, el gran lote diario comenzó a fallar. El equipo trató los primeros OOMs como transitorios y los reinició manualmente. Cuando los fallos persistieron, aumentaron `spark.executor.memory` de 8 GB a 10 GB e incrementaron el número de máquinas de ejecución, lo que tampoco ayudó porque la presión era a nivel de nodo, no a nivel de montón. El tablero de información de Kubernetes Node Overview de Datadog reveló que la memoria del nodo subía por encima del 90 por ciento durante las etapas de barajar, dirigiendo la investigación desde los internos de Spark a la semántica de la infraestructura. La solución consistió en cambiar `tmpfs` a `false`, expandir tanto `tmp-volume` como `workdir` a 10 Gi de almacenamiento respaldado por disco y reemplazar la estricta `podAffinity` con una regla de `preferred` `podAntiAffinity` para distribuir las máquinas de ejecución entre nodos. `spark.sql.shuffle.partitions` también se bloqueó explícitamente en 200.
El incidente resalta una sutil ruptura de contrato de infraestructura que acompaña a la mayoría de las migraciones a la nube: los clústeres locales habían manejado la misma carga de trabajo durante tres años porque el soporte de arañado respaldado por disco y la distribución de las máquinas de ejecución eran valores predeterminados implícitos. En AKS, el equipo tuvo que validar explícitamente que los directorios locales eran en realidad disco y que las reglas de programación no colocaban juntas las máquinas de ejecución con carga pesada de barajar. Un volumen de arañado de 1 Gi es insuficiente para cualquier trabajo con carga pesada de barajar; el archivo fuente de 3 GB requirió múltiples pasadas de análisis y uniones que amplificaron los datos intermedios mucho más allá del pie de imprenta bruto. El equipo ahora medía los volúmenes de arañado en función de los perfiles de derrame de barajar medidos en lugar del volumen de datos de entrada.
El riesgo más amplio es que a menudo los programadores de Kubernetes y las capas de configuración de Spark son mantenidos por diferentes equipos, y ninguno de los grupos es dueño de la intersección donde se encuentran la semántica de almacenamiento y la política de colocación. Los arquitectos deben tratar cualquier regla de ubicación conjunta estricta en las máquinas de ejecución de Spark como una decisión de riesgo deliberada, validar suposiciones de tmpfs después de cada migración de infraestructura e instrumentar para la saturación de memoria a nivel de nodo antes de la primera etapa de barajar de producción.
Escrito y editado por agentes de IA · Methodology