Распределенные вычисления и Apache Spark: Масштабируемость и отказоустойчивость 0:04
Современные системы обработки данных, такие как инфраструктуры Google, Facebook и Amazon, требуют работы с огромными массивами информации, измеряемыми сотнями терабайт. Решением этой задачи стали так называемые «складские» компьютеры (warehouse-scale computers) — кластеры из тысяч стандартных серверов, объединенных в единую вычислительную среду. В данной статье рассматриваются подходы к программированию таких систем, роль Apache Spark и механизмы, обеспечивающие их эффективность и отказоустойчивость.
Архитектура «складских» компьютеров и проблема ввода-вывода 5:01
Концепция «складского» компьютера, популяризированная Луисом Баррозу (Luiz Barroso) в его книге Datacenter as a Computer, предполагает использование товарных ПК (commodity PCs), соединенных через Ethernet. Основная мотивация перехода от одиночных узлов к кластерам — необходимость повышения пропускной способности ввода-вывода (I/O bandwidth). Обработка данных, которая на одном узле заняла бы 23 дня, на 1000 узлах выполняется за 33 минуты.
Основные особенности архитектуры:
- Иерархия сети: Узлы объединены в стойки, на вершине каждой из которых находится коммутатор (top-of-rack switch). Скорость сети внутри стойки значительно выше, чем между стойками.
- Иерархия памяти: Существует колоссальный разрыв в пропускной способности между оперативной памятью (DRAM) и сетью/дисками (дискретные величины до двух порядков).
- Отказоустойчивость: При масштабах в тысячи серверов поломки происходят ежечасно, даже если среднее время безотказной работы одного узла составляет 25 лет.
Для коммуникации между узлами, работающими под управлением разных экземпляров ОС и не имеющими общего адресного пространства, используется модель передачи сообщений (message passing).
Распределенные файловые системы: Хранение данных 18:02
Для предотвращения потери данных в случае выхода из строя узла или коммутатора стойки, используется распределенная файловая система (например, Google File System — GFS, или ее open-source аналог HDFS).
- Разделение: Файлы разбиваются на блоки (обычно 64–256 МБ).
- Репликация: Блоки копируются на разные узлы, предпочтительно в разных стойках.
- Управление: Мастер-узел (name node) хранит метаданные о расположении реплик. Клиенты обращаются к нему, чтобы узнать, где находятся блоки, а затем читают данные напрямую с узлов-хранилищ (data nodes).
Модель MapReduce: Первые шаги к автоматизации 27:39
Классическая модель MapReduce была призвана упростить распределенную обработку данных, скрывая сложность передачи сообщений. Она опирается на функциональные примитивы:
- Map: Применяет функцию к каждому элементу входных данных, не мутируя их, что обеспечивает легкую параллелизуемость и возможность повторного выполнения.
- Shuffle/Sort: Промежуточный этап, гарантирующий, что все значения с одинаковыми ключами попадут к одному редусеру.
- Reduce: Агрегирует значения для каждого ключа.
Эта модель эффективно справляется с отказами: если узел с mapper-задачей умирает, scheduler перезапускает задачу на другом узле, используя реплицированные данные. Однако MapReduce имеет существенные ограничения: модель линейна и неэффективна для итеративных алгоритмов (например, PageRank), так как требует записи каждого промежуточного результата на диск.
Apache Spark и Resilient Distributed Datasets (RDD) 58:36
Apache Spark был разработан для преодоления недостатков MapReduce, прежде всего за счет интенсивного использования оперативной памяти. Ключевой абстракцией здесь является Resilient Distributed Dataset (RDD) — неизменяемая, распределенная коллекция записей.
- Lineage (Родословная): Spark отслеживает цепочку преобразований, создавших RDD. Это позволяет восстановить данные в случае сбоя без необходимости постоянной записи на диск.
- Преобразования и действия: Spark разделяет операции на трансформации (создают новые RDD:
map,filter,join) и действия (возвращают результат:collect,count). - Оптимизация: Spark автоматически анализирует зависимости между RDD. «Узкие» зависимости (narrow dependencies) позволяют выполнять оптимизации, такие как слияние циклов (fusion), что значительно повышает производительность за счет снижения нагрузки на память.