Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan

If you have been scrolling Hacker News or X this week, you have seen the same headline repeated: "Lakehouse is the future of data engineering". Companies are ripping out their old ETL pipelines and rebuilding on top of Delta Lake, Apache Iceberg, or Hudi. In that rush, a second debate is heating up behind the scenes – which execution engine will become the default for the lakehouse: Apache Spark or Apache Flink?
My hot take: Flink is already outpacing Spark for real‑time workloads, and the lakehouse community is quietly pivoting toward Flink because it solves the latency‑consistency paradox that Spark still wrestles with. If you keep betting on Spark alone, you are ignoring a wave that will reshape data engineering in the next 12‑18 months.
A lakehouse combines the low‑cost storage of an object store (S3, GCS, Azure Blob) with the transactional guarantees of a warehouse. The key promise is one copy of truth for batch and streaming. Tools like Delta Lake, Iceberg, and Hudi provide ACID semantics, schema evolution, and time travel.
From a developer’s perspective, the lakehouse eliminates the classic "batch‑only" vs "stream‑only" silos. You can write a single pipeline that ingests clickstream data, enriches it, and writes back to the same table that your BI tools query.
To make this promise real, the engine must deliver two things simultaneously:
Spark Structured Streaming achieved exactly‑once on write, but its micro‑batch model still adds a 5‑10 second tail latency. Flink, on the other hand, was built for true stream processing with a low‑latency, event‑time driven model.
Supporters of Spark point to its massive ecosystem – MLlib, GraphX, Spark SQL, and the fact that most data engineers already know PySpark or Scala Spark. The Spark community has also added Continuous Processing mode, claiming sub‑second latency.
However, Continuous Processing is still experimental, and many production teams avoid it because it requires a custom sink and lacks the rich connector catalog that Flink provides out of the box.
Netflix runs a hybrid stack: Spark for nightly feature engineering and Flink for real‑time personalization. Their public talks repeatedly mention that Spark cannot meet the 100‑ms SLA for recommendation updates, so they off‑load that to Flink.
Flink’s Watermark and State‑Backend architecture let you handle out‑of‑order events without the artificial batch windows Spark imposes. This means you can keep the lakehouse table up‑to‑date with true event time, not just processing time.
The Flink community has shipped native connectors for Apache Iceberg, Delta Lake, and Apache Hudi. These connectors support read‑write semantics with exactly‑once guarantees via the Two‑Phase Commit protocol. Spark’s Iceberg connector is solid, but Flink’s implementation is more tightly integrated with its checkpointing model.
With Flink you can keep per‑key state (e.g., user session aggregates) in a fault‑tolerant way and query that state directly from the lakehouse using Flink SQL. Spark only recently added support for stateful aggregations, and it still lags behind Flink’s performance.
Below are minimal examples of writing a simple transformation to an Iceberg table in both engines. Notice how Flink’s code stays fully streaming, while Spark falls back to a micro‑batch trigger.
scala// Spark Structured Streaming (Scala)
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
val spark = SparkSession.builder()
.appName("spark-iceberg")
.getOrCreate()
val source = spark.readStream
.format("kafka")
.option("kafka.bootstrap.servers", "kafka:9092")
.option("subscribe", "events")
.load()
val parsed = source.selectExpr("CAST(value AS STRING) as json")
.select(from_json(col("json"), schema).as("data"))
.select("data.*")
parsed.writeStream
.format("iceberg")
.option("path", "s3://lakehouse/events")
.outputMode("append")
.trigger(processingTime = "5 seconds")
.start()
.awaitTermination()
java// Flink DataStream API (Java)
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.table.api.*;
import org.apache.flink.connector.file.sink.FileSink;
import org.apache.iceberg.flink.TableLoader;
public class FlinkIceberg {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tEnv = StreamTableEnvironment.create(env);
// Kafka source
tEnv.executeSql("""
CREATE TABLE kafka_events (
user_id STRING,
event_time TIMESTAMP(3),
event_type STRING,
payload MAP<STRING, STRING>
) WITH (
'connector' = 'kafka',
'topic' = 'events',
'properties.bootstrap.servers' = 'kafka:9092',
'format' = 'json',
'scan.startup.mode' = 'earliest-offset'
)
""");
// Iceberg sink with exactly-once
tEnv.executeSql("""
CREATE TABLE iceberg_events (
user_id STRING,
event_time TIMESTAMP(3),
event_type STRING,
payload MAP<STRING, STRING>
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'my_catalog',
'catalog-type' = 'hadoop',
'warehouse' = 's3://lakehouse/',
'format-version' = '2',
'write.format.default' = 'parquet',
'streaming' = 'true'
)
""");
// Continuous insert
tEnv.executeSql("INSERT INTO iceberg_events SELECT * FROM kafka_events");
env.execute();
}
}
Key takeaways:
streaming = 'true' flag tells Iceberg to use the two‑phase commit protocol, guaranteeing exactly‑once without extra tricks.But note: even the biggest Spark proponents are now adding Flink to their stack for latency‑critical paths. The trend is hybrid, not zero‑sum.
If you are building a new data platform in 2024, start with Flink as the streaming backbone and use Spark for periodic batch enrichment or large‑scale ML training. This hybrid approach gives you the best of both worlds and positions you for the next wave of lakehouse innovations such as SQL‑based governance, real‑time materialized views, and universal catalog services.
Bottom line: The lakehouse is not a Spark‑only club. The industry is quietly shifting toward Flink for the real‑time core, and ignoring that shift will leave you stuck with higher latency, higher cost, and a less competitive data product.
The conversation is just beginning. Join the debate on X, share your experiences, and watch the lakehouse ecosystem evolve. The next big headline will likely read "Flink Powers the Real‑Time Lakehouse at Scale" – be ready to claim a front‑row seat.