Что такое распределённая обработка данных (Distributed Processing) и какие фреймворки для неё используются?

«Что такое распределённая обработка данных (Distributed Processing) и какие фреймворки для неё используются?» — вопрос из категории Архитектура, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Распределённая обработка данных — это парадигма, при которой вычислительная задача разделяется на множество подзадач, выполняющихся параллельно на кластере связанных компьютеров (нод). Цели: масштабируемость (обработка больших данных), отказоустойчивость и высокая производительность.

Ключевые концепции:

  • Распределённое хранение: Данные разделены и реплицируются по узлам кластера (HDFS, Amazon S3, Cassandra).
  • Параллельное выполнение: Задача разбивается на этапы (stages), которые выполняются на разных узлах.
  • Отказоустойчивость: При падении узла его задача перезапускается на другом (благодаря восстанавливаемым данным и checkpoint-ам).

Основные фреймворки и модели:

Фреймворк Модель/Язык Ключевая абстракция Преимущества
Apache Hadoop MapReduce Batch, Java Пары ключ-значение (Map → Shuffle → Reduce) Высокая отказоустойчивость, обработка данных, не помещающихся в память.
Apache Spark Batch, Streaming, Java/Scala/Python/PySpark RDD (Resilient Distributed Dataset), DataFrame/Dataset In-memory вычисления (в 100x быстрее Hadoop), единый стек для batch/streaming, богатый API.
Apache Flink Streaming-first, Java/Scala DataStream (бесконечные потоки) Очень низкая задержка, точный контроль над состоянием (state), обработка событий в реальном времени.
Akka (на JVM) Акторная модель, Scala/Java Акторы (Actors) Асинхронная обработка сообщений, построение высоконагруженных и отзывчивых распределённых систем.

Пример на Apache Spark (Scala/Java API):

// Чтение данных из распределённой файловой системы
val textFile = sparkSession.read.textFile("hdfs:///logs/app.log")
// Распределённая обработка: фильтрация и агрегация
val errorCount = textFile
  .filter(line => line.contains("ERROR")) // Преобразование фильтрации
  .count() // Действие (action), запускающее вычисление
println(s"Количество ошибок в логах: $errorCount")

Типичные use cases: ETL-конвейеры, анализ больших наборов данных, машинное обучение на кластере, обработка потоковых событий (логи, телеметрия).