Потоковая обработка
Apache Flink: внутреннее устройство
Netflix обрабатывает 2 миллиона событий в секунду через Apache Flink. Один worker из 200 упал - что происходит? Без checkpointing - перезапуск с нуля, потеря всего накопленного состояния за часы работы. С checkpointing - восстановление за 15 секунд, exactly-once гарантия. LinkedIn хранит 10+ ТБ агрегированного состояния в Flink через RocksDB. Uber делает zero-downtime деплой через savepoints. Это и есть разница между Flink-приложением в продакшне и экспериментом.
- **Netflix** - 2M событий/сек, checkpoint каждые 10 сек на S3, RocksDB state backend для per-user состояния; recovery за ~15 секунд без потери данных
- **LinkedIn** - feed-ranking pipeline хранит 10+ ТБ состояния в EmbeddedRocksDB; инкрементальные checkpoint'ы снижают нагрузку на S3 с 30 мин до 45 сек
- **Uber** - zero-downtime деплой Flink-приложений через savepoints: stop → savepoint → deploy new version → restore from savepoint; водители не замечают обновления
Checkpointing
Netflix запускает Flink на 2 миллионах событий в секунду. Что происходит, если один из 200 worker'ов падает? Без checkpointing - перезапуск с нуля, потеря всего накопленного состояния. С checkpointing Flink восстанавливается за секунды, обработав ровно те же события без дублирования - **exactly-once semantics**.
**Checkpoint** - снимок всего распределённого состояния задачи в момент времени T: состояние каждого оператора + позиция в Kafka (offset). Flink использует алгоритм Chandy-Lamport: через поток вставляются специальные маркеры-«барьеры», которые синхронизируют снятие снимка без остановки обработки.
Почему Flink checkpoint не останавливает обработку данных во время снятия снимка?
Savepoints
Нужно обновить Flink-приложение с версии 1.2 на 1.3, изменив логику агрегации? Checkpoint нельзя использовать для этого - он автоматически управляется Flink и удаляется. **Savepoint** - это ручной checkpoint под полным контролем пользователя. Индустрия: Uber использует savepoints для zero-downtime деплоев своих Flink-приложений обработки поездок.
**Savepoint** vs **Checkpoint**: checkpoint - автоматический, управляется Flink, удаляется когда больше не нужен; savepoint - ручной (`flink savepoint <jobId>`), хранится вечно, совместим между версиями кода. Savepoint позволяет: обновить код, изменить parallelism, мигрировать на другой кластер.
| Свойство | Checkpoint | Savepoint |
|---|---|---|
| Управление | Автоматическое (Flink) | Ручное (оператор) |
| Жизненный цикл | Удаляется автоматически | Хранится вечно |
| Совместимость кода | Только та же версия | Между версиями (с uid) |
| Использование | Fault tolerance | Деплой, масштабирование, миграция |
| Команда | Настраивается в коде | flink savepoint / flink stop |
В чём ключевое различие savepoint и checkpoint в Flink?
State Backends
Flink-приложение считает уникальных пользователей за скользящее окно 7 дней. Для 100 миллионов пользователей хранить HyperLogLog-состояние в RAM - невозможно. **State backend** определяет где и как Flink хранит рабочее состояние: в памяти JVM или на диске через RocksDB.
Три backend'а: **HashMapStateBackend** (RAM JVM, быстро, ограничен heap), **EmbeddedRocksDBStateBackend** (локальный RocksDB, до терабайт состояния, checkpoint идёт в S3/HDFS), **legacy MemoryStateBackend** (только для разработки). LinkedIn использует RocksDB для хранения 10+ ТБ агрегированного состояния в feed-ranking pipeline.
| Backend | Хранение | Размер состояния | Checkpoint скорость | Use case |
|---|---|---|---|---|
| HashMapStateBackend | JVM heap | Сотни MB | Быстро (full) | Небольшое состояние, низкая latency |
| EmbeddedRocksDB | Локальный диск | Терабайты | Инкрементально | Большое состояние, длинные окна |
| MemoryStateBackend (legacy) | JVM heap | Мегабайты | В JM memory | Только разработка/тесты |
Когда следует выбирать EmbeddedRocksDBStateBackend вместо HashMapStateBackend?
Event Time vs Processing Time
Мобильное приложение логирует клик пользователя в 10:00:00, но из-за плохого соединения событие приходит на сервер в 10:05:32. В какое окно его поместить? Это фундаментальный вопрос потоковой обработки: **event time** (время когда событие произошло) vs **processing time** (время когда система его обработала).
**Event time** - метка времени внутри самого события, отражает реальный момент. **Processing time** - системное время сервера в момент обработки. **Ingestion time** - компромисс: время когда событие попало в Flink. Event time требует watermarks для управления опозданиями; processing time проще, но некорректен при задержках сети или batch-replay.
Flink гарантирует exactly-once для любых источников и приёмников
Exactly-once в Flink достигается только при использовании транзакционных sink'ов (Kafka transactions, JDBC с идемпотентными upserts). Запись в обычный файл или HTTP endpoint без транзакций даст at-least-once.
Checkpointing гарантирует exactly-once внутри Flink-графа. Но при recover'е sink может перезаписать уже отправленные данные. Kafka sink использует двухфазный коммит: данные отправляются в транзакции, которые подтверждаются только после успешного checkpoint'а.
Почему event time предпочтительнее processing time для большинства аналитических задач?
Ключевые идеи
- **Checkpointing** - алгоритм Chandy-Lamport: барьеры синхронизируют снимок состояния без остановки потока; при сбое откат до checkpoint + перечитать Kafka с сохранённого offset
- **Savepoints** - ручные checkpoint'ы под контролем оператора; используются для деплоя новых версий, изменения parallelism, миграции кластера без потери состояния
- **State backends**: HashMapStateBackend (RAM, быстро, до ~1 ГБ) vs EmbeddedRocksDB (диск, до ТБ состояния, инкрементальные checkpoint'ы)
- **Event time** vs **processing time**: event time детерминирован при replay, требует watermarks; processing time прост, но некорректен при задержках и batch-replay
Связанные темы
Flink internals - основа для понимания надёжных потоковых систем:
- Windowing и время — Event time и watermarks - механизм закрытия окон в stream processing
- Stream Processing основы — Batch vs stream, Flink vs Spark Streaming - база для углублённого изучения
Вопросы для размышления
- Flink checkpoint использует алгоритм Chandy-Lamport с барьерами. Что происходит с производительностью если checkpoint выполняется каждые 100 мс против каждые 10 секунд - какой trade-off?
- LinkedIn хранит 10 ТБ состояния в RocksDB с инкрементальными checkpoint'ами. Что произойдёт если нужно откатить состояние на 3 часа назад при обнаружении бага в логике - как это сделать через savepoints?
- Netflix использует event time для all аналитических pipeline'ов. Мобильное приложение может буферизовать события до 24 часов в offline режиме. Как настроить watermark strategy чтобы не ждать 24 часа перед закрытием каждого окна?