FABRIC SPARK TOOLKIT
DEEP DIVE REFERENCE & MIGRATION FRAMEWORK

Microsoft Fabric Runtime 2.0 Internals

Comprehensive architectural breakdown of Microsoft Fabric Runtime 2.0 (Apache Spark 4.1, Delta Lake 4.2, Python 3.13, Java 21, Scala 2.13, Azure Linux 3.0). Covers the ANSI standard execution shift, the critical ANSI × Gluten SIMD offload trade-off, Spark Connect, Python UDAFs, and production migration runbooks.

1. Chronological Timeline of Fabric Runtimes

Understanding the component evolution across Fabric runtimes is essential when upgrading existing Lakehouse pipelines or debugging subtle behavioral discrepancies.

Runtime Version Spark Engine Delta Lake Python & Java OS & Kernel Key Architectural Milestones
Runtime 1.1 Spark 3.3.4 Delta 2.2.0 Python 3.10
Java 11
Mariner 2.0 Synapse legacy keys (spark.synapse.*), initial Fabric release baseline.
Runtime 1.2 Spark 3.4.1 Delta 2.4.0 Python 3.10
Java 11
Azure Linux 2.0 First iteration of Native Execution Engine (Gluten/Velox preview); legacy optimize write keys.
Runtime 1.3 (LTS) Spark 3.5.2 Delta 3.2.1 Python 3.11
Java 11
Azure Linux 2.0 spark.microsoft.delta.optimizeWrite.enabled standard; ANSI off by default; Liquid Clustering preview; Deletion Vectors supported.
Runtime 2.0 (GA) Spark 4.1.0 Delta 4.2.0 Python 3.13
Java 21 (LTS)
Azure Linux 3.0 ANSI default ON; Liquid Clustering GA; Spark Connect gRPC; Python UDAFs; Generational ZGC; Velox SIMD AVX-512 acceleration.

2. Architectural Blueprint: Runtime 1.3 to 2.0 Changes

Architecture: Fabric Runtime 2.0 Component Stack & Interop Layers
BASE INFRASTRUCTURE: Azure Linux 3.0 · OpenJDK 21 LTS (Generational ZGC) · GCC 13 APACHE SPARK 4.1 CORE Spark Connect gRPC Variant JSON Type ANSI Mode ON (spark.sql.ansi.enabled=true) NATIVE & STORAGE LAYERS Velox SIMD AVX-512 Delta 4.2 Liquid GA Python 3.13 UDAFs + Fast Deletion Vectors

3. The ANSI × Native Execution Engine (NEE) Conflict

The single most impactful behavioral difference in Fabric Runtime 2.0 is the interaction between ANSI SQL mode and the Native Execution Engine (Gluten/Velox).

CRITICAL PERFORMANCE TRADE-OFF: In Spark 3.5 (Runtime 1.3), ANSI mode was disabled by default (spark.sql.ansi.enabled=false). In Spark 4.1 (Runtime 2.0), ANSI mode is enabled by default. Under ANSI mode, integer overflows and invalid string-to-numeric casts throw runtime exceptions instead of returning NULL. Because Velox SIMD C++ kernels implement non-ANSI silent NULL semantics for certain operations, Gluten planner intercepts ANSI expressions and forces a fallback to JVM Janino bytecode (VeloxColumnarToRowExec), resulting in a 2x to 4x execution slowdown.
Architecture: ANSI vs Gluten SIMD Offload Decision Boundary
Incoming Query Plan SQL expression evaluation SELECT CAST(col AS INT), a + b FROM lake_table ANSI ON? (spark.sql.ansi) JVM Fallback: VeloxColumnarToRow Strict exception throwing; Janino GC overhead (2-4x slower) Native SIMD: 100% C++ Velox AVX-512 vectorized execution + zero-copy buffer transfer

How to Mitigate the ANSI vs NEE Conflict

PYSPARK RUNTIME SCOPE · ANY CELL
# Strategy 1: Use try_cast() in SQL - Preserves native SIMD acceleration under ANSI mode
df_optimized = spark.sql("""
  SELECT 
    order_id,
    try_cast(amount_raw AS DOUBLE) AS amount,
    try_cast(tax_raw AS DOUBLE) AS tax
  FROM bronze_orders
""")
# Strategy 2: For pure batch ETL pipelines where performance supersedes ANSI strictness
spark.conf.set("spark.sql.ansi.enabled", "false")

4. Interactive Migration Diagnostic Simulator

Select a code pattern to inspect the behavioral transition from Runtime 1.3 to Runtime 2.0:

Interactive Diagnostic: Code Pattern Behavior Matrix
1. Invalid Type Casting: CAST('abc' AS INT)
2. Table Optimization: CLUSTER BY (cust_id)
3. Python Aggregations: @udaf(returnType=...)
4. Remote Client: SparkConnectClient
[Runtime 1.3]: Returns NULL silently; executed via Gluten SIMD.
[Runtime 2.0 (Default)]: Throws SparkNumberFormatException; triggers JVM fallback.
[Remediation]: Replace with try_cast('abc' AS INT) to retain native Velox execution without error.

5. V-Order (spark.sql.parquet.vorder.default) — Workload Decision Matrix

Enabling V-Order globally across all workloads is a major anti-pattern in Microsoft Fabric. V-Order imposes a 10% to 15% write-time CPU & memory overhead during writes in exchange for ~20% to 40% faster read scans in Power BI Direct Lake and the Polaris SQL Endpoint.

Workload / Architecture Layer Recommended V-Order Setting Technical Rationale & Capacity Impact
Bronze / Raw Ingestion spark.sql.parquet.vorder.default = false Maximize Write Throughput: Raw data is never queried directly by Power BI. Paying 15% write CPU overhead burns capacity CUs with zero downstream benefit.
Streaming Micro-Batches spark.sql.parquet.vorder.default = false Minimize Ingestion Latency: Frequent micro-batches (5–30s triggers) suffer severe latency inflation if calculating dictionary sort orders on every batch commit.
Intermediate ETL & Scratch Staging spark.sql.parquet.vorder.default = false Transient Data: Temporary staging tables that are dropped or rewritten should never pay the V-Order encoding cost.
Silver Transformed Layer spark.sql.parquet.vorder.default = false
(Unless queried by Direct Lake)
Batch Processing: Spark queries scan columnar Parquet with native predicate pushdown and do not require V-Order dictionary layouts unless serving BI directly.
Gold Reporting & Semantic Marts spark.sql.parquet.vorder.default = true Sub-Second BI Acceleration: Essential for Power BI Direct Lake VertiPaq memory paging and high-concurrency SQL analytics endpoints.
Scheduled Off-Peak Maintenance Run OPTIMIZE gold_table Decoupled Maintenance: Delta OPTIMIZE automatically applies V-Order during off-peak compaction without impacting production ingestion SLAs.
PYSPARK RUNTIME SCOPE · ANY CELL
# Bronze / Streaming Pipeline: Disable V-Order to minimize write latency and save CUs
spark.conf.set("spark.sql.parquet.vorder.default", "false")
# Gold Aggregation Pipeline: Enable V-Order for Direct Lake sub-second dashboard queries
spark.conf.set("spark.sql.parquet.vorder.default", "true")

6. Fact-Checked Configuration Reference: When is %%configure Actually Needed?

In Microsoft Fabric, %%configure -f forces a complete kernel restart and allocates a new session. It should only be used when configuring session-locked infrastructure properties:

Configuration Setting Proper Scope Why It Belongs Here
spark.sql.adaptive.* (AQE targets) Runtime Scope (spark.conf.set) Dynamic execution rules evaluated per query. Never restart session for AQE.
spark.sql.parquet.vorder.default Runtime Scope (spark.conf.set) Toggled per ETL pipeline (disable on Bronze, enable on Gold).
delta.enableDeletionVectors Table DDL (TBLPROPERTIES) Delta metadata property; invalid inside Spark session conf.
Custom PyPI Index / Extra Packages Session-Start (%%configure) Requires pip resolution before SparkSession initialization.
Custom Pool Executor Core/Memory Sizing Session-Start (%%configure) Allocates physical JVM executor container shapes on custom pools.

7. Validated Workload Defaults & Configuration Scopes

Important Validation Finding: AQE settings such as spark.sql.adaptive.advisoryPartitionSizeInBytes and parallelismFirst are runtime-mutable SQL configurations. Putting them in %%configure -f is an anti-pattern that forces an unnecessary session restart.

In Microsoft Fabric, Starter Pools require ZERO %%configure boilerplate. All tuning should happen dynamically per-cell via spark.conf.set() or at table creation via TBLPROPERTIES.

Archetype 1: Bronze & High-Frequency Streaming Ingestion (< 50 GB)

Optimized for raw ingestion speed. Skips V-Order write overhead; uses minimal shuffle sizing.

PYSPARK RUNTIME SCOPE · ANY CELL
# Bronze / Ingestion: Maximize write throughput (Skip V-Order, tune small shuffle)
spark.conf.set("spark.sql.parquet.vorder.default", "false")
spark.conf.set("spark.sql.shuffle.partitions", "128")
SPARK SQL NOTEBOOK %%sql OR SQL ENDPOINT
-- Standard Delta Table (Optimized Write is active by default in Fabric)
CREATE TABLE bronze_telemetry (
device_id BIGINT,
timestamp TIMESTAMP,
payload STRING
) USING DELTA;

Archetype 2: Silver CDC & Heavy Merge ETL (100 GB – 1 TB)

Optimized for row mutations and incremental change tracking. Uses 128 MB write bins with Deletion Vectors.

PYSPARK RUNTIME SCOPE · ANY CELL
# Silver Merge / CDC: 128 MB bins minimize rewrite footprint during MERGE
spark.conf.set("spark.microsoft.delta.optimizeWrite.binSize", "134217728")
spark.conf.set("spark.sql.parquet.vorder.default", "false")
spark.conf.set("spark.sql.adaptive.skewJoin.skewedPartitionFactor", "5")
SPARK SQL NOTEBOOK %%sql OR SQL ENDPOINT
ALTER TABLE silver_orders SET TBLPROPERTIES (
'delta.enableDeletionVectors' = 'true',
'delta.enableChangeDataFeed' = 'true'
);

Archetype 3: Gold Layer & Direct Lake BI Serving (Consumption)

Optimized for Power BI Direct Lake VertiPaq memory paging. Uses V-Order and 512 MB file bin targets.

PYSPARK RUNTIME SCOPE · ANY CELL
# Gold Consumption: Enable V-Order for Direct Lake sub-second queries
spark.conf.set("spark.sql.parquet.vorder.default", "true")
spark.conf.set("spark.microsoft.delta.optimizeWrite.binSize", "536870912") # 512 MB bins for Direct Lake
SPARK SQL NOTEBOOK %%sql OR SQL ENDPOINT
CREATE TABLE gold_sales_mart (
sale_id BIGINT,
customer_id INT,
store_id INT,
total_amount DOUBLE
) USING DELTA
CLUSTER BY (customer_id, store_id)
TBLPROPERTIES ('delta.enableDeletionVectors' = 'true');
-- Scheduled Maintenance
OPTIMIZE gold_sales_mart;

Archetype 4: Heavy ML Prep & Wide Shuffle (> 1 TB, Cache-Heavy)

Optimized for massive distributed joins and wide shuffles. Scaled dynamically per notebook execution.

PYSPARK RUNTIME SCOPE · ANY CELL
# Large-Scale Shuffle (> 1 TB): Scale shuffle partitions and broadcast thresholds dynamically
spark.conf.set("spark.sql.shuffle.partitions", "8192")
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", "268435456") # 256 MB broadcast ceiling
spark.conf.set("spark.sql.adaptive.advisoryPartitionSizeInBytes", "134217728")