Потоковая обработка

Проектирование стриминговых систем: масштаб

Netflix обрабатывает 2.5 триллиона событий в день. Uber - 1 миллион поездок в день с real-time ценообразованием. Twitter - 500 миллионов твитов в день. Каждая из этих систем проектировалась вокруг backpressure, ordering и fault tolerance - три кита production streaming. Без них система работает на demo, но падает под нагрузкой.

  • **LinkedIn Samza**: streaming система на Kafka. 7 трлн сообщений в день. Backpressure через Kafka pull-model. Fault tolerance через Kafka offset checkpoints
  • **Uber Flink**: real-time surge pricing. Backpressure при пиковой нагрузке (NYE, концерты). Fault tolerance: checkpoint каждые 30 сек, RTO < 1 мин
  • **Cloudflare**: 100B+ DNS запросов/день через streaming pipeline. Горячие ключи - популярные домены. Решение: два уровня агрегации с salting

Backpressure: когда консьюмер медленнее продьюсера

2016 год. Twitter переводит Heron на production. Главная проблема Storm: нет механизма backpressure - fast producer, slow consumer = OOM и каскадные падения. Backpressure - механизм, при котором медленный downstream сигнализирует upstream замедлить производство. Без него буферы переполняются и система падает.

Стратегии: (1) Pull-based: consumer сам запрашивает данные когда готов (Kafka: consumer poll). (2) Credit-based: upstream получает 'кредит' (N сообщений) и останавливается когда кредит исчерпан (Flink). (3) Drop + retry: дропаем сообщения при перегрузке, consumer идемпотентен (real-time метрики). (4) Blocking: producer блокируется - простейший вариант, но deadlock risk.

ML-параллель: backpressure в streaming pipeline = gradient accumulation в training. Когда GPU не успевает обработать батч - увеличиваем шаг накопления. Те же механизмы: downstream сигнализирует upstream (memory pressure → reduce batch_size). Reactive Streams (Java 9+) стандартизирует backpressure через Publisher.request(N).

Kafka consumer использует pull-based модель. В чём преимущество перед push-based?

Упорядоченность: глобальная vs per-partition

Глобальная упорядоченность событий в распределённой системе невозможна без координации (→ bottleneck). Практическое решение: гарантируем упорядоченность только внутри partition/key. Kafka: все сообщения с одним key → одна partition → упорядочены. Транзакции пользователя → упорядочены по user_id, не глобально.

Out-of-order events: в реальности события приходят не по порядку (сеть, retry, разные источники). Flink watermarks решают это: watermark(t) означает 'все события до t уже получены'. Window ждёт watermark перед вычислением. Trade-off: больший allowed_lateness → более точный результат, но большая задержка вывода.

Почему глобальная упорядоченность в Kafka недостижима без потери производительности?

Партиционирование: масштабирование через шардинг

Партиционирование - горизонтальное масштабирование стриминга. Kafka topic с 12 partitions = 12 параллельных consumer'ов. Стратегии: (1) Hash partition по ключу - равномерное распределение, упорядоченность по ключу. (2) Round-robin - максимальный параллелизм, нет упорядоченности. (3) Range partition - диапазоны ключей, локальность для window-операций. (4) Custom - по бизнес-логике (гео, tenant).

Горячие ключи - главная проблема в стриминге. Twitter: один trending hashtag → 90% событий в одну partition. Решения: salting (добавить суффикс 0-9), двухэтапная агрегация, adaptive partitioning (Flink автоматически), custom partitioner. Аналог в ML: class imbalance в streaming training - те же паттерны oversampling/undersampling.

Что такое 'горячий ключ' в стриминговой системе и как его решить?

Fault Tolerance: checkpoints и восстановление

Стриминговая система работает 24/7. Узел упал - что происходит? Flink: distributed snapshot (Chandy-Lamport алгоритм). Каждые N секунд: синхронный checkpoint всего состояния (operator state + Kafka offsets) в durable storage (S3, HDFS). При падении: restart с последнего checkpoint, replay событий из Kafka от checkpoint offset.

Exactly-once vs at-least-once: exactly-once в Flink требует 2-phase commit с Kafka (KafkaSink с transactional producer). Стоимость: latency +checkpoint interval, throughput -20-30%. Для большинства аналитики - at-least-once достаточно (idempotent aggregation). Exactly-once критичен для финансовых транзакций.

Exactly-once гарантирует что событие обрабатывается ровно один раз физически

Exactly-once означает что результат обработки виден ровно один раз, даже если физически событие обрабатывается несколько раз при восстановлении

При replay после checkpoint события обрабатываются снова, но state уже содержит их результат - повторная обработка идемпотентна. Это semantic guarantee, а не физическое ограничение

После восстановления из Flink checkpoint происходит replay событий из Kafka. Почему это не вызывает дублирование?

Связанные темы

Production стриминг стоит на трёх китах:

  • Exactly-Once Semantics — Fault tolerance реализует exactly-once через checkpoint + idempotent replay
  • Windowing и время — Out-of-order events решаются через watermarks - связано с ordering
  • Stream-Table Duality — Паттерны проектирования используют stream-table duality для stateful операций

Ключевые идеи

  • **Backpressure**: pull-based (Kafka) или credit-based (Flink). Медленный consumer не должен убивать систему - lag растёт, не OOM.
  • **Ordering**: глобальная упорядоченность = bottleneck. Per-partition ordering + watermarks для out-of-order events.
  • **Горячие ключи**: salting (key+suffix) + двухэтапная агрегация. Trending hashtag в одну partition = катастрофа.
  • **Fault tolerance**: Chandy-Lamport checkpoint = operator state + Kafka offset в S3. Restart → replay от checkpoint offset.
  • **Exactly-once**: semantic guarantee через 2PC + idempotency. Физически событие может обработаться несколько раз.

Вопросы для размышления

  • Flink checkpoint каждые 5 секунд с RocksDB state. При checkpoint 100GB state на S3 - какой retention нужен и как checkpoint влияет на throughput?
  • Горячий ключ решён через salting с 10 buckets. Но события одного user_id теперь в 10 partitions - как агрегировать с гарантией upорядоченности?
  • При восстановлении из checkpoint Kafka replay занимает 3 минуты. Downstream системы ждут. Как минимизировать RTO без уменьшения checkpoint interval?

Связанные уроки

  • stream-14 — Stream-Table Duality - фундамент для понимания проектирования
  • stream-09 — Exactly-Once - ключевое свойство fault tolerant стриминга
  • stream-08 — Windowing и время влияют на upорядоченность и fault tolerance
  • stream-16 — Паттерны проектирования - основа для интервью по системному дизайну
  • ds-08-vector-clocks — Kafka/Kinesis как distributed queue: те же принципы backpressure и ordering
  • dist-14-sharding
Проектирование стриминговых систем: масштаб

0

1

Войти