Migration introduced infrastructure-level misconfigurations that caused spark executor OOM failures

When the team migrated from on-premises infrastructure to Azure Kubernetes Service (AKS), performance issues surfaced almost immediately. Spark executors began crashing with out-of-memory (OOM) errors during the most data-intensive stages. What looked like a typical Spark tuning problem turned out to be something else entirely, a byproduct of subtle infrastructure-level misconfigurations introduced during the move.

Two specific settings were at fault: enabling memory-backed local scratch directories (spark.kubernetes.local.dirs.tmpfs=true) and enforcing a hard podAffinity rule that forced all executors to run on the same physical node. Together, they redirected temporary shuffle data, large intermediate datasets Spark generates when grouping or merging information, from disk to system memory. With all executors grouped on one node, that memory filled rapidly, and the system responded by terminating processes to survive.

This experience underscores a simple truth: migrations change more than just the environment; they alter how systems behave under pressure. A configuration that worked fine on-premises can become a liability in the cloud if its dependencies or infrastructure assumptions shift. Executives planning modernization programs should ensure that all configuration changes, even minor ones, receive the same review rigor as the code itself. Minor oversights at this level can jeopardize reliability, create serious operational noise, and slow overall transformation goals.

Datadog’s monitoring confirmed the diagnosis, during shuffle-intensive stages, node memory usage spiked beyond 90 percent before executors were killed by Kubernetes’ OOM protection. Fixing these two misconfigurations restored stability without expanding hardware, highlighting that strong configuration discipline often beats hardware scaling.

Shuffle-heavy spark workloads amplify memory pressure in unexpected ways

The Spark job in question processed a relatively small three‑gigabyte input file, but the structure of that data made things more complex. Each file included multiple interleaved record layouts that required several parsing passes and union operations. Every pass created temporary data structures that Spark had to keep in memory before writing intermediate results. As those datasets multiplied, memory requirements spiked far beyond the initial three gigabytes.

This is a common pattern in enterprise data pipelines: input size alone is not a true signal of workload intensity. Shuffle work, the process of redistributing data between executors, is the most memory-demanding phase in Spark. Jobs that involve unions or joins across many partitions can multiply resource use rapidly, even with small inputs. When those shuffle stages depend on memory-backed storage (as they did here), the system quickly reaches physical memory limits.

For business leaders, there’s a strategic insight here. Performance stability in data-intensive systems depends less on the sheer amount of available memory and more on how data operations are structured. Understanding job complexity is critical before migrating or scaling production workloads. Cloud infrastructure doesn’t automatically solve inefficiencies that exist at the job design level, it amplifies them under new conditions.

Organizations that invest in profiling workloads at realistic scale gain a competitive advantage. They avoid false optimism about “lightweight” datasets and ensure that cloud resources match the true operational footprint of their jobs. That balance between accurate sizing and configuration understanding drives both stability and long-term efficiency in modern data platforms.

Okoone experts
LET'S TALK!

A project in mind?
Schedule a 30-minute meeting with us.

Senior experts helping you move faster across product, engineering, cloud & AI.

Please enter a valid business email address.

Executor colocation from podAffinity misconfiguration concentrated memory usage on one node

During the migration, a hard podAffinity rule was applied to the Spark executors. This rule instructed Kubernetes to place all four executors on the same physical node, a machine with 64 GB of RAM. In isolation, this configuration did not appear harmful; the node had sufficient nominal memory. However, Spark’s shuffle process, which redistributes data between executors, depends heavily on balanced memory use across nodes. By forcing all executors into one location, the configuration concentrated both computational and memory load into a single failure point.

The outcome was predictable: shuffle operations generated large intermediate data, all stored in-memory due to the tmpfs setting. This led to rapid memory exhaustion and Kubernetes terminating executors to prevent system instability. The team originally increased executor heap size from 8 GB to 10 GB, but node-level capacity was the true bottleneck.

For C-suite leaders, the takeaway is straightforward. Cloud infrastructure offers powerful flexibility, but default or inflexible placement rules can reduce performance efficiency rather than improve it. Resource colocation should be deliberate. Effective scheduling policies distribute pressure evenly and reduce correlated risks across workloads. Proper pod distribution helps jobs perform consistently under varying input sizes and system conditions, which is vital for maintaining predictability in high‑throughput enterprise data operations.

Correcting this misconfiguration required moving from a hard required podAffinity rule to a preferred podAntiAffinity rule. This shift ensured that executors were spread across multiple nodes, dramatically improving performance reliability without increasing compute capacity or cost. Good configuration choices often deliver better results than hardware expansion alone.

Using tmpfs (RAM) for spark local directories critically reduced memory headroom

In the original configuration, the setting spark.kubernetes.local.dirs.tmpfs=true instructed Spark to back local directories with memory. This made every temporary operation, including shuffle spill, consume node RAM. The volumes tmp-volume and workdir were each limited to just 1 GiB, leaving little capacity for intermediate data generated during shuffle-heavy jobs. Under load, these volumes quickly became saturated, consuming node memory and triggering forced termination of executors by the Kubernetes kernel.

This configuration was introduced unintentionally during migration. On-premises systems used disk-backed local storage, which provided ample space for shuffle spill and avoided memory contention. The shift to RAM-based temporary storage went unnoticed in migration review, but it fundamentally altered runtime behavior. A dataset that once executed reliably began to crash consistently, even though hardware parameters, CPU and total memory, matched the old environment.

For business executives, this incident underscores a practical truth: reliability in cloud systems depends on explicit configuration auditing, not assumptions about default behavior. Every setting carries operational consequences, and parameters such as tmpfs can convert a stable workload into a recurrent failure point if not closely examined. The key is to design configurations that reflect empirical data, the actual size, structure, and processing characteristics of production workloads.

The fix was simple but pivotal: disable tmpfs by setting it to false and move back to disk-backed volumes. Increasing the volume size from 1 GiB to 10 GiB provided ample capacity for shuffle data without compromising speed. After these adjustments, executor stability returned immediately. For leaders overseeing digital transformation initiatives, this kind of disciplined configuration work is what transforms reactive operations into predictable, scalable performance environments.

The compounding interaction of colocation and tmpfs triggered cascading executor failures

The persistent OOM failures were not the result of a single configuration flaw but the interaction of three related conditions: memory-heavy shuffle stages, forced executor colocation, and memory-backed (tmpfs) scratch directories. Each condition, taken on its own, could have been managed through typical Spark optimization or Kubernetes scheduling logic. Together, they created a cascading effect, all executors consumed the same node memory for shuffle operations, the node ran out of capacity within seconds, and Kubernetes began terminating executors to preserve node stability.

As a result, the Spark application repeatedly created replacement executors, only for them to be terminated again. This cycle continued until more than 50 executors had been created and killed, burning resources without making progress. The cluster spent more time recovering from memory exhaustion than performing actual data processing.

From a leadership perspective, the lesson is that modern cloud environments produce complex dependency chains. One misaligned setting rarely operates in isolation. Interconnected parameters can quietly amplify each other until they produce emergent failures that are difficult to trace. Effective governance of data infrastructure requires systematic validation across layers, Spark, Kubernetes, and underlying storage, to ensure that resource allocation logic functions as intended.

Once the team identified the combined impact of these factors, corrective actions were straightforward. Disabling tmpfs and redistributing executors across multiple nodes through updated anti-affinity policies stabilized the system. The number of executors returned to a consistent four per job, and job completion became predictable again. The outcome proved that addressing configuration interplay is often the most efficient path to restoring performance in production-scale systems.

Configuration and scheduling fixes fully resolved the instability without additional hardware

After confirming the root cause, the engineering team deployed targeted fixes that immediately stabilized operations. They disabled tmpfs by setting spark.kubernetes.local.dirs.tmpfs=false, expanded temporary disk volume sizes from 1 GiB to 10 GiB, and implemented a preferred podAntiAffinity rule. This allowed executors to distribute evenly across multiple nodes rather than competing for the same physical memory. These straightforward configuration changes corrected the memory imbalance and eliminated the need for additional compute nodes.

Post-fix results were decisive. Monitoring through Datadog showed node memory stabilized around 60 percent utilization during shuffle-heavy stages, while executor churn dropped to zero. The job that previously failed daily now completed in roughly one hour with consistent four-executor operation. Over the next six months, there were no further OOM incidents or on-call escalations.

For C-suite leaders, the strategic takeaway is clear: operational stability comes from precision. Throwing more hardware at complex systems is expensive and often ineffective when the underlying problem lies in configuration alignment. Well-structured diagnostics and intelligent reconfiguration yield scalable, predictable performance, often without altering infrastructure budgets.

Configuration management is an ongoing practice. Regular audits of scheduler behavior, storage allocation, and runtime parameters ensure that application demands remain in sync with infrastructure capacity. This disciplined approach keeps systems resilient while maintaining a tight cost-performance balance, a priority for any organization scaling data-driven operations in the cloud.

Root cause analysis highlighted three contributing factors linked to lift‑and‑shift cloud migration risk

The investigation revealed that the failures stemmed from three connected issues: Spark’s natural memory pressure during heavy shuffle operations, a Kubernetes scheduling rule that forced all executors onto one node, and a tmpfs configuration that made Spark write temporary data directly into memory. Each of these conditions alone would have been manageable, but their combination created an unstable environment. More importantly, all three surfaced because assumptions from the on‑premises infrastructure carried over unchanged into the cloud deployment.

This is a pattern often seen in lift‑and‑shift migrations. Teams mirror hardware specifications such as CPU and RAM, assuming identical performance will follow. In reality, cloud infrastructure has different behaviors that can drastically affect application-level performance. In this case, Kubernetes scheduling and storage semantics differed in subtle but crucial ways. The team’s expectation of one-to-one parity between the on-premises and cloud environments was misplaced.

For C‑suite executives, this point reinforces that modernization efforts must go beyond infrastructure replication. A cloud platform alters how workloads interact with memory, scheduling, and storage layers. Treating migration as a mechanical transfer overlooks these systemic differences and exposes critical workloads to new risk factors that don’t appear until systems hit scale.

The solution is a structured validation process before going live, using configuration comparison tools, environment-level parity testing, and documentation of expected behaviors under cloud conditions. By institutionalizing these checks, companies can prevent the kinds of subtle drift that disrupt even well‑established production workloads. Effective modernization demands awareness of operational context.

Pre‑migration testing failed to simulate production‑scale loads

During testing, migration validation runs used smaller datasets and less shuffle-intensive jobs. These tests completed without issue, giving a false impression of overall stability. However, when the full-scale production job executed, a complex multi-pass process involving multiple unions of parsed data, the combined effects of executor colocation and tmpfs-backed storage surfaced, leading to repeated OOM failures. Small verification runs simply did not generate enough shuffle activity to trigger the same instability.

This disconnect between test and production workloads reflects a common oversight in cloud transformations: validating only partial workloads under simplified conditions. Cloud systems behave differently at full throughput. Real data volumes activate interactions and pressures that small tests cannot reproduce. Effective testing must replicate not just sample data, but the concurrency, memory usage, and I/O intensity of production operations.

Executives should view this as a strategic reminder that infrastructure readiness cannot be measured solely by whether smaller workloads “run without error.” Production-grade reliability requires stress testing that mirrors realistic data size, frequency, and processing depth. Limited testing creates blind spots that later translate into operational disruptions, incident escalations, and potential data delivery delays.

The team learned that smaller-scale validation had masked fundamental configuration flaws that only appeared under full workload volume. After implementing full-scale testing as part of their validation pipeline, subsequent migrations captured similar issues early in staging. For organizations pursuing cloud modernization, designing realistic pre-deployment stress scenarios is an investment that prevents costly and time‑consuming post-migration firefighting.

The fixes demonstrate how careful scheduler and storage configuration prevent Spark‑on‑Kubernetes OOMs

Once the underlying problems were identified, the engineering team implemented targeted corrections that directly addressed the instability. They redefined the executor placement policy by introducing a preferred podAntiAffinity configuration, ensuring executors were distributed evenly across multiple nodes. At the same time, they disabled tmpfs to prevent the use of RAM for temporary storage and increased local volume sizes from 1 GiB to 10 GiB, allowing shuffle data to spill onto disk as intended.

These systematic and minimal adjustments transformed performance. The job that previously failed reached stable completion in one hour with its original four executors. Executor churn, which had peaked at 50 replacements per job, dropped to zero. Over six months, there were no further OOM events, despite processing the same data volume and frequency as before. Metrics from Datadog confirmed that memory use remained consistently within safe limits.

For senior executives, this outcome illustrates the return on precision engineering over expansion. Instead of scaling hardware or adding nodes, the team improved efficiency through better orchestration and resource alignment. Investing in technical understanding preserves infrastructure budgets while ensuring production reliability.

Well-defined configuration is one of the strongest levers of operational efficiency in cloud data systems. It allows teams to control performance outcomes, reduce downtime, and increase predictability without additional expenditure. As more enterprises adopt cloud-native processing, leadership should prioritize configuration audits, cross-environment validation, and continuous instrumentation as part of their standard reliability governance. These steps transform ad hoc troubleshooting into proactive system management.

Broader lessons for cloud‑native spark operations

The incident exposed a deeper reality about operating Spark in Kubernetes: the cloud is not infrastructure-neutral. Choices around storage type, scheduling policies, and volume sizing can alter how Spark behaves under heavy loads. Cloud-native abstractions such as Kubernetes’ emptyDir or persistent volumes provide flexibility, but they introduce performance trade-offs that teams must measure explicitly. Spark’s shuffle-heavy workloads are sensitive to these factors, making configuration awareness a core operational requirement rather than an afterthought.

The same applies to scheduling behavior. Kubernetes optimizes for general-purpose workloads and does not account for Spark’s unique executor and shuffle memory dynamics by default. Without deliberate configuration, scheduler decisions can inadvertently reduce performance stability. The solution lies in explicit design choices, defining pod placement, memory headroom, and disk-backed spill paths aligned to Spark’s runtime behavior.

For executives, the broader takeaway is strategic. Cloud modernization demands more than migration; it requires operating models that integrate infrastructure behavior into data engineering governance. Ensuring configuration parity between environments, validating at production scale, and continuously monitoring node memory trends build resilience and predictability. These are not technical exercises alone; they protect business continuity by reducing the probability of silent configuration drift, a common source of critical incidents in cloud ecosystems.

In a six-month observation window following these corrections, the system maintained perfect stability without additional infrastructure cost. That consistency proves that proactive configuration management can deliver both performance and efficiency at scale. For organizations accelerating digital transformation through data platforms, adapting operational practices to the realities of cloud-native infrastructure is no longer optional, it’s fundamental to sustained reliability and growth.

Post‑incident impact and longer‑term stability

After the configuration and scheduling corrections were fully deployed, the Spark pipeline returned to stable performance. The same job that had previously failed every day now completed reliably in about one hour using four executors, the same number as before the migration. There were no additional node resources, no extended compute capacity, and no new infrastructure. The improvement came entirely from better configuration control. Over the following six months, monitoring tools such as Datadog tracked zero OOM events and no unexpected executor churn.

From an operational standpoint, the transformation was clear. Node memory utilization remained predictable and below peak thresholds; the team saw no further on-call escalations or restarts. Cluster use became stable and efficient, confirming that targeted tuning, when based on evidence and system insight, can deliver reliable large‑scale performance without new investment. The system’s reliability held under production‑scale loads, proving that Spark-on-Kubernetes can be both resilient and cost-effective with the right balance of runtime and infrastructure settings.

For executives, this outcome demonstrates that stability in cloud environments depends less on infrastructure expansion and more on operational precision. Sustainable efficiency is achieved when teams maintain deep visibility into system behavior and act quickly on measurable signals. This requires leadership commitment to performance observability, cross-discipline collaboration between infrastructure and data engineering teams, and a governance model that treats configuration oversight as a continuous process.

By closing the feedback loop between observed system data and architectural configuration, the organization created a foundation for ongoing reliability. The business impact extended beyond engineering stability, predictable workloads improved downstream data availability for analysis and reporting, reducing latency and risk in data-driven decisions. This operational discipline should guide all future modernization projects: continuous review, precise configuration, and validated execution are the building blocks of dependable outcomes in large-scale cloud environments.

The bottom line

Cloud migrations are as much about awareness as they are about technology. The issues that disrupted this Spark workload weren’t caused by software bugs or resource limits, but by overlooked configuration changes. The fixes that restored stability required no new hardware, only clarity, discipline, and data‑driven validation.

For executives, the lesson is straightforward. Modern data infrastructure delivers speed and scalability, but only when configuration and governance evolve alongside it. Every system in the cloud carries hidden dependencies that can quietly shape performance and cost. Ignoring them turns predictable operations into reactive firefighting.

Executives who invest in precision, through validation pipelines, configuration audits, and performance observability, gain lasting operational leverage. They move teams from short‑term interventions to proactive control. That shift stabilizes workloads and protects business continuity and strengthens confidence in cloud investments.

Predictable performance isn’t a matter of adding power; it’s a matter of understanding how power is used. In the long term, disciplined configuration design and continuous verification will separate organizations that simply adopt the cloud from those that truly master it.

Alexander Procter

July 7, 2026

15 Min

Okoone experts
LET'S TALK!

A project in mind?
Schedule a 30-minute meeting with us.

Senior experts helping you move faster across product, engineering, cloud & AI.

Please enter a valid business email address.