FinCodeCow · Глава XI

Анатомия «тяжеловесных» фреймворков

Когда мощности Big Data встречаются с микросервисами: Flink, Spark, Beam и Storm

До сих пор мы рассматривали микросервисы, которые либо полагались на базовые клиенты брокера событий (шаблон BPC), либо использовали «легковесные» библиотеки, встроенные прямо в приложение. Но что делать, если бизнес-логика требует обработки терабайтов данных в секунду, сложнейших оконных агрегаций и глобальных JOIN-ов между десятками потоков?

На сцену выходят «тяжеловесные» фреймворки потоковой обработки — Apache Spark, Apache Flink, Apache Storm и Apache Beam. Они не просто обрабатывают события; они управляют целыми распределёнными кластерами, обеспечивая беспрецедентную масштабируемость и отказоустойчивость. Но за эту мощь приходится платить — архитектурной сложностью.

Это одиннадцатая глава цикла. Она опирается на главу V (watermarks, windowing), главу VI (event time), главу VII (state stores, RocksDB, checkpoint), главу IX (FaaS как противоположный полюс) и главу X (BPC как минимализм). Здесь мы замыкаем спектр: от простейшего poll-process-produce до распределённых титанов Big Data.

• • •

IНаследие пакетной обработки: от Hadoop к real-time

Чтобы понять философию «тяжеловесных» фреймворков, нужно взглянуть на их историю. Они родились из эпохи пакетной обработки (Apache Hadoop и MapReduce), когда объёмы данных выросли настолько, что их невозможно было обработать на одном сервере. Инженерам понадобились инструменты для массового параллелизма, распределённого хранения и автоматического восстановления после сбоев тысяч узлов.

Со временем запросы сместились от ночных пакетных заданий к аналитике в режиме, близком к реальному времени. Так появились Spark Streaming, Flink и Storm. Они унаследовали кластерную архитектуру предков, но адаптировали её для непрерывного потребления событий из брокеров.

Ключевое отличие от лёгких библиотек

Kafka Streams, BPC и FaaS живут внутри вашего приложения или в managed runtime. Flink и Spark — это отдельный кластер, который запускает ваше задание (job) как первый среди равных. Это архитектурное решение, а не деталь реализации.

• • •

IIВнутренняя анатомия: Master, Worker и Zookeeper

Главная отличительная черта «тяжеловесного» фреймворка — наличие независимого выделенного кластера. Архитектура разделена на две основные роли:

Master Node (ведущий узел)

Мозг кластера. Принимает ваше приложение (job), разбивает его на задачи (tasks), распределяет их по рабочим узлам и следит за выполнением. Если рабочий узел падает, Master перезапускает задачу на другом.

Executor / Worker

Рабочие лошадки. Потребляют вычислительные мощности, память и диски для обработки событий, выполнения агрегаций и shuffle данных между задачами.

Для координации и обеспечения высокой доступности (HA) исторически использовался Apache Zookeeper. Он решает, какой узел является главным, если текущий Master выходит из строя. Современные фреймворки учатся обходиться без него: Flink использует Kubernetes HA, Spark — Zookeeper или встроенный recovery mode.

• • •

IIISpark vs Flink: две разные модели

Многие ставят Spark и Flink в один ряд как «движки потоковой обработки». Но у них принципиально разные модели, и это критично для выбора.

Критерий Flink Spark Structured Streaming
Модель обработки True streaming — событие за событием Micro-batch — пакетами по N мс
Latency Миллисекунды 100 мс – секунды
Event time Полная поддержка с watermarks Через micro-batch watermarks
State backend RocksDB (embedded) или Flink 2.0 ForSt (S3) In-memory + checkpoint
Exactly-once Checkpoint + two-phase commit Micro-batch transactions
SQL Flink SQL (декларативный streaming) Spark SQL (micro-batch)
Лучше для Real-time, low-latency, event-time Analytics, ML, batch + streaming unified
Практическое правило

Если latency критична (финансовые транзакции, fraud detection) — Flink. Если нужна unified batch + streaming аналитика и ML — Spark. Если нужен максимум гибкости для разных runners (Flink, Spark, Dataflow, Samza) — Apache Beam.

• • •

IVПлюсы и минусы: цена мощи

Сильные стороны

  1. Аналитическая мощь. Идеальны для ETL, сложного сеансового анализа, выявления аномалий и агрегации с поддержкой состояния.
  2. Зрелость экосистемы. Огромное сообщество, отличная документация, интеграция с Data Lakes (Iceberg, Delta, Hudi).
  3. Масштаб. Способны обрабатывать миллионы событий в секунду, распределяя нагрузку на сотни узлов.
  4. Event time и watermarks. Полноценная работа с запоздалыми событиями, idle sources, allowed lateness.
  5. SQL на потоках. Flink SQL и Spark SQL позволяют писать streaming jobs декларативно.

Слабые стороны (в контексте микросервисов)

  1. Операционный «налог». Отдельный кластер, мониторинг, алертинг, выделение ресурсов — дублирование функций CMS и брокера событий.
  2. JVM-лок (для классических версий). Привязка к Java/Scala ограничивает выбор языков для команд.
  3. Сложность материализации. Глобальные JOIN и бесконечная материализация потоков в таблицы часто реализованы, но плохо документированы.
  4. Startup time. Развёртывание кластера — минуты, а не секунды. Не подходит для FaaS-парадигмы.
  5. Стоимость при простое. Кластер работает 24/7, даже если нет событий.
• • •

VЭволюция развёртывания: от «голого железа» до Kubernetes

То, как вы развёртываете «тяжеловесный» фреймворк, определяет, насколько хорошо он впишется в вашу микросервисную архитектуру. Существует три основных пути:

1. Managed Services

AWS EMR, Google Dataflow, Databricks, Confluent Cloud. Вы платите за compute, провайдер управляет кластером. Минус — vendor lock-in и ограниченная гибкость настройки.

2. Выделенный автономный кластер

Классический Hadoop-подход. Вы сами настраиваете VM, Zookeeper и Master. Подходит для гигантских нагрузок, но ужасен для гибкости микросервисов.

3. Интеграция с Kubernetes

Современный золотой стандарт. Flink или Spark использует Kubernetes как планировщик ресурсов. Каждое задание запускается в изолированном session cluster. Развёртывание — как обычного контейнера, через CI/CD.

Application Mode vs Session Mode

Flink поддерживает два режима: session mode — один кластер для многих jobs (быстрее старт, но изоляция слабее), application mode — кластер под каждый job (полная изоляция, но медленнее старт).

Тренд

Flink и Spark на Kubernetes перестают быть «чужеродным телом» в микросервисной архитектуре. Они становятся managed workloads с CI/CD, RBAC, autoscaling — как любой другой сервис в кластере.

• • •

VIМагия выживания: checkpointing и два типа state

В распределённой системе сбои — норма. «Тяжеловесные» фреймворки решают это через механизм контрольных точек (checkpoints): моментальные снимки состояния приложения, периодически сохраняемые в надёжное хранилище (HDFS, S3).

При сбое узла Master восстанавливает задачу на новом рабочем узле, загружая последнюю контрольную точку. Фреймворк синхронизирует два типа состояния:

Operator State

Хранит смещения (offsets) брокера событий. Гарантирует, что при восстановлении микросервис продолжит чтение ровно с того места, где остановился.

Keyed State

Хранит бизнес-логику (агрегаты, окна, JOIN-буферы). Гарантирует, что вычисления не будут дублированы или потеряны.

Правило

Если operator state и keyed state не синхронизированы в одной контрольной точке, вы получите либо потерю данных, либо их дублирование. Фреймворки берут эту рутину на себя, но разработчик должен понимать механизм.

Связь с главой VII: в Kafka Streams аналогом checkpoint является changelog topic. Во Flink — checkpoint в S3/HDFS. Это два разных подхода к одной задаче: сохранение state для восстановления после сбоя.

• • •

VIIExactly-once и two-phase commit

Flink предоставляет exactly-once через checkpointing + two-phase commit для external sinks. Это принципиально отличается от Kafka Streams exactly_once_v2:

Аспект Flink EOS Kafka Streams EOS v2
Механизм Snapshot barrier + 2PC Kafka transactions
Требует поддержки sink Да (Kafka, JDBC, File с 2PC) Только Kafka to Kafka
Overhead Checkpoint frequency + 2PC на каждый sink Transaction на batch
Где применяется Flink jobs с внешними sinks Kafka Streams applications
Ограничение

Flink EOS работает с transactional sinks. Если sink не поддерживает transactions (например, HTTP API), EOS не гарантируется — нужна идемпотентность на стороне sink, как в BPC (глава X).

• • •

VIIIWatermarks и event time: связь с главой VI

Watermarks — ключевое отличие тяжёлых фреймворков от BPC и FaaS. Это механизм определения «прошлое прошло»:

WatermarkStrategy.<Event>forBoundedOutOfOrderness(
        Duration.ofSeconds(30))
    .withTimestampAssigner((event, ts) ->
        event.getOccurredAt().toEpochMilli())
    .withIdleness(Duration.ofMinutes(5));
  • forBoundedOutOfOrderness — допускаем опоздание до 30 секунд.
  • withTimestampAssigner — откуда берём event time.
  • withIdleness — если источник замолчал 5 минут, исключаем его из watermark.

Flink предоставляет полную поддержку того, что в главе VI обсуждалось для Kafka Streams: watermarks, allowed lateness, idle sources, watermark alignment. Разница — в уровне абстракции и мощности: Flink работает с сотнями источников одновременно.

• • •

IXShuffle и External Shuffle Service (ESS)

Самая большая боль при масштабировании stateful-приложений — операция shuffle. Когда вы группируете данные по ключу (groupByKey), события с одинаковыми ключами должны физически попасть на один рабочий узел.

Если вы добавляете или удаляете рабочие узлы «на лету», данные, которые уже были перемешаны старыми узлами, могут стать недоступны для новых. Исторически это решалось либо остановкой приложения, либо использованием External Shuffle Service (ESS) — выделенного хранилища, которое буферизует данные между задачами.

Тенденция к упрощению

Apache Spark 3.0+ учится динамически масштабироваться без ESS, удерживая узлы-источники активными, пока нижестоящие задачи не заберут данные. Flink решает эту задачу иначе: state сохраняется в checkpoint, а после rescale восстанавливается на новых узлах. Это сближает тяжёлые фреймворки с парадигмой эластичных микросервисов.

• • •

XFlink 2.0: disaggregated state (ForSt)

Flink 2.0 (март 2025) представил disaggregated state backend (ForSt): состояние живёт в remote object storage (S3), а не на локальном диске TaskManager. State pages in/out по мере необходимости.

Что это даёт:

  • Decouples state size от диска. Не нужно выделять SSD под каждый TaskManager.
  • Ускоряет rescaling. TaskManagers просто начинают читать другие key partitions из S3.
  • Упрощает эксплуатацию. State — это просто объекты в S3, а не тома на локальных дисках.

Trade-offs:

  • Latency. Page in/out из S3 занимает десятки миллисекунд, а не микросекунды, как локальный RocksDB.
  • Стоимость. Оплата за S3 API calls + storage.
  • Не для всех workloads. Для latency-sensitive задач (real-time fraud detection) лучше embedded RocksDB.

Связь с главой VII: Flink 2.0 ForSt — это эволюция того же подхода, что обсуждался для Kafka Streams (внутренний vs внешний state). Разница — в уровне абстракции.

• • •

XIFlink SQL и Spark SQL: декларативный streaming

Современное развитие тяжёлых фреймворков — SQL на потоках. Flink SQL и Spark SQL позволяют писать streaming jobs декларативно, без Java/Scala кода.

-- Flink SQL: session windows для рекламы
SELECT
    userId,
    COUNT(*) AS view_count,
    SESSION_START(eventTime, INTERVAL '30' MINUTE) AS session_start,
    SESSION_END(eventTime, INTERVAL '30' MINUTE) AS session_end
FROM ad_views
GROUP BY
    userId,
    SESSION(eventTime, INTERVAL '30' MINUTE);

Это радикально снижает порог входа: аналитики и data engineers могут писать streaming jobs без знания Java API. SQL становится языком для ETL и аналитики в реальном времени.

• • •

XIITesting тяжёлых jobs

Как тестировать Flink job без production кластера?

MiniCluster

Локальный Flink в unit-тестах. Запускает job в том же JVM с минимальными ресурсами. Быстрая проверка топологии.

TestHarness

Тестирование операторов в изоляции. Подаёт события, проверяет выход. Без полноценного кластера.

DataStream API testing

Утилиты для интеграционного тестирования Flink jobs. Проверка watermark propagation, state, sinks.

Spark TestingBase

Аналог для Spark: локальный SparkSession, тестовые данные, проверка output.

• • •

XIIIOperational side: метрики и проблемы

Метрика Что показывает Порог алерта
checkpoint_duration Время на checkpoint Растёт — диск/сеть bottleneck
checkpoint_failures Провалы checkpoint > 0 в течение 10 мин
backpressure Давление на upstream High > 5 мин
watermark_lag Отставание watermark от processing time Растёт — источник отстаёт
task_skew Неравномерность нагрузки между subtasks Ratio > 3x
GC_time Время на garbage collection > 10% от CPU time

Типичные production-проблемы

  • Checkpoint timeout. State слишком большой или диск медленный.
  • Backpressure. Один оператор медленнее остальных — весь pipeline ждёт.
  • Task skew. Одни partitions получают больше событий — нужен rebalance.
  • Watermark stagnation. Idle source замораживает watermark (см. главу VI).
• • •

XIVCosts: managed vs self-hosted

Сценарий Managed Self-hosted
Старт Быстро (минуты) Медленно (недели)
Операционные расходы Низкие Высокие (SRE)
Стоимость при простое Есть (cluster runs) Есть (cluster runs)
Гибкость настройки Ограничена Полная
Vendor lock-in Есть Нет
Стоимость при scale Растёт линейно Растёт с дисконтом
Правило

Managed — для команд без Big Data экспертизы и при переменной нагрузке. Self-hosted — для крупных организаций с экспертизой и предсказуемой нагрузкой. На длинном горизонте self-hosted дешевле, но требует SRE-команды.

• • •

XVСравнение Flink vs Spark vs Beam vs Storm

Критерий Flink Spark Structured Streaming Beam Storm
Модель True streaming Micro-batch Unified (runner-dependent) True streaming
Latency ms 100ms+ depends ms
State backend RocksDB + ForSt (S3) In-memory + checkpoint depends Custom
Exactly-once Checkpoint + 2PC Micro-batch transactions depends Trident
SQL Flink SQL Spark SQL Beam SQL Нет
K8s native Да (operator) Да (operator) Да Ограниченно
Лучше для Real-time, event time Analytics, ML, unified Multi-runner Legacy real-time
• • •

XVIПрактический пример: session windows для рекламы

Представьте, что нужно объединить потоки «Просмотров рекламы» и «Кликов по рекламе» для расчёта конверсии в сеансовом окне: если пользователь не кликает и не смотрит рекламу 30 минут, сеанс закрывается.

DataStream<Event> clickStream = ...;
DataStream<Event> viewStream = ...;

clickStream
    .union(viewStream)                          // 1. Объединяем потоки
    .keyBy(e -> e.getUserId())                  // 2. Группируем по пользователю (shuffle)
    .window(EventTimeSessionWindows
        .withGap(Time.minutes(30)))             // 3. Сеансовое окно
    .aggregate(new SessionAggregator())         // 4. Агрегация
    .addSink(producerToKafka);                  // 5. Результат в Kafka

Фреймворк берёт на себя управление state окон, watermarks и обработкой запоздалых событий. Разработчику остаётся только описать бизнес-логику агрегатора.

Связь с главой VI

Session windows уже обсуждались в главе VI для Kafka Streams. Здесь Flink реализует тот же паттерн, но с полной поддержкой watermarks, idle sources и allowed lateness. Это тот уровень, на котором BPC уже не справляется.

• • •

XVIIЧеклисты и связь с циклом

Связь с предыдущими главами

Глава Фокус Связь с текущей главой
V. Механика потоковой обработки Windowing, state stores, rebalance Flink и Spark реализуют то же на кластерном уровне
VI. Время в потоках Event time, watermarks, late events Flink предоставляет полную поддержку watermarks
VII. Память микросервисов RocksDB, changelog, TTL Flink state backend — RocksDB или ForSt (S3)
IX. Бессерверная архитектура FaaS как противоположный полюс Тяжёлые фреймворки не подходят для FaaS-парадигмы
X. Базовый шаблон Производитель-Потребитель BPC как минимализм Flink/Spark — верхний предел сложности EDA
XI. Тяжеловесные фреймворки Flink, Spark, Beam, Storm Замыкание спектра: от простого к сложному

Чеклист выбора тяжёлого фреймворка

  • Есть ли реальная потребность в обработке > 100k msg/s?
  • Нужны ли watermarks и event-time с точностью до миллисекунд?
  • Нужны ли сложные JOIN трёх и более потоков?
  • Нужна ли интеграция с Data Lake (Iceberg, Delta, Hudi)?
  • Есть ли команда с экспертизой Big Data (Flink/Spark)?
  • Готовы ли выделить SRE-команду для эксплуатации кластера?
  • Выбран ли Flink (true streaming, low latency) или Spark (micro-batch, analytics)?
  • Решён ли вопрос развёртывания: managed vs K8s operator vs standalone?
  • Настроены ли checkpoints, HA, monitoring?
  • Настроен ли state backend: RocksDB или ForSt (S3)?
  • Настроен ли exactly-once с transactional sinks?
  • Настроены ли watermarks, idle sources, allowed lateness?
  • Есть ли тесты через MiniCluster / TestHarness?
  • Настроены ли алерты на checkpoint failures, backpressure, skew?
  • Оценена ли стоимость managed vs self-hosted?

Ключевые выводы главы

  1. Тяжёлые фреймворки — это не замена микросервисам. Это мощный бэкенд для сложных аналитических задач.
  2. Spark vs Flink — разные модели. Spark — micro-batch, Flink — true streaming. Выбор зависит от latency-требований.
  3. Checkpointing синхронизирует operator state (offsets) и keyed state (агрегаты).
  4. Exactly-once во Flink — через checkpoint + two-phase commit для external sinks.
  5. Watermarks — полная поддержка event time, idle sources, allowed lateness.
  6. Shuffle — физическое перемещение данных по ключу. ESS или динамическое масштабирование без ESS.
  7. Flink 2.0 ForSt — state в S3, decoupling от локальных дисков TaskManager.
  8. Flink SQL / Spark SQL — декларативный streaming для аналитиков.
  9. Testing — MiniCluster, TestHarness для unit и integration тестов.
  10. Operational — метрики checkpoint, backpressure, skew; типичные production-проблемы.
  11. Costs — managed vs self-hosted, trade-offs.
  12. Kubernetes integration — современный золотой стандарт. Flink/Spark на K8s — managed workloads.
Финальный тезис

Главный тренд сегодня — интеграция тяжёлых фреймворков с Kubernetes. Когда Flink или Spark начинают воспринимать CMS как планировщик ресурсов, они перестают быть «чужеродным телом» в архитектуре и становятся полноправными, хотя и очень прожорливыми, микросервисами. Спектр EDA замкнут: от простейшего BPC до распределённых титанов Big Data — каждый инструмент занимает свою нишу.

Глава XI цикла «Событийно-управляемая архитектура». Источники: Apache Flink, Apache Spark, Apache Beam, Apache Storm, Confluent, Databricks, практические кейсы production-систем.

FinCodeCow · Chapter XI

Anatomy of Heavyweight Frameworks

When Big Data power meets microservices: Flink, Spark, Beam, and Storm

So far, we have looked at microservices that either relied on basic event broker clients (BPC pattern) or used "lightweight" libraries embedded directly in the application. But what if your business logic requires processing terabytes per second, complex window aggregations, and global JOINs between dozens of streams?

Enter heavyweight stream processing frameworks — Apache Spark, Apache Flink, Apache Storm, and Apache Beam. They don't just process events; they manage entire distributed clusters, providing unprecedented scalability and fault tolerance. But this power comes at a cost — architectural complexity.

This is the eleventh chapter of the series. It builds on Chapter V (watermarks, windowing), Chapter VI (event time), Chapter VII (state stores, RocksDB, checkpoint), Chapter IX (FaaS as the opposite pole), and Chapter X (BPC as minimalism). Here we close the spectrum: from the simplest poll-process-produce to the distributed titans of Big Data.

• • •

ILegacy of Batch Processing: From Hadoop to Real-Time

To understand the philosophy of heavyweight frameworks, we need to look at their history. They were born in the era of batch processing (Apache Hadoop and MapReduce), when data volumes grew so large they couldn't be processed on a single server. Engineers needed tools for massive parallelism, distributed storage, and automatic recovery after failures of thousands of nodes.

Over time, demands shifted from nightly batch jobs to near-real-time analytics. So Spark Streaming, Flink, and Storm appeared. They inherited the cluster architecture of their ancestors but adapted it for continuous event consumption from brokers.

Key Difference from Lightweight Libraries

Kafka Streams, BPC, and FaaS live inside your application or managed runtime. Flink and Spark are a separate cluster that runs your job as a first-class citizen. This is an architectural decision, not an implementation detail.

• • •

IIInternal Anatomy: Master, Worker, and Zookeeper

The main distinguishing feature of heavyweight frameworks is the presence of an independent dedicated cluster. Architecture is divided into two main roles:

Master Node

The brain of the cluster. Accepts your application (job), splits it into tasks, distributes them across worker nodes, and monitors execution. If a worker node fails, the Master restarts the task on another.

Executor / Worker

The workhorses. They consume compute, memory, and disk to process events, perform aggregations, and shuffle data between tasks.

For coordination and high availability (HA), Apache Zookeeper was historically used. It decided which node is the leader if the current Master failed. Modern frameworks are learning to live without it: Flink uses Kubernetes HA, Spark uses Zookeeper or built-in recovery mode.

• • •

IIISpark vs Flink: Two Different Models

Many put Spark and Flink in the same row as "stream processing engines." But they have fundamentally different models, and this is critical for choosing.

Criterion Flink Spark Structured Streaming
Processing model True streaming — event by event Micro-batch — batches of N ms
Latency Milliseconds 100 ms – seconds
Event time Full support with watermarks Via micro-batch watermarks
State backend RocksDB (embedded) or Flink 2.0 ForSt (S3) In-memory + checkpoint
Exactly-once Checkpoint + two-phase commit Micro-batch transactions
SQL Flink SQL (declarative streaming) Spark SQL (micro-batch)
Best for Real-time, low-latency, event-time Analytics, ML, batch + streaming unified
Practical Rule

If latency is critical (financial transactions, fraud detection) — Flink. If you need unified batch + streaming analytics and ML — Spark. If you need maximum flexibility across runners (Flink, Spark, Dataflow, Samza) — Apache Beam.

• • •

IVPros and Cons: The Price of Power

Strengths

  1. Analytical power. Ideal for ETL, complex session analysis, anomaly detection, and stateful aggregation.
  2. Ecosystem maturity. Huge community, excellent documentation, Data Lake integration (Iceberg, Delta, Hudi).
  3. Scale. Capable of processing millions of events per second across hundreds of nodes.
  4. Event time and watermarks. Full support for late events, idle sources, allowed lateness.
  5. SQL on streams. Flink SQL and Spark SQL allow writing streaming jobs declaratively.

Weaknesses (in the context of microservices)

  1. Operational tax. Separate cluster, monitoring, alerting, resource allocation — duplicating CMS and event broker functions.
  2. JVM lock (for classic versions). Java/Scala binding limits language choice.
  3. Materialization complexity. Global JOINs and infinite stream-to-table materialization are often implemented but poorly documented.
  4. Startup time. Cluster deployment — minutes, not seconds. Not suitable for FaaS paradigm.
  5. Cost at idle. Cluster runs 24/7, even when no events.
• • •

VDeployment Evolution: From Bare Metal to Kubernetes

1. Managed Services

AWS EMR, Google Dataflow, Databricks, Confluent Cloud. You pay for compute, provider manages the cluster. Downside — vendor lock-in and limited tuning flexibility.

2. Dedicated Standalone Cluster

Classic Hadoop approach. You configure VM, Zookeeper, and Master yourself. Suitable for giant workloads, but terrible for microservice flexibility.

3. Kubernetes Integration

Modern gold standard. Flink or Spark uses Kubernetes as a resource scheduler. Each job runs in an isolated session cluster. Deployment is like any container via CI/CD.

Application Mode vs Session Mode

Flink supports two modes: session mode — one cluster for many jobs (faster start, weaker isolation), application mode — cluster per job (full isolation, slower start).

Trend

Flink and Spark on Kubernetes stop being a "foreign body" in microservice architecture. They become managed workloads with CI/CD, RBAC, autoscaling — like any other service in the cluster.

• • •

VIThe Magic of Survival: Checkpointing and Two Types of State

In a distributed system, failures are normal. Heavyweight frameworks solve this via checkpoints: snapshots of application state periodically saved to reliable storage (HDFS, S3).

On node failure, the Master restores the task on a new worker node, loading the last checkpoint. The framework synchronizes two types of state:

Operator State

Stores broker offsets. Guarantees that on recovery, the microservice resumes reading exactly where it stopped.

Keyed State

Stores business logic (aggregates, windows, JOIN buffers). Guarantees that computations are neither duplicated nor lost.

Rule

If operator state and keyed state are not synchronized in the same checkpoint, you get either data loss or duplication. Frameworks handle this routine, but the developer must understand the mechanism.

Link to Chapter VII: in Kafka Streams, the analog of checkpoint is the changelog topic. In Flink — checkpoint in S3/HDFS. These are two different approaches to the same task.

• • •

VIIExactly-once and Two-Phase Commit

Aspect Flink EOS Kafka Streams EOS v2
Mechanism Snapshot barrier + 2PC Kafka transactions
Requires sink support Yes (Kafka, JDBC, File with 2PC) Only Kafka to Kafka
Overhead Checkpoint frequency + 2PC per sink Transaction per batch
Where applied Flink jobs with external sinks Kafka Streams applications
Limitation

Flink EOS works with transactional sinks. If a sink doesn't support transactions (e.g., HTTP API), EOS is not guaranteed — you need idempotency on the sink side, as in BPC (Chapter X).

• • •

VIIIWatermarks and Event Time: Link to Chapter VI

WatermarkStrategy.<Event>forBoundedOutOfOrderness(
        Duration.ofSeconds(30))
    .withTimestampAssigner((event, ts) ->
        event.getOccurredAt().toEpochMilli())
    .withIdleness(Duration.ofMinutes(5));
  • forBoundedOutOfOrderness — allow up to 30 seconds of lateness.
  • withTimestampAssigner — where to get event time from.
  • withIdleness — if a source is idle for 5 minutes, exclude it from watermark calculation.

Flink provides full support for what Chapter VI discussed for Kafka Streams: watermarks, allowed lateness, idle sources, watermark alignment. The difference is in abstraction level and power: Flink works with hundreds of sources simultaneously.

• • •

IXShuffle and External Shuffle Service (ESS)

The biggest pain of scaling stateful applications is the shuffle operation. When you group data by key (groupByKey), events with the same key must physically land on the same worker node.

If you add or remove worker nodes "on the fly," data already shuffled by old nodes may become unavailable to new ones. Historically this was solved either by stopping the application or by using an External Shuffle Service (ESS) — a dedicated storage that buffers data between tasks.

Trend Toward Simplification

Apache Spark 3.0+ is learning to dynamically scale without ESS, keeping source nodes active until downstream tasks fetch the data. Flink solves this differently: state is saved to checkpoint and restored on new nodes after rescale. This brings heavyweight frameworks closer to elastic microservices.

• • •

XFlink 2.0: Disaggregated State (ForSt)

Flink 2.0 (March 2025) introduced the disaggregated state backend (ForSt): state lives in remote object storage (S3) rather than on the local disk of TaskManager. State pages in/out on demand.

Benefits: decouples state size from disk, speeds up rescaling, simplifies operations.

Trade-offs: higher latency (ms instead of μs), S3 costs, not for latency-sensitive workloads.

Link to Chapter VII: Flink 2.0 ForSt is the evolution of the same approach discussed for Kafka Streams (internal vs external state).

• • •

XIFlink SQL and Spark SQL: Declarative Streaming

-- Flink SQL: session windows for ads
SELECT
    userId,
    COUNT(*) AS view_count,
    SESSION_START(eventTime, INTERVAL '30' MINUTE) AS session_start,
    SESSION_END(eventTime, INTERVAL '30' MINUTE) AS session_end
FROM ad_views
GROUP BY
    userId,
    SESSION(eventTime, INTERVAL '30' MINUTE);

This radically lowers the barrier: analysts and data engineers can write streaming jobs without Java API knowledge. SQL becomes the language for ETL and real-time analytics.

• • •

XIITesting Heavyweight Jobs

MiniCluster

Local Flink in unit tests. Runs job in the same JVM with minimal resources. Fast topology verification.

TestHarness

Testing operators in isolation. Feeds events, checks output. No full cluster needed.

DataStream API Testing

Utilities for integration testing Flink jobs. Watermark propagation, state, sinks verification.

Spark TestingBase

Analog for Spark: local SparkSession, test data, output verification.

• • •

XIIIOperational Side: Metrics and Issues

Metric What It Shows Alert Threshold
checkpoint_duration Time to checkpoint Growing — disk/network bottleneck
checkpoint_failures Checkpoint failures > 0 within 10 min
backpressure Pressure on upstream High > 5 min
watermark_lag Watermark lag behind processing time Growing — source falling behind
task_skew Load imbalance between subtasks Ratio > 3x
GC_time Garbage collection time > 10% of CPU time

Typical Production Issues

  • Checkpoint timeout. State too large or disk too slow.
  • Backpressure. One operator slower than others — whole pipeline waits.
  • Task skew. Some partitions get more events — need rebalance.
  • Watermark stagnation. Idle source freezes watermark (see Chapter VI).
• • •

XIVCosts: Managed vs Self-Hosted

Scenario Managed Self-Hosted
Start Fast (minutes) Slow (weeks)
Operational cost Low High (SRE)
Cost at idle Exists (cluster runs) Exists (cluster runs)
Tuning flexibility Limited Full
Vendor lock-in Yes No
Cost at scale Grows linearly Grows with discount
• • •

XVFlink vs Spark vs Beam vs Storm

Criterion Flink Spark SS Beam Storm
Model True streaming Micro-batch Unified (runner-dependent) True streaming
Latency ms 100ms+ depends ms
State backend RocksDB + ForSt (S3) In-memory + checkpoint depends Custom
Exactly-once Checkpoint + 2PC Micro-batch transactions depends Trident
SQL Flink SQL Spark SQL Beam SQL None
K8s native Yes (operator) Yes (operator) Yes Limited
• • •

XVIPractical Example: Session Windows for Ads

DataStream<Event> clickStream = ...;
DataStream<Event> viewStream = ...;

clickStream
    .union(viewStream)
    .keyBy(e -> e.getUserId())
    .window(EventTimeSessionWindows
        .withGap(Time.minutes(30)))
    .aggregate(new SessionAggregator())
    .addSink(producerToKafka);

The framework handles state management of windows, watermarks, and late event processing. The developer only describes the aggregator's business logic.

• • •

XVIIChecklists and Link to the Series

Link to Previous Chapters

Chapter Focus Link to This Chapter
V. The Mechanics of Stream Processing Windowing, state stores, rebalance Flink and Spark implement the same at cluster level
VI. Time in Streams Event time, watermarks, late events Flink provides full watermark support
VII. The Memory of Microservices RocksDB, changelog, TTL Flink state backend — RocksDB or ForSt (S3)
IX. Serverless Architecture FaaS as opposite pole Heavyweight frameworks don't fit FaaS paradigm
X. Basic Producer/Consumer Pattern BPC as minimalism Flink/Spark — upper limit of EDA complexity
XI. Heavyweight Frameworks Flink, Spark, Beam, Storm Closing the spectrum: from simple to complex

Heavyweight Framework Selection Checklist

  • Is there a real need for processing > 100k msg/s?
  • Are watermarks and event-time with ms precision needed?
  • Are complex JOINs of three or more streams needed?
  • Is Data Lake integration needed (Iceberg, Delta, Hudi)?
  • Is there a team with Big Data expertise (Flink/Spark)?
  • Are you ready to allocate an SRE team for cluster operations?
  • Flink (true streaming, low latency) or Spark (micro-batch, analytics) chosen?
  • Deployment path decided: managed vs K8s operator vs standalone?
  • Checkpoints, HA, monitoring configured?
  • State backend configured: RocksDB or ForSt (S3)?
  • Exactly-once with transactional sinks configured?
  • Watermarks, idle sources, allowed lateness configured?
  • Tests via MiniCluster / TestHarness in place?
  • Alerts on checkpoint failures, backpressure, skew configured?
  • Cost evaluated: managed vs self-hosted?
Final Thesis

The main trend today is integrating heavyweight frameworks with Kubernetes. When Flink or Spark begin to perceive CMS as their resource scheduler, they stop being a "foreign body" in the architecture and become full-fledged, albeit very voracious, microservices. The EDA spectrum is closed: from the simplest BPC to the distributed titans of Big Data — each tool occupies its niche.

Chapter XI of the "Event-Driven Architecture" series. Sources: Apache Flink, Apache Spark, Apache Beam, Apache Storm, Confluent, Databricks, production system case studies.