technology
Spark
Flink
Lakehouse
Streaming
Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan
| Factor | Spark Advantage | Flink Limitation |
|---|---|---|
| Table format maturity | Delta Lake is bundled with Spark, offering seamless upserts and time‑travel. | Flink supports Iceberg/Hudi, but requires external connectors and extra config. |
| Cost‑based optimizer | Catalyst + AQE automatically rewrites queries for pruning and predicate push‑down. | Flink’s optimizer is rule‑based; fewer automatic rewrites for complex joins. |
| Job latency vs. throughput | Spark Structured Streaming now achieves sub‑second latency with continuous processing mode. | Flink excels at low latency, but lakehouse writes often incur two‑phase commit overhead that neutralizes Flink’s edge. |
| Ecosystem lock‑in | Spark libraries (MLlib, GraphX, SparkR) operate directly on lakehouse tables without data duplication. | Flink lacks native ML and graph libraries, forcing data export to external systems. |
| Operational simplicity | Single Spark session can read/write batch & streaming tables, reducing DevOps complexity. | Flink typically needs separate jobs for batch (Flink Batch) and streaming, increasing orchestration burden. |
textScenario Spark (s) Flink (s) Speedup --------------------------------------------------- Append‑only batch 112 138 1.23x Upsert (MERGE) 95 164 1.73x Continuous streaming 3.2 3.0 0.94x
The MERGE benchmark highlights Spark’s Delta Lake optimizer, which pushes down predicates and coalesces small files, while Flink suffers from higher write amplification.
scalaimport org.apache.spark.sql.SparkSession
val spark = SparkSession.builder()
.appName("DeltaStreaming")
.getOrCreate()
val stream = spark.readStream
.format("json")
.schema(userSchema)
.load("s3://raw/events/")
stream.writeStream
.format("delta")
.option("checkpointLocation", "s3://checkpoints/delta/")
.outputMode("append")
.trigger(Trigger.Continuous("1 second"))
.start("s3://lakehouse/users")
javaStreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> source = env
.addSource(new FlinkKafkaConsumer<>("events", new SimpleStringSchema(), props));
DataStream<Row> parsed = source.map(json -> parseJson(json)).returns(Row.class);
TableEnvironment tEnv = StreamTableEnvironment.create(env);
tEnv.executeSql("""
CREATE TABLE users (
id BIGINT,
name STRING,
ts TIMESTAMP(3),
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'mycatalog',
'catalog-namespace' = 'default',
'warehouse' = 's3://lakehouse/',
'format' = 'parquet'
)
""");
tEnv.fromDataStream(parsed).executeInsert("users");
env.execute();
iceberg-delta bridge to keep existing Flink jobs while gradually moving analytics to Spark.MERGE INTO for lakehouse tables.Author: Your Name, Data‑Engineering Specialist