Learning Platform
Глоссарий Troubleshooting
Урок 01.01 · 18 мин
Продвинутый
Course goalsInternals philosophyProduction debuggingPrerequisites

Это курс не о том, как писать Flink-приложения. Если вы здесь, у вас уже есть прод с Flink: DataStream или Table API, какие-то стейтфул-операторы, чекпоинтинг, возможно — exactly-once-выводы в Kafka. Вы умеете запускать job, рестартить его с savepoint, читать flink-conf.yaml. И вы уже сталкивались с тем, что эта поверхностная модель перестаёт работать, когда нужно объяснить, почему checkpoint занимает 45 секунд, или почему backpressure начинается на map-операторе, который вроде бы ничего тяжёлого не делает.

Этот курс — про спуск с уровня API до уровня машины. Мы не будем учиться писать KeyedProcessFunction (предполагается, что вы это уже делали). Мы будем разбирать, что происходит на ноде, когда KeyedProcessFunction вызывается на 12-миллионном элементе с 800-килобайтным state.

Базовая архитектура Flink: JobManager и TaskManager

Когда DataStream API становится недостаточно

Большинство Flink-инженеров годами живут на уровне API: env.fromSource(...).map(...).keyBy(...).window(...).process(...).sinkTo(...). Это работает, и в нормальных условиях работает хорошо. До того момента, пока не нужно ответить на вопросы вроде этих:

  • Почему checkpoint на job с 200 GiB state стартует за 200 мс на одном TaskManager и за 18 секунд — на другом, при идентичной конфигурации?
  • Job из 12 операторов, parallelism 64. На метрике numRecordsOutPerSecond map-оператора виден провал в 4 раза каждые 30 секунд. Map не делает ничего тяжёлого — просто десериализует JSON. Что это?
  • Включили disaggregated state (Flink 2.0+), s3 как state backend. Latency на keyed state read вырос с 0.3 ms до 47 ms p99. Это норма или мы что-то сломали?
  • Adaptive Scheduler “не видит” 8 свободных слотов в TaskManager и держит job в WAITING_FOR_RESOURCES. JM-логи показывают Could not allocate the required slot within slot request timeout. ResourceManager думает иначе. Кто прав?
  • Падает производительность Calcite-планирования SQL-запроса с 12 JOIN-ами. EXPLAIN PLAN показывает разумный план, но планирование занимает 11 секунд на запрос. Где затык?

Ни один из этих вопросов нельзя ответить, не понимая internals. Документация Flink написана на уровне “вот такой параметр существует и вот что он примерно делает”. Это полезно, но не достаточно для отладки. Чтобы тюнить, нужно знать причинно-следственные связи — какое решение разработчика Flink привело к тому поведению, которое вы видите в метриках.

Что значит “знать internals”

Под internals в этом курсе понимается слой между публичным API и системными вызовами. Это:

  • Структура процессов JobManager и TaskManager, их под-компоненты (Dispatcher, ResourceManager, JobMaster, TaskExecutor) и как они общаются между собой через ActorSystem (исторически Akka — теперь Flink использует свой RpcGateway-абстракцию).
  • Граф преобразования программы:
    StreamGraph
    ->
    JobGraph
    ->
    ExecutionGraph
    , и какие решения принимаются на каждом уровне.
  • Network stack: credit-based flow control, как байты передаются между Task-ами через LocalBufferPool и RemoteInputChannel, что такое subpartition.
  • Memory model: managed memory vs heap, на что Flink тратит память внутри одного TaskManager.
  • State backends: внутренности RocksDB (LSM-tree, MemTable, SSTable, compaction), как Flink использует ColumnFamilies, что такое incremental checkpointing.
  • Checkpoint protocol: алгоритм Чанди-Лэмпорта, как barriers ходят по графу, что такое alignment, как работает unaligned checkpointing.
  • Watermark механика: per-channel vs operator watermark, idleness detection, что значит “watermark holders” в production.
  • SQL планирование: что Calcite делает с вашим SELECT, какие правила переписывания применяются, почему план иногда внезапно меняется.

Это всё открытый код, и весь курс на него ссылается. В каждом deep-уроке вы увидите конкретные классы: org.apache.flink.runtime.dispatcher.Dispatcher, org.apache.flink.runtime.checkpoint.CheckpointCoordinator, org.apache.flink.streaming.runtime.io.checkpointing.CheckpointBarrierHandler. Идея — не зазубрить имена, а знать, куда смотреть, когда дебажите.

Три причины спуститься на этот уровень

Причина 1: Production debugging

Самая прагматичная. Когда у вас лежит job в проде и метрики говорят что-то странное, у вас есть три источника информации: документация (поверхностная), JM/TM логи (часто непонятные без контекста), и source code Flink (понятный, если знаешь куда смотреть). Без знания internals вы остаётесь с первыми двумя — и часто застреваете на сообщении вроде Async checkpoint operation failed for checkpoint 12345: java.io.IOException: Could not flush to file and close the file system output stream. Без понимания, что такое async snapshot, как RocksDB flushed-state передаётся в JobMaster, и какой именно файл это пытался создать на DFS — это сообщение бесполезно.

Понимание internals превращает “магические” инциденты в систему диагностируемых сценариев. После этого курса при backpressure вы знаете, что проверить: inPoolUsage, outPoolUsage, numBuffersInRemote per channel, network buffer count в TM. При медленных чекпоинтах — checkpointStartDelayNanos, alignmentDurationNanos, distribution размеров incrementalCheckpointStateSizeMBytes по TM-ам.

Причина 2: Тюнинг

Параметров в flink-conf.yaml сотни. На 2026 год — state.backend.rocksdb.write-buffer-size, taskmanager.network.memory.buffers-per-channel, pipeline.operator-chaining, execution.checkpointing.unaligned, state.backend.rocksdb.compaction.style — список длинный. Тюнить по cargo-cult-форумам не работает: один и тот же параметр в одном workload даёт +30%, в другом — −15%. Чтобы тюнить осмысленно, нужно понимать, что именно этот параметр меняет в runtime. Например, state.backend.rocksdb.write-buffer-size определяет размер MemTable; больше MemTable = меньше flush-ей = меньше SSTable = меньше работы compaction-у, но больше recovery-времени и больше JVM heap usage. Без модели LSM-tree это знание получить негде.

Причина 3: Архитектурные решения

Стек streaming-данных в 2026 году богатый: Flink, Spark Structured Streaming, Kafka Streams, Materialize, RisingWave, ksqlDB. Когда вам нужно выбрать инструмент или защитить выбор Flink перед заказчиком, аргументация “у Flink event-time лучше” не убеждает. Нужно конкретно: Flink в отличие от Spark Structured Streaming работает event-at-a-time (не micro-batch), что даёт миллисекундные latency, но требует более сложного state management. Flink в отличие от Kafka Streams работает на собственном кластере с separate state backend, что позволяет state-ам быть больше памяти ноды. Эти аргументы вы можете предъявить только если знаете, как Flink работает внутри.

Цель курса

Сформулируем явно. К концу курса вы:

  1. Понимаете архитектуру Flink на уровне исходного кода. Когда читаете JM-лог про JobMaster transitioned from RUNNING to FAILING, знаете, какие компоненты участвуют и в каком порядке. Можете открыть flink-runtime и навигироваться в нужный класс.

  2. Можете диагностировать production-инциденты по метрикам и логам без догадок. Видите backpressure — знаете, какие 4 метрики посмотреть и как они между собой связаны. Видите медленный checkpoint — знаете, на какой фазе протокола искать узкое место.

  3. Тюните Flink осознанно. Когда меняете параметр, можете предсказать, что именно изменится в runtime и какие будут побочные эффекты. Не зависите от форумов и blog-постов.

  4. Понимаете эволюцию Flink с 1.x до 2.2. Знаете, что удалили (DataSet API, Scala API, SourceFunction) и почему. Можете оценить, какие breaking changes ждут вас при upgrade.

  5. Знаете disaggregated state и ForStDB. Эта тема — самая значимая в 2.0/2.1, и большинство production-инсталляций в 2026 ещё на классической RocksDB-модели. Курс даст вам понимание, когда и зачем мигрировать.

  6. Понимаете SQL слой и его место в стеке. Flink Table/SQL API использует Apache Calcite для планирования. Это означает специфические оптимизации, специфические гача-моменты, и специфические способы тюнить.

  7. Знаете lakehouse-стек: Paimon и Fluss. Эти проекты — будущее Flink-CDC и Flink-streaming-table direction. Покрываем что они дают и как с ними жить.

Этот курс строго senior-уровневый. Перед ним вы должны:

  • Уметь писать DataStream-приложения. Знать, что такое DataStream/KeyedStream/WindowedStream, как использовать keyBy(), window(), process(). Уметь имплементить KeyedProcessFunction, использовать ValueState, MapState, ListState. Если эти слова требуют объяснения — пройдите сначала basic flink-course.
ValueState, ListState, MapState — практический API
  • Иметь опыт production-эксплуатации. Под “опытом” имеется в виду минимум один Flink job в проде, который вы запускали, чекпоинтили и рестартили. Без этого многие “почему так больно” из курса не будут резонировать.
  • Знать Java на уровне чтения runtime-кода. Flink написан на Java + немного Scala в legacy-местах (на 2026 Scala API удалён, но Akka — наследие — местами всё ещё проглядывает). Вы должны быть способны открыть класс на 800 строк и понять, что в нём происходит.
  • Понимать distributed systems основы. Терминология вроде “leader election”, “two-phase commit”, “consensus”, “log replication” должна быть знакома. Курс будет ссылаться на эти концепции без долгих объяснений.
  • Опционально, но желательно: Kafka на уровне internals (партиции, ISR, consumer groups), потому что 90% production Flink-стеков сидят на Kafka, и многие архитектурные решения Flink (например, exactly-once через 2PC) специфичны для transactional Kafka producer.
Kafka internals: log-сегменты и механика хранения Kafka transactional producer — механизм транзакций

Если вы что-то из этого пропустили — рекомендую пройти соответствующий курс перед началом. Этот курс не остановится для повторения basics.

WARNING

Курс не для тех, кто хочет “начать с Flink”. Если ваше понимание stream processing ограничено просмотром нескольких YouTube-туториалов, эта серия будет фрустрирующей. Каждый модуль предполагает, что у вас уже есть rough mental model — мы её углубляем, а не строим с нуля.

Baseline курса — Flink 2.2, current stable на май 2026. Это значит:

  • DataSet API удалён (deprecated в 1.12, removed в 2.0). Если у вас legacy-код на DataSet — мигрируйте на DataStream с Boundedness.BOUNDED или Table API.
  • Scala API удалён (deprecated в 1.18, removed в 2.0). Если у вас Scala-код — мигрируйте на Java DataStream или используйте community-fork.
  • SourceFunction/SinkFunction удалены (deprecated в 1.14/1.15, removed в 2.0). Если у вас старые connectors — мигрируйте на Source V2 (FLIP-27) / Sink V2 (FLIP-191).
  • Disaggregated state доступен (FLIP-423, GA в 2.0). Это означает state, который хранится не в локальном RocksDB-инстансе, а в DFS (s3, hdfs), доступный через cache.
  • ForStDB — новый state backend, оптимизированный под disaggregated режим. Покроем в модуле 10.
  • AI integration (CREATE MODEL, ML_PREDICT, VECTOR_SEARCH) появилась в 2.1 и развилась в 2.2. Покроем в модуле 16.
  • Adaptive Scheduler — default для streaming-режима с 2.0. Default Scheduler доступен, но не рекомендуется для новых развёртываний.
  • Kubernetes Operator — recommended deployment на 2026. YARN — legacy, поддерживается, но мало кто использует.

Курс ориентируется на 2.2, но в исторических контекстах обсуждает, что было в 1.18/1.19/1.20, потому что многие production-инсталляции ещё там сидят, и upgrade-стратегии — отдельный важный навык.

Как учиться по этому курсу

Несколько практических рекомендаций.

Скачайте Flink source code и держите рядом.

git clone https://github.com/apache/flink.git
cd flink
git checkout release-2.2

В каждом deep-уроке курс ссылается на конкретные классы — org.apache.flink.runtime.dispatcher.Dispatcher, org.apache.flink.runtime.taskexecutor.TaskExecutor. Открывайте их в IDE параллельно с чтением. Понимание приходит не от чтения курса, а от того, что вы видите код глазами и проверяете утверждения курса.

Запускайте job-ы локально в режиме single-process.

./bin/start-cluster.sh
./bin/flink run examples/streaming/WordCount.jar

Локальный mini-cluster — отличный полигон. JM и TM работают в одной JVM, можно подцепить дебаггер и пройтись по реальному checkpoint flow.

Не пропускайте labs. В каждом модуле будет 1-2 lab-задания, часто на собственном Flink-кластере в Docker Compose. Часть из них требует терпения (поднять Kafka + Flink + RocksDB) — но это единственный способ получить мышечную память.

Используйте курс как карту, не как учебник. Цель — не запомнить все детали, а знать структуру и куда смотреть. Идеальный workflow: вы читаете урок про checkpoint internals, через месяц у вас в проде падает чекпоинт с непонятной ошибкой, вы возвращаетесь к уроку, находите нужный раздел, и оттуда быстро доходите до причины. Это и есть value.

Что дальше

Следующий урок — детальный roadmap всех 21 модуля курса. После него — tour по source code: как разложен репозиторий Apache Flink, какие модули важны, как работает FLIP-процесс.

После intro-блока (модули 00-01) идёт глубокое погружение: архитектура (модуль 02), network stack (03), memory model (04), state (05), checkpoints (06), watermarks (08). Это — фундамент. После этого — специальные темы: SQL/Calcite (09), disaggregated state (10), adaptive scheduling (11), exactly-once (12), и так далее до production-практик и capstone.


Как создавался курс

Курс создан при участии Claude (Anthropic) как соавтора: ИИ помогал писать материалы, структурировать темы, генерировать примеры кода и диаграммы. Каждая глава проходила ручную сверку с первоисточниками — спецификациями, документацией, исходным кодом рассматриваемых систем — но гарантировать 100% точность невозможно.

Если вы заметили неточность, опечатку или хотите предложить улучшение — напишите в Telegram-группу курса. Это самый ценный вклад в курс, который вы можете сделать.


Углублённое изучение с Claude

Курс рассчитан на самостоятельное изучение, но любая теория быстрее ложится, если задавать вопросы. Рекомендую держать рядом браузерное расширение Claude (claude.com/download) — оно работает с контентом открытой страницы: выделяете кусок урока и спрашиваете напрямую.

Сценарии, которые особенно хорошо работают для углублённого погружения:

  • «Объясни проще» / «дай ещё один пример» — когда формулировка из урока не дошла с первого раза.
  • «Покажи, как это устроено на уровне кода / железа» — когда хочется спуститься на слой ниже того, что даёт урок.
  • «Как это связано с [другая тема курса]» — когда нужно увязать концепцию с тем, что было раньше.
  • «У меня в проекте стек X — как применить?» — когда хочется примерить материал на свой реальный кейс.

Это не замена курсу, а способ ускорить интеграцию материала в вашу картину мира. Если что-то из ответов Claude расходится с уроком — присылайте в Telegram-группу, курс будет уточнён.


Нашли ошибку?

Если заметили неточность, опечатку или хотите предложить улучшение:

Telegram-группа курса
Обсуждение, вопросы, предложения

Telegram-канал

Подписывайтесь, чтобы узнавать об обновлениях и новых курсах:

@levoely_channel
Новости, обновления, новые курсы

Проверка знанийKnowledge check
Вы как Flink-инженер видите в production метрики: backpressure на 4 из 12 операторов, p99 checkpoint duration 38s (alert порог 30s), всё это происходит ровно в момент когда у вас в кластере 8 TM, и нагрузка стабильная, нет пиков. Почему знание internals принципиально для диагностики этого инцидента, и какие классы Flink (high-level) вы бы изучили в первую очередь?
ОтветAnswer
Без internals у вас есть только метрики и догадки — "наверное, надо увеличить чекпоинт interval" или "может быть, что-то с диском". С internals вы знаете: backpressure на конкретных операторах означает, что какой-то downstream-оператор не успевает обрабатывать байты, и upstream упирается в credit-based flow control (модуль 03). Это даёт первую гипотезу: возможно, slow path — это checkpoint snapshot, который alignment-блокирует поток данных. Если alignment-time высокий (метрика alignmentDurationNanos), то нужно копнуть в CheckpointBarrierHandler (модуль 06) или включить unaligned checkpointing. Если alignment низкий, но async-snapshot долгий — копать в RocksDB snapshot pipeline (модуль 05): incremental checkpoint, размер SSTable, network throughput на DFS. Классы в первую очередь: CheckpointCoordinator (orchestration), CheckpointBarrierHandler (alignment), RocksDBKeyedStateBackend (snapshot mechanics). Без знания этих классов и их взаимодействия диагноз остаётся гаданием.

Проверьте понимание

Результат: 0 из 0
Аналитический
Вопрос 1 из 4. Production-инцидент: Flink job показывает backpressure на 4 операторах из 12. Какой подход к диагностике корректен с точки зрения internals?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 3