Каковы будут некоторые соображения для выбора операций со скользящими окнами без сохранения состояния (например, reduceByKeyAndWindow) и выбора сохранения состояния (например, через updateStateByKey или нового mapStateByKey) при обработке потока последовательных сеансов конечных событий с помощью Spark Streaming?
Например, рассмотрим следующий сценарий:
Носимое устройство отслеживает физические упражнения, выполняемые владельца. Устройство автоматически обнаруживает, когда начинается упражнение, и испускает сообщение; испускает дополнительные сообщения, пока упражнение (например, частота сердечных сокращений); и, наконец, испускает сообщение, когда упражнение выполнено.
Желаемый результат - поток агрегированных записей за сеанс тренировки. то есть все события одного и того же сеанса должны быть объединены вместе (например, чтобы каждый сеанс мог быть сохранен в одной строке БД). Обратите внимание, что каждый сеанс имеет конечную длину, но весь поток из нескольких устройств является непрерывным. Для удобства предположим, что устройство генерирует GUID для каждого сеанса тренировки.
Я вижу два подхода для обработки этого прецедента с помощью Spark Streaming:
-
Использование неперекрывающихся окон и сохранение состояния. Состояние сохраняется на каждый GUID со всеми соответствующими ему событиями. Когда приходит новое событие, состояние обновляется (например, с помощью mapWithState), и в случае, если событие является "завершением сеанса тренировки", будет выведена агрегированная запись на основе состояния, а ключ удален.
-
Использование перекрывающих скользящих окон и сохранение только первых сеансов. Предположим, что скользящее окно длины 2 и интервал 1 (см. Диаграмму ниже). Также предположим, что длина окна 2 X (максимальное возможное время тренировки). В каждом окне события агрегируются с помощью GUID, например. используя reduceByKeyAndWindow. Затем все сеансы, которые начинаются во второй половине окна, сбрасываются, а остальные сеансы испускаются. Это позволяет использовать каждое событие ровно один раз и гарантирует, что все события, принадлежащие одному сеансу, будут объединены вместе.
Диаграмма для подхода № 2:
Only sessions starting in the areas marked with \\\ will be emitted. ----------- |window 1 | |\\\\| | ----------- ---------- |window 2 | |\\\\| | ----------- ---------- |window 3 | |\\\\| | -----------
Плюсы и минусы я вижу:
Подход №1 менее дорогостоящий, но требует сохранения и управления состоянием (например, если число одновременных сеансов увеличивается, состояние может увеличиться, чем память). Однако, если максимальное количество одновременных сеансов ограничено, это может не быть проблемой.
Подход №2 в два раза дороже (каждое событие обрабатывается дважды) и с более высокой задержкой (максимальное время выполнения 2 X), но более простым и легко управляемым, поскольку состояние не сохраняется.
Что было бы лучшим способом справиться с этим вариантом использования - есть ли какой-либо из этих подходов "правильный", или есть ли лучшие способы?
Какие другие плюсы и минусы следует принимать во внимание?