Watermark в Spark: когда позднее событие уже не меняет окно

Заказ произошёл в 12:04, но до потока добрался в 12:11. Если витрина считает продажи по десятиминутным окнам времени события, он относится к окну 12:00–12:10, а не к минуте поступления. Structured Streaming может обновить уже открытый агрегат, пока хранит состояние этого окна. Watermark задаёт, когда старое состояние можно очистить и перестать ждать слишком поздние события.

Допустим, задержка watermark равна десяти минутам. После наблюдения события с временем 12:14 ориентир примерно 12:04: заказ с event time 12:09 ещё может обновить окно 12:00–12:10. Когда максимальное наблюдаемое время продвинулось до 12:21 и watermark достиг примерно 12:11, окно, закончившееся в 12:10, уже может быть закрыто. Позже пришедший заказ с временем 12:04 не восстановит этот агрегат автоматически.

Слова «примерно» здесь важны: watermark продвигается в механике trigger, а гарантия Spark асимметрична. Данные внутри указанной задержки не отбрасываются как слишком поздние из-за watermark, но данные за её пределами могут обрабатываться по-разному в зависимости от момента продвижения. Не обещайте бизнесу точное правило по настенным часам только на основании выражения «10 minutes».

Почему задержка — это бизнес-решение

Короткий допуск быстрее освобождает память и раньше публикует финальный результат, но отбрасывает больше опоздавших событий. Длинный допуск повышает полноту, зато дольше держит состояние окон и задерживает финализацию в append-режиме. Сначала измерьте распределение разницы между временем события и временем появления в потоке: медиану, 95-й и 99-й процентили, отдельные периоды аварий источника.

Если 99,5% заказов приходят за 15 минут, а оставшиеся могут задержаться на часы, выберите, какие из них должны попасть в оперативную витрину. Для финансовой сверки может понадобиться отдельный batch-пересчёт или поток исправлений. Watermark не превращает позднюю запись в ошибку источника; он ограничивает состояние конкретного streaming-запроса.

Время события должно быть настоящим

Если вместо времени заказа подставить момент чтения из Kafka, все давно произошедшие события выглядят свежими. Витрина будет своевременно обрабатывать их технически, но строить неверные исторические окна. Сохраняйте исходный event timestamp, его часовую зону и время поступления отдельно. На контрольном наборе проверьте события ровно на границе окна, с опозданием внутри допуска и намного позднее.

Для нескольких потоков, соединённых в одном запросе, Spark выбирает глобальный watermark из отдельных источников. По умолчанию используется минимум: медленный поток может задерживать очистку состояния и публикацию результата. Настройка на максимум ускоряет продвижение, но способна агрессивнее терять данные от отстающего источника. Это ещё один повод измерять задержки каждого входа, а не только общую скорость job.

Наконец, проверьте режим вывода. В update-режиме окно может публиковать промежуточные изменения, поэтому downstream должен уметь обновлять результат по ключу окна. В append-режиме финальная строка выходит позже, когда окно считается закрытым. Иначе два отчёта по одному потоку могут выглядеть противоречиво, хотя используют разные обещания о готовности результата.

Полезный диагностический срез — доля событий по величине опоздания: до минуты, до десяти минут, до часа и позже. Стройте его по исходным логам до отбрасывания слишком поздних записей, иначе измерение будет смещено: поток покажет только те события, которые допустил текущий watermark. Если источник иногда останавливается на три часа, распределение в обычный день не описывает поведение во время аварии.

Закрытое окно не следует исправлять простой повторной отправкой того же события в Kafka. Его event time не изменится, а streaming-запрос снова сочтёт запись поздней. Восстановление требует отдельного процесса: пакетно пересчитать затронутые окна из полного источника и обновить целевую таблицу по ключу окна или направить исправление в предусмотренный канал. Такое правило лучше определить до запуска витрины, особенно для оплат.

Если мониторинг показывает мало поздних событий, проверьте часы устройств. Событие с ошибочной датой в далёком будущем может продвинуть наблюдаемое максимальное event time и ускорить watermark, после чего нормальные записи окажутся «старыми». Валидация timestamp на входе и отдельный учёт аномальных часов защищают агрегат лучше, чем бездумное увеличение допустимой задержки.

В курсе Data Engineering Fast‑Track поток Kafka обрабатывается Spark и попадает в lakehouse. Посмотрите программу, чтобы проектировать свежесть витрины с учётом event time и поздних данных.

Если разница возникла ещё при чтении Kafka, сначала проверьте момент commit offset.

Продолжить на практике

  • Data Engineering Fast‑Track: Kafka → Airflow → Spark ↗

    Практический fast-track по data engineering: за 4–6 недель собираем рабочий конвейер Kafka → Spark → Lakehouse под управлением Airflow. Разберём batch и streaming, окна и watermark, схемы и контракты. Мини‑проекты, Docker Compose, шаблоны DAG и пайплайнов. Курс подойдёт инженерам, аналитикам и тем, кто хочет освоить современные пайплайны данных с уверенным Python.