Flink vs Spark Structured Streaming vs Kafka Streams
В 2026 году stream processing — насыщенная экосистема. Apache Flink, Spark Structured Streaming, Kafka Streams — три самых популярных open source фреймворка с миллионами production deployments. Каждый имеет свою нишу, свою архитектуру, свои сильные стороны. Этот урок — про то, как выбирать осознанно.
Если ваш ответ “Flink, потому что я учу Flink-курс” — это не выбор, это закрепление выбора, который кто-то сделал за вас. К концу урока у вас будет рабочий framework для сравнения, и вы сможете объяснить руководству, почему именно Flink (или почему нет) для конкретной задачи.
Три модели обработки
Перед сравнением фреймворков надо понять, что они работают в трёх принципиально разных режимах:
Continuous processing (true streaming)
Событие проходит pipeline по одному, по мере прихода. Latency — миллисекунды. Это родной режим Flink и Kafka Streams.
Event 1 --> Source --> Map --> Aggregate --> Sink
Event 2 --> Source --> Map --> Aggregate --> Sink
Каждое событие — независимая единица обработки, движется через DAG конвейером.
Micro-batch processing
Источник копит события в маленькие batch’и (типично 100мс - 30с), затем каждый batch обрабатывается как мини batch-job. Это родной режим Spark Structured Streaming.
Batch [Event 1..100] --> Source --> Map --> Aggregate --> Sink
Batch [Event 101..200] --> ...
Latency = batch interval + processing time. Trade-off: micro-batch проще реализовать и отлаживать, но latency выше.
Continuous mode у Spark
Spark Structured Streaming с 2.3 имеет experimental Continuous Processing — true streaming с millisecond latency. Но он имеет ограничения (нет stateful операций в этом mode) и используется редко в production. По умолчанию Spark — micro-batch.
Apache Flink: native streaming
Flink задумывался как streaming-first фреймворк. Batch — это частный случай streaming с bounded source. Архитектура построена вокруг continuous processing с богатой моделью state и времени.
Архитектура:
- JobManager (master) + TaskManager (workers). Caнодостаточный кластер.
- State — first-class: каждый оператор имеет встроенный state, который персистится в RocksDB/HashMap.
- Checkpoints — Chandy-Lamport algorithm для distributed snapshot. Аligned vs unaligned, incremental.
- Watermarks — встроенный механизм для event time processing с обработкой late events.
- Connectors — Kafka, Kinesis, Pulsar, JDBC, Iceberg, Hudi и десятки других.
Сильные стороны:
- Лучшая в классе модель event time + watermarks. Корректная работа с out-of-order событиями.
- Богатый stateful API: keyed state, broadcast state, operator state, savepoints.
- End-to-end exactly-once через two-phase commit. Доказано в production у Alibaba (десятки петабайт в день).
- Низкая latency (10-100 мс end-to-end типично).
- Гибкость через ProcessFunction — можно написать любую custom логику.
Слабые стороны:
- Кривая обучения круче, чем у Spark или Kafka Streams. Watermarks, state TTL, broadcast pattern — концептуально сложно.
- Operational сложность — нужно ставить Flink-кластер (хотя Flink K8s Operator упрощает).
- Меньше Python-tooling по сравнению с Spark — PyFlink работает, но Python-ML экосистема не такая богатая.
Когда выбирать: stateful streaming, event time критичен, нужны exactly-once гарантии, нужны custom операторы через ProcessFunction. Real-time fraud detection, CDC, ML feature pipelines, live aggregations с windowing.
Spark Structured Streaming: batch ум на streaming
Spark Structured Streaming: основыSpark Structured Streaming родился как естественное расширение Spark Batch. Та же DataFrame/Dataset API, тот же SparkSQL, та же кластерная инфраструктура — но с streaming источниками.
Архитектура:
- Стандартный Spark кластер (Driver + Executors). Streaming-режим — это особый тип query, который continuously запускается.
- Micro-batch по умолчанию. Source накапливает события в течение interval, query запускается на этом batch.
- Checkpointing в S3/HDFS для exactly-once.
- Watermarks есть, но менее зрелые, чем в Flink.
- Catalyst optimizer работает для streaming queries — преимущество над Flink в плане SQL оптимизации.
Сильные стороны:
- Единый API с batch — если у вас уже Spark Batch, переход на streaming проще. Те же DataFrame, те же UDFs, тот же SparkSQL.
- Огромная экосистема — каждый дата-инженер знает Spark.
- Python-tooling — PySpark зрелый, ML библиотеки (MLlib, Spark NLP) интегрированы.
- Delta Lake / Iceberg / Hudi — streaming + lakehouse архитектура естественна.
- Богатый SQL — Catalyst делает streaming queries оптимизированными.
Слабые стороны:
- Micro-batch latency — обычно 1-5 секунд минимум. Для sub-second latency не подходит.
- State API менее богатый — нет broadcast pattern, нет ProcessFunction-уровня контроля.
- Watermarks слабее Flink — особенно для сложных windowing патернов.
- End-to-end exactly-once требует idempotent sinks; нет встроенного two-phase commit как у Flink.
Когда выбирать: у вас уже Spark в стеке, latency требования — секунды (не миллисекунды), большая команда знает Spark, активно используете lakehouse (Delta/Iceberg). Streaming ETL, near-real-time analytics, lakehouse ingestion.
Kafka Streams: библиотека, не кластер
Kafka Streams — это библиотека (JAR), которая встраивается в обычное Java-приложение. Никакого отдельного кластера; ваш Spring Boot сервис становится stream processor.
KStream, KTable, GlobalKTable в Kafka StreamsАрхитектура:
- Stream processing topology описана в коде приложения.
- Каждый экземпляр приложения — TaskManager.
- State stores в локальном RocksDB + changelog topic в Kafka для fault tolerance.
- Координация через Kafka consumer groups — никакого отдельного коordinator’а.
- Connectors — только Kafka (для других нужен Kafka Connect отдельно).
Сильные стороны:
- Нет отдельного кластера — деплой как обычное приложение (Spring Boot, K8s Deployment).
- Простая operational модель — масштабирование = добавить инстансов приложения.
- Tight integration с Kafka — exactly-once семантика через Kafka transactional producer.
- Низкая latency (десятки миллисекунд).
Слабые стороны:
- Только Kafka — для других источников/sinks нужна интеграция через приложение или Kafka Connect.
- Меньше fault tolerance options — отказ инстанса означает rebalance и пересчёт state из changelog topic (может занять минуты).
- Ограниченная masштабируемость — один инстанс ограничен памятью JVM. Для очень большого state — проблема.
- State не shared между инстансами — Interactive Queries сложны (нужно знать, какой инстанс хранит какой ключ).
- Меньше зрелости в Python — Kafka Streams работает только в JVM (Java/Scala/Kotlin).
Когда выбирать: микросервис, который читает из Kafka и пишет в Kafka, не нужно много state, не нужны не-Kafka источники. Простые stream-сервисы для микросервисной архитектуры. Event-driven services внутри организации с Kafka-only стеком.
Сравнительная таблица
| Свойство | Flink | Spark Structured Streaming | Kafka Streams |
|---|---|---|---|
| Парадигма | True streaming | Micro-batch (default) | True streaming |
| Latency | 10-100 мс | 1-5 с | 10-100 мс |
| Архитектура | Standalone cluster | Spark cluster | Library в приложении |
| State backend | RocksDB / ForSt / HashMap | RocksDB / HDFS | RocksDB + Kafka changelog |
| Event time | Самая зрелая модель | Поддерживается, проще | Поддерживается |
| Exactly-once | Two-phase commit | Idempotent sinks | Kafka transactional |
| Watermarks | Богатая модель + alignment | Простая модель | Базовая |
| Connectors | Очень много (50+) | Много (включая lakehouse) | Только Kafka |
| Python | PyFlink (компромиссы) | PySpark (зрелый) | Нет |
| Кривая обучения | Высокая | Низкая (если знаете Spark) | Низкая |
| Operational complexity | Высокая | Средняя | Низкая |
| Лучше всего для | Stateful streaming, event time | Streaming ETL в lakehouse | Микросервисы на Kafka |
Реальные кейсы из индустрии
Alibaba: Flink. Десятки петабайт в день. Real-time recommendations для Taobao, real-time analytics для merchants. Flink выбран за scalability и event time correctness — точные результаты при огромном объёме.
Netflix: Spark Structured Streaming + Flink. Spark для streaming ETL в Iceberg lakehouse (терабайты в день, latency минуты приемлема). Flink для real-time impressions и recommendations (sub-second latency, stateful pipelines).
Uber: Flink + Kafka Streams. Flink для критичных систем (ETA prediction, fraud detection). Kafka Streams для внутренних микросервисов с простым stream processing.
Stripe: Flink. Real-time risk scoring на каждую транзакцию (latency десятки миллисекунд). Choice driven by state management complexity и exactly-once requirements.
Pinterest: Flink. Real-time advertising aggregations. Перешли с Spark Streaming на Flink в 2020 году из-за event time correctness и latency.
Slack: Kafka Streams. Микросервисная архитектура, тысячи сервисов на Kafka. Kafka Streams для большинства простых stream-операций. Flink — для сложных аналитических пайплайнов.
Общий паттерн: Flink выбирают для критичных, сложных, низко-latency задач. Spark — для streaming ETL в lakehouse. Kafka Streams — для микросервисов, где tight integration с Kafka важнее, чем фичи.
Decision framework: как выбирать
Latency больше 1 секунды И уже есть Spark?
Если latency требования больше 1 секунды И вы уже используете Spark для batch ETL — Spark Structured Streaming чаще всего лучший выбор. Меньше cognitive load.Только Kafka источник/sink + микросервис?
Kafka Streams если: микросервис, читает только из Kafka, пишет только в Kafka, не нужен большой state (помещается в память + RocksDB одного инстанса). Простой, lightweight, без кластера.Sub-second latency + сложный state + event time?
Если нужны: sub-second latency, сложный stateful processing, event time correctness, custom операторы, exactly-once для не-Kafka sinks — это Flink territory.Не выбирайте фреймворк “на будущее”. Выбирайте под текущие требования. Переход с Spark Streaming на Flink через 2 года, когда вырастете в complexity, — это нормальный путь миграции (Pinterest, Netflix, Lyft через это прошли). Гораздо хуже сразу взять Flink для простой задачи и потерять полгода на operational complexity, которая не нужна.
Когда НЕ нужен ни один из них
Иногда правильный ответ — не использовать stream-фреймворк вовсе:
- Простые ETL копии — Kafka Connect (Source / Sink connectors) без любого stream processor.
- Real-time запросы на свежие данные — Materialize, RisingWave, ClickHouse Live Views. Это streaming databases, отличный путь для аналитики.
- Очень простая stateless обработка — самописный consumer на Go/Rust с записью в Kafka может быть проще и эффективнее.
- Если у вас 10 событий в секунду — может вам вообще не нужен streaming, batch с интервалом 5 минут решит задачу.
Stream processing — мощный, но дорогой инструмент. Используйте его осознанно.
Попробуй сам
Возьмите 3 реальных streaming use case из вашей компании (или вашего опыта):
- Для каждого — пройдите по decision tree выше. К какому фреймворку приходите?
- Сравните с тем, что используется на самом деле. Совпадает?
- Если расходится — почему? Был ли выбор обоснованным, или это “историческое решение”?
Запишите ответы — мы будем возвращаться к ним в модулях про state и event time, где вы поймёте, в чём именно сильна Flink (а Spark не очень).