Learning Platform
Глоссарий Troubleshooting
Урок 11.02 · 24 мин
Начальный
streamingevent timewatermarkswindowsexactly-once

В прошлом уроке мы говорили о batch — накопил данные за окно, прогнал, сохранил. У этой модели есть фундаментальное ограничение: между событием и его попаданием в аналитику проходит часы или сутки. Для отчётов CFO это нормально. Для обнаружения мошенничества, реагирования на сбои инфраструктуры, real-time recommendations — нет. В этих сценариях нужен другой шаблон — streaming.

Streaming обрабатывает события в момент их появления, без накопления в окно. Это другая инженерная модель с другими понятиями. Этот урок про базу — для глубины есть отдельные курсы (Kafka, Flink, Spark Streaming).

Что такое поток событий

Поток — это бесконечная последовательность сообщений, каждое из которых описывает одно событие. Сообщения приходят непрерывно, в произвольном темпе, в порядке, который не гарантируется. У потока нет «конца», в отличие от batch-окна.

Поток событий

События возникают в источнике непрерывно. Stream-processor читает их по одному (или микро-пакетами) и реагирует мгновенно.

Источникклик / заказ / сенсорЛюбое место, где события рождаются: пользовательские клики, заказы в e-commerce, показания IoT-датчиков, логи сервера, события Kafka.
event 1
Stream brokerKafka / KinesisРаспределённый лог сообщений: Kafka, AWS Kinesis, Google Pub/Sub, Azure Event Hubs. Хранит события и отдаёт их consumer-ам в порядке, гарантированном внутри партиции.
event 2
ProcessorFlink / SparkStream-processor: Apache Flink, Spark Structured Streaming, Kafka Streams. Читает события и применяет логику: фильтры, агрегаты, joins, обновление состояния.
SinkDWH / DB / alertКуда уходит результат: запись в DWH, обновление операционной базы, отправка алерта, обновление кэша.

В отличие от batch, тут нет «вчерашнего окна». Каждое событие проходит через систему за миллисекунды-секунды. Если в систему пришёл подозрительный заказ — алерт срабатывает в момент, а не утром следующего дня.

Event time vs processing time

Это первое и самое важное различие, которое отличает streaming от batch. У каждого события есть две временные метки:

Event time — когда событие реально произошло в источнике. Например, пользователь нажал кнопку «купить» в мобильном приложении в 14:23:15.

Processing time — когда событие попало в систему обработки. Например, через 30 секунд после клика, в 14:23:45 — мобильное приложение синхронизировалось с бэкендом.

В идеальном мире event time и processing time почти совпадают. В реальности — нет. Между ними бывают задержки от миллисекунд до часов:

  • Мобильник был в самолёте — событие пришло через 4 часа после клика.
  • Сетевая задержка между регионами — 500 ms между Европой и Сингапуром.
  • Очередь Kafka переполнилась — consumer догоняет полчаса.
Event time vs processing time

Реальное время события (event time) и время его обработки (processing time) могут сильно расходиться. Streaming-системы должны уметь работать с обеими.

14:23:00event timeПользователь нажал кнопку в приложении.
14:23:00processing timeВ идеальном мире система обработала событие в тот же миг.
14:23:00event time
14:25:30processing time +2.5 минВ реальности сеть была медленной, и событие дошло через 2.5 минуты.
14:23:00event time
18:23:00processing time +4 часаПользователь был в самолёте, события синхронизировались только при подключении к Wi-Fi 4 часа спустя.

Большинство аналитических метрик считается по event time: «выручка за час 14:00-15:00» означает события, фактически произошедшие в этом интервале. Это правильный подход, но он требует, чтобы система умела ждать запоздалые события.

Windows в streaming

В streaming тоже есть окна, но они работают иначе, чем в batch. Окно создаётся динамически в процессе обработки, и в нём накапливаются события за определённый период.

Tumbling windows — непересекающиеся фиксированные окна. Например, окна по 1 минуте: [14:00, 14:01), [14:01, 14:02), и т.д. Каждое событие попадает ровно в одно окно по своему event time.

Hopping windows (или sliding windows в некоторых системах) — окна с фиксированной длиной и фиксированным шагом, могут перекрываться. Например, длина 5 минут, шаг 1 минута: [14:00, 14:05), [14:01, 14:06), [14:02, 14:07). Одно событие попадает в несколько окон.

Sliding windows — окна, которые движутся вместе с каждым событием. В Flink это специальный тип, используется для rolling-метрик.

Session windows — окна группируются по периодам активности. Если между событиями одного пользователя прошло меньше N минут — они в одной сессии. Если больше — началась новая сессия. Длина окна заранее неизвестна.

Типы окон в streaming

Tumbling — окна не пересекаются. Hopping — пересекаются с фиксированным шагом. Session — длина определяется активностью.

Tumbling14:00-14:05Фиксированные непересекающиеся окна по 5 минут. Каждое событие попадает в одно окно.
14:05-14:10
14:10-14:15
14:15-14:20
Hopping14:00-14:05Окна по 5 минут со сдвигом 1 минута. Перекрываются. Используется для rolling-метрик.
14:01-14:06
14:02-14:07
14:03-14:08
Sessionuser A: 14:01-14:08Сессия пользователя A: активность с 14:01 до 14:08, потом пауза 15 минут — следующее событие начнёт новую сессию.
user A: 14:25-14:30
user B: 14:03-14:09

Watermarks

Главный вопрос streaming с event time: когда закрывать окно? Если окно [14:00, 14:05), можно ли публиковать результат в 14:05:00? А вдруг ещё придёт запоздалое событие с event time 14:04:30, которое сейчас в пути?

Эту проблему решают watermarks (водяные знаки). Watermark — это метка вида: «мы видели все события с event time меньше T». Это сигнал процессору: окна, чьё время полностью меньше T, можно безопасно закрывать и публиковать результат.

Watermark обычно отстаёт от текущего processing time на некоторое окно толерантности: например, «watermark = max(event_time) - 5 минут». Это значит: мы готовы ждать запоздалые события до 5 минут, потом публикуем результат.

Текущий event_time max:  14:08:00
Watermark:               14:03:00  (= max - 5 минут)
-> Окна [14:00, 14:02) и [14:02, 14:03) можно закрывать.
-> Событие с event_time 14:04 ещё может прийти — оно попадёт в открытое окно.
NOTE

Watermarks — это компромисс между свежестью и точностью. Маленький watermark (например, 1 минута) — данные публикуются быстро, но запоздалые события теряются или попадают в специальную side output. Большой watermark (1 час) — данные надёжнее, но публикуются с задержкой.

Что делать с событиями, пришедшими после закрытия окна? Тут несколько стратегий:

  • Drop — игнорировать. Простейший вариант, теряем точность.
  • Side output — отправлять в отдельный поток для специальной обработки (логирование, ручной разбор).
  • Allowed lateness — держать окно «полузакрытым» ещё какое-то время, переоткрывая для запоздавших.
  • Update mode — отправлять корректирующее событие (insert delta) в downstream.

Exactly-once

Третье ключевое понятие streaming — гарантии доставки. Возможны три уровня:

At-most-once. Сообщение обрабатывается 0 или 1 раз. Просто, но небезопасно: при сбое события теряются.

At-least-once. Сообщение обрабатывается минимум 1 раз, но при сбоях может быть обработано повторно. Безопасно от потерь, но возможны дубликаты. Самый частый дефолт в простых streaming-системах.

Exactly-once. Сообщение обрабатывается ровно 1 раз — никаких потерь, никаких дубликатов. Самая сильная гарантия и самая дорогая в реализации.

Exactly-once в streaming реализуется через комбинацию:

  • Транзакционная запись в sink (Kafka transactions, two-phase commit в DWH).
  • Idempotent producers на стороне отправителя.
  • Checkpoints в процессоре — снэпшоты состояния, к которым можно откатиться при сбое.

Flink, Spark Structured Streaming, Kafka Streams все поддерживают exactly-once при определённых конфигурациях.

Простой пример: rolling count в Kafka + consumer

Чтобы было совсем конкретно, представим пайплайн: пользователи кликают на сайте, события улетают в Kafka, простой consumer считает количество кликов по странам за последние 5 минут.

Producer (на сайте, после клика):

producer.send('user-clicks', value={
    'user_id': user_id,
    'country': country,
    'page': page,
    'event_time': datetime.utcnow().isoformat()
})

Consumer (псевдо-Flink логика):

stream = env.from_kafka_topic('user-clicks')

stream \
    .key_by(lambda event: event['country']) \
    .window(TumblingEventTimeWindows.of(Time.minutes(5))) \
    .with_watermark(BoundedOutOfOrderness(Duration.of_minutes(2))) \
    .aggregate(lambda events: {'country': events[0]['country'], 'count': len(events)}) \
    .add_sink(KafkaSink('country-clicks-5min'))

Что тут происходит:

  • Группируем события по country.
  • Используем tumbling windows по 5 минут по event_time.
  • Watermark — толерантность 2 минуты к запоздалым событиям.
  • В каждом окне считаем count.
  • Результат пишем в другой Kafka-топик.

Этот consumer работает 24/7 и каждые 5 минут публикует свежие агрегаты. Никакого ночного job-а, никакого batch — данные мгновенно отражают реальность.

Когда нужен streaming

Не всё нужно делать в streaming. Хорошие случаи:

  • Фрод-детекция. Подозрительный платёж нужно отклонить за секунды.
  • Realtime-метрики. Дашборд DevOps с задержкой 30 секунд для обнаружения сбоев.
  • Streaming ETL. Простая чистка/обогащение данных «на пути» в DWH.
  • Realtime recommendations. Обновить рекомендации в момент взаимодействия.

Плохие случаи для streaming:

  • Тяжёлая аналитика по большим окнам. Месячные отчёты лучше делать batch — streaming на месячных окнах сложен и нестабилен.
  • Сценарии с late-arriving в дни. Если данные часто опаздывают на сутки, watermark будет огромным, streaming становится бессмысленным.
  • Простая аналитика без требований к свежести. Если CFO смотрит отчёт раз в день, не надо ради этого городить streaming.
Kafka: distributed commit log — фундамент streaming pipeline Spark Structured Streaming: watermarks и windows в продакшене
TIP

В 2026 году многие команды переоценивают streaming. Реальная потребность в realtime обычно ограничивается операционными сценариями (фрод, алерты, recommendations). Для аналитики batch чаще достаточно. Старший DE умеет говорить «нет» необоснованному streaming.

Попробуй сам

Возьми любой продукт, которым пользуешься. Подумай, какие там процессы должны работать в streaming, а какие — в batch. Push-уведомление о подозрительном входе в аккаунт — streaming. Месячный отчёт по подпискам — batch. Recommendations на главной — может быть и то, и другое. Подумай, что определяет выбор. Обычно это бизнес-требование к латентности и стоимость инфраструктуры.

Проверка знанийKnowledge check
В чём разница между event time и processing time в streaming-обработке?
ОтветAnswer
Event time — это момент, когда событие реально произошло в источнике (например, пользователь нажал кнопку в 14:23). Processing time — это момент, когда событие попало в систему обработки (например, в 14:25 после сетевой задержки). Эти две метки могут расходиться от миллисекунд до часов из-за сетевых задержек, офлайн-устройств, переполненных очередей. Большинство аналитических метрик считается по event time — это семантически правильно. Но event time требует watermarks, чтобы понимать, когда можно закрывать окна, не теряя запоздалых событий.

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Чем event time отличается от processing time?

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

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

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

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