Введение
В Hadoop версии 2.0 и более поздних появилась новая схема управления ресурсами YARN. Она помогает эффективнее использовать ресурсы кластера, обеспечивает централизованное управление ими и позволяет совместно использовать данные. В этом разделе, опираясь на уже созданный псевдораспределённый кластер Hadoop, вы изучите архитектуру и принципы работы YARN, его конфигурацию, а также методы разработки и мониторинга приложений.
Для выполнения этой лабораторной работы необходимы базовые знания Java.
В шагах по разработке приведён полный исходный код Java. Вставьте каждый файл целиком в редактор, а затем разберитесь, как клиент отправляет приложение и как ApplicationMaster запрашивает и запускает контейнер для задачи.
Архитектура и компоненты YARN
На этом этапе изучите архитектуру YARN и назначение его компонентов.
YARN появился в Hadoop 0.23 как часть MapReduce 2.0 (MRv2) и изменил подход к управлению ресурсами и планированию заданий в кластерах Hadoop:
- Разделение функций JobTracker:
MRv2разделяет функцииJobTrackerмежду отдельными службами:ResourceManagerуправляет ресурсами, аApplicationMasterпланирует задания и отслеживает их выполнение. - Единый ResourceManager: каждому приложению соответствует свой
ApplicationMaster. Приложением может быть задание MapReduce или DAG, описывающий задание. - Среда выполнения и обработки данных:
ResourceManager,SlaveиNodeManagerобразуют среду, в которой ResourceManager управляет ресурсами всех приложений. - Компоненты ResourceManager:
Schedulerвыделяет ресурсы с учётом ограничений, например ёмкости и очередей, аApplicationsManagerобрабатывает отправку заданий и запуск ApplicationMaster. - Выделение ресурсов: требования к ресурсам задаются контейнерами, в описании которых указываются такие ресурсы, как память, процессор, диск и сеть.
- Роль NodeManager: NodeManager отслеживает использование ресурсов контейнерами и передаёт сведения ResourceManager и Scheduler.
- Задачи ApplicationMaster: ApplicationMaster согласует выделение контейнеров с Scheduler, отслеживает их состояние и контролирует ход выполнения.
Связи между компонентами показаны на рисунке:

YARN сохраняет совместимость API с предыдущими версиями, поэтому запущенные задания MapReduce можно перенести без сложных изменений. Чтобы эффективно управлять ресурсами и планировать задания в кластере Hadoop, важно понимать архитектуру YARN и назначение его компонентов.
Запуск служб Hadoop
На этом этапе запустите службы Hadoop, необходимые для работы приложения YARN.
Прежде чем изучать параметры конфигурации и разработку приложений YARN, запустите службы Hadoop. После этого они будут доступны для работы.
Сначала дважды щёлкните значок терминала Xfce на рабочем столе. В открывшемся терминале выполните команду, чтобы переключиться на пользователя hadoop:
su - hadoop
Подсказка: пароль пользователя hadoop — hadoop.
После переключения запустите службы, связанные с Hadoop, в том числе HDFS и YARN.
Выполните в терминале следующие команды:
/home/hadoop/hadoop/sbin/start-dfs.sh
/home/hadoop/hadoop/sbin/start-yarn.sh
После запуска можете выполнить команду jps, чтобы проверить, работают ли соответствующие службы.
hadoop:~$ jps
3378 NodeManager
3028 SecondaryNameNode
3717 Jps
2791 DataNode
2648 NameNode
3240 ResourceManager
Подготовка файла конфигурации
На этом этапе изучите один из основных файлов конфигурации Hadoop — yarn-site.xml — и выясните, какие параметры кластера YARN можно в нём задавать.
Чтобы случайно не изменить исходный файл конфигурации, скопируйте его в другой каталог, а затем откройте копию.
Сначала создайте каталог для файла конфигурации, выполнив в терминале команду:
mkdir /home/hadoop/hadoop_conf
Затем скопируйте основной файл конфигурации YARN yarn-site.xml из каталога установки в созданный каталог.
Выполните в терминале команду:
cp /home/hadoop/hadoop/etc/hadoop/yarn-site.xml /home/hadoop/hadoop_conf/yarn-site.xml
Откройте файл в редакторе vim и просмотрите его содержимое:
vim /home/hadoop/hadoop_conf/yarn-site.xml
Принцип работы файла конфигурации
На этом этапе рассмотрите параметры конфигурации, которые использует запущенный кластер Hadoop.
В среде YARN важны две роли: ResourceManager и NodeManager. Поэтому параметры в файле относятся к настройкам этих компонентов.
В файле можно задавать много параметров, но по умолчанию пользовательские настройки в нём отсутствуют. Например, в открытом сейчас файле указана только настройка aux-services, заданная ранее при настройке псевдораспределённого кластера Hadoop. Это показано на примере ниже:
hadoop:~$ cat /home/hadoop/hadoop/etc/hadoop/mapred-site.xml
...
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
Этот параметр задаёт службы, которые должны запускаться на NodeManager и от которых он зависит. Указанное нами значение — mapreduce_shuffle. Оно означает, что в YARN нужно запустить службу, необходимую программам MapReduce.
Значит ли это, что параметры, которых нет в файле, не работают? Не совсем. Если параметры конфигурации явно не указаны в файле, среда YARN в Hadoop считывает значения по умолчанию из внутренних файлов. Все параметры, явно заданные в yarn-site.xml, переопределяют значения по умолчанию. Это позволяет адаптировать Hadoop к различным сценариям использования.
Параметры конфигурации ResourceManager
Правильная настройка ResourceManager в файле yarn-site.xml необходима для эффективного управления ресурсами и выполнения заданий в кластере Hadoop. Ниже перечислены основные связанные с ним параметры:
yarn.resourcemanager.address: адрес, по которому клиенты отправляют приложения и останавливают их. Порт по умолчанию — 8032.yarn.resourcemanager.scheduler.address: адрес, по которому ApplicationMaster запрашивает и освобождает ресурсы. Порт по умолчанию — 8030.yarn.resourcemanager.resource-tracker.address: адрес, по которому NodeManager отправляет сигналы проверки связи и получает задания. Порт по умолчанию — 8031.yarn.resourcemanager.admin.address: адрес для команд администрирования. Порт по умолчанию — 8033.yarn.resourcemanager.webapp.address: адрес веб-интерфейса для просмотра сведений о кластере. Порт по умолчанию — 8088.yarn.resourcemanager.scheduler.class: полное имя основного класса планировщика, например FIFO, CapacityScheduler или FairScheduler.- Настройки потоков:
yarn.resourcemanager.resource-tracker.client.thread-countyarn.resourcemanager.scheduler.client.thread-count
- Выделение ресурсов:
yarn.scheduler.minimum-allocation-mbyarn.scheduler.maximum-allocation-mbyarn.scheduler.minimum-allocation-vcoresyarn.scheduler.maximum-allocation-vcores
- Управление NodeManager:
yarn.resourcemanager.nodes.exclude-pathyarn.resourcemanager.nodes.include-path
- Настройка сигналов проверки связи:
yarn.resourcemanager.nodemanagers.heartbeat-interval-ms
Эти параметры позволяют настраивать поведение ResourceManager, выделение ресурсов, обработку потоков, управление NodeManager и интервалы между сигналами проверки связи в кластере Hadoop. Знание этих настроек помогает предотвращать проблемы и поддерживать стабильную работу кластера.
Параметры конфигурации NodeManager
Настройки NodeManager в файле yarn-site.xml важны для эффективного управления ресурсами и задачами кластера Hadoop. Ниже перечислены основные связанные с ним параметры:
yarn.nodemanager.resource.memory-mb: общий объём физической памяти, доступный NodeManager. Это значение не меняется во время работы YARN.yarn.nodemanager.vmem-pmem-ratio: соотношение выделяемой виртуальной и физической памяти. По умолчанию —2.1.yarn.nodemanager.resource.cpu-vcores: общее число виртуальных процессоров, доступных NodeManager. Значение по умолчанию —8.yarn.nodemanager.local-dirs: путь к каталогам для хранения промежуточных результатов на NodeManager. Можно указать несколько каталогов.yarn.nodemanager.log-dirs: путь к каталогам журналов NodeManager. Можно указать несколько каталогов.yarn.nodemanager.log.retain-seconds: максимальное время хранения журналов NodeManager. По умолчанию — 10800 секунд (3 часа).
Эти параметры позволяют настраивать выделение ресурсов, управление памятью, пути к каталогам и срок хранения журналов, чтобы NodeManager эффективнее использовал ресурсы кластера Hadoop. Знание этих настроек помогает поддерживать стабильную работу кластера и эффективно выполнять задачи.
Справочные материалы по параметрам и значениям по умолчанию
Чтобы ознакомиться со всеми доступными параметрами YARN и других распространённых компонентов Hadoop, изучите файлы конфигурации по умолчанию, предоставленные Apache Hadoop. Вот ссылки на них:
Параметры конфигурации YARN:
Общие файлы конфигурации:
- core-default.xml (core-site.xml)
- hdfs-default.xml (hdfs-site.xml)
- mapred-default.xml (mapred-site.xml)
В этих файлах подробно описаны параметры конфигурации и их назначение. Изучив их, вы лучше поймёте роль каждого параметра в архитектуре Hadoop.
Закончив изучение настроек Hadoop, закройте редактор vim.
Создание каталогов и файлов проекта
На этом этапе создайте исходные файлы приложения. Вы соберёте минимальное, но полноценное приложение YARN: клиент отправит ApplicationMaster, который запросит один контейнер для задачи, выводящей приветствие.
Сначала создайте каталог проекта. Выполните в терминале команду:
mkdir /home/hadoop/yarn_app
Затем создайте в каталоге проекта два файла с исходным кодом.
Сначала создайте файл Client.java с помощью команды touch:
touch /home/hadoop/yarn_app/Client.java
Затем создайте файл ApplicationMaster.java:
touch /home/hadoop/yarn_app/ApplicationMaster.java
hadoop:~$ tree /home/hadoop/yarn_app/
/home/hadoop/yarn_app/
├── ApplicationMaster.java
└── Client.java
0 directories, 2 files
Написание кода клиента
На этом этапе напишите полный код клиента, который отправляет приложение. Продолжайте работать от имени пользователя hadoop. Откройте файл с исходным кодом:
vim /home/hadoop/yarn_app/Client.java
Полностью замените содержимое файла приведённым ниже кодом, включая объявление пакета и импорты. В Vim введите :set paste и нажмите Enter, а затем нажмите i, чтобы перейти в режим вставки. Вставьте файл целиком и дождитесь, пока появятся все строки. Затем нажмите Esc, введите :wq и сохраните файл, выйдя из редактора.
package com.labex.yarn.app;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.hadoop.yarn.api.records.*;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.client.api.YarnClientApplication;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.util.ConverterUtils;
public class Client {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
throw new IllegalArgumentException("Usage: Client /absolute/path/to/yarn-app.jar");
}
YarnConfiguration conf = new YarnConfiguration();
YarnClient client = YarnClient.createYarnClient();
client.init(conf);
client.start();
try {
YarnClientApplication application = client.createApplication();
ApplicationSubmissionContext context = application.getApplicationSubmissionContext();
ApplicationId id = context.getApplicationId();
FileSystem fs = FileSystem.get(conf);
Path destination = new Path(fs.getHomeDirectory(), "yarn-app/" + id + "/app.jar");
fs.mkdirs(destination.getParent());
fs.copyFromLocalFile(new Path(args[0]), destination);
FileStatus status = fs.getFileStatus(destination);
LocalResource jar = LocalResource.newInstance(
ConverterUtils.getYarnUrlFromPath(fs.makeQualified(destination)),
LocalResourceType.FILE, LocalResourceVisibility.APPLICATION,
status.getLen(), status.getModificationTime());
Map<String, LocalResource> resources = new HashMap<>();
resources.put("app.jar", jar);
Map<String, String> environment = new HashMap<>();
// The single-node lab uses the same Hadoop installation in every container.
environment.put("CLASSPATH", "./app.jar:" + System.getProperty("java.class.path"));
String command = ApplicationConstants.Environment.JAVA_HOME.$$()
+ "/bin/java -Xmx128m com.labex.yarn.app.ApplicationMaster"
+ " 1>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/stdout"
+ " 2>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/stderr";
ContainerLaunchContext launch = ContainerLaunchContext.newInstance(
resources, environment, Collections.singletonList(command), null, null, null);
context.setApplicationName("LabEx YARN Hello");
context.setQueue("default");
context.setResource(Resource.newInstance(256, 1));
context.setAMContainerSpec(launch);
client.submitApplication(context);
System.out.println("Application ID: " + id);
long deadline = System.currentTimeMillis() + 180000;
while (System.currentTimeMillis() < deadline) {
ApplicationReport report = client.getApplicationReport(id);
YarnApplicationState state = report.getYarnApplicationState();
if (state == YarnApplicationState.FINISHED
|| state == YarnApplicationState.FAILED
|| state == YarnApplicationState.KILLED) {
System.out.println("Final status: " + report.getFinalApplicationStatus());
if (report.getFinalApplicationStatus() != FinalApplicationStatus.SUCCEEDED) {
throw new IllegalStateException(report.getDiagnostics());
}
return;
}
Thread.sleep(1000);
}
client.killApplication(id);
throw new IllegalStateException("Application timed out after three minutes");
} finally {
client.stop();
}
}
}
YarnClient подключается к ResourceManager и получает идентификатор приложения. Клиент копирует JAR-файл в HDFS и объявляет его локальным ресурсом app.jar, чтобы YARN мог поместить его в рабочий каталог ApplicationMaster. Контекст запуска задаёт classpath и команду Java, а контекст отправки приложения — очередь и ресурсы контейнера.
Classpath использует установленные библиотеки Hadoop, общие для контейнеров в этом одновузловом лабораторном кластере. Загружать зависимости с помощью Maven или Gradle не нужно. Этот пример предназначен для кластера лабораторной работы, в котором не используется Kerberos.
После отправки клиент проверяет отчёт приложения, пока оно не перейдёт в конечное состояние, и проверяет итоговый статус. Метод killApplication вызывается, только если приложение не завершилось за три минуты. В заключительном шаге мы скомпилируем и запустим оба класса.
Написание кода ApplicationMaster
На этом этапе напишите полный код ApplicationMaster. Он зарегистрируется в ResourceManager, запросит один контейнер, запустит в нём команду приветствия через NodeManager и сообщит результат выполнения задачи.
Откройте файл от имени пользователя hadoop:
vim /home/hadoop/yarn_app/ApplicationMaster.java
Полностью замените содержимое файла приведённым ниже кодом. Введите :set paste и нажмите Enter, а затем нажмите i. Вставьте файл целиком и дождитесь, пока появятся все строки. Затем нажмите Esc, введите :wq и сохраните файл, выйдя из редактора.
package com.labex.yarn.app;
import java.util.Collections;
import org.apache.hadoop.yarn.api.ApplicationConstants;
import org.apache.hadoop.yarn.api.protocolrecords.AllocateResponse;
import org.apache.hadoop.yarn.api.records.*;
import org.apache.hadoop.yarn.client.api.AMRMClient;
import org.apache.hadoop.yarn.client.api.NMClient;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
public class ApplicationMaster {
public static void main(String[] args) throws Exception {
YarnConfiguration conf = new YarnConfiguration();
AMRMClient<AMRMClient.ContainerRequest> rm = AMRMClient.createAMRMClient();
NMClient nm = NMClient.createNMClient();
rm.init(conf);
nm.init(conf);
rm.start();
nm.start();
try {
rm.registerApplicationMaster("", 0, "");
AMRMClient.ContainerRequest request = new AMRMClient.ContainerRequest(
Resource.newInstance(256, 1), null, null, Priority.newInstance(0));
rm.addContainerRequest(request);
boolean launched = false;
long deadline = System.currentTimeMillis() + 120000;
while (System.currentTimeMillis() < deadline) {
// Each allocate call also sends a heartbeat to the ResourceManager.
AllocateResponse response = rm.allocate(launched ? 0.5f : 0.0f);
for (Container container : response.getAllocatedContainers()) {
if (launched) {
rm.releaseAssignedContainer(container.getId());
continue;
}
rm.removeContainerRequest(request);
String command = "/bin/echo Hello-from-YARN"
+ " 1>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/stdout"
+ " 2>" + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/stderr";
ContainerLaunchContext launch = ContainerLaunchContext.newInstance(
Collections.emptyMap(), Collections.emptyMap(),
Collections.singletonList(command), null, null, null);
nm.startContainer(container, launch);
launched = true;
}
for (ContainerStatus status : response.getCompletedContainersStatuses()) {
if (status.getExitStatus() != 0) {
throw new IllegalStateException(status.getDiagnostics());
}
rm.unregisterApplicationMaster(FinalApplicationStatus.SUCCEEDED,
"Hello container completed", "");
return;
}
Thread.sleep(1000);
}
rm.unregisterApplicationMaster(FinalApplicationStatus.FAILED,
"No successful container within two minutes", "");
throw new IllegalStateException("Container timed out");
} finally {
nm.stop();
rm.stop();
}
}
}
AMRMClient отвечает за регистрацию и запрос ресурсов. Каждый вызов allocate отправляет сигнал проверки связи и возвращает сведения о вновь выделенных контейнерах и статусах завершённых контейнеров. NMClient запускает команду в выделенном контейнере. В этом примере используется синхронный цикл опроса, поэтому не нужны неописанные классы обратного вызова или вспомогательные методы.
Задача выводит Hello-from-YARN в журнал своего контейнера. Если задача завершается с кодом 0, ApplicationMaster снимается с регистрации со статусом SUCCEEDED. После этого клиент выводит итоговый статус. ResourceManager может округлить запрошенные 256 МБ в большую сторону до минимального объёма выделения. Пока ApplicationMaster ожидает контейнер, цикл продолжает отправлять сигналы проверки связи.
Процесс запуска приложения
На этом этапе скомпилируйте и запустите два созданных Java-класса, а затем просмотрите сведения о приложении в веб-интерфейсе ResourceManager. Продолжайте работу в терминале от имени пользователя hadoop.
Компиляция и запуск приложения
Перейдите в каталог с исходными файлами:
cd /home/hadoop/yarn_app
Создайте каталог для результатов компиляции:
mkdir -p classes
Скомпилируйте оба исходных файла, используя библиотеки Hadoop, уже установленные в виртуальной машине. Параметр --release 8 создаёт классы, совместимые со средой выполнения Hadoop на Java 8, даже если по умолчанию используется более новая версия компилятора:
javac --release 8 -cp "$(/home/hadoop/hadoop/bin/hadoop classpath --glob)" -d classes Client.java ApplicationMaster.java
Предупреждение об устаревшем API можно не учитывать. Ошибок компиляции быть не должно. Упакуйте скомпилированные классы:
jar cf yarn-app.jar -C classes .
Отправьте приложение с помощью клиента и сохраните его вывод. Последний аргумент — JAR-файл, который клиент загрузит в HDFS для ApplicationMaster:
set -o pipefail
/home/hadoop/hadoop/bin/yarn jar /home/hadoop/yarn_app/yarn-app.jar com.labex.yarn.app.Client /home/hadoop/yarn_app/yarn-app.jar | tee /home/hadoop/yarn_app/application.log
Дождитесь завершения приложения. Среди сообщений Hadoop ожидайте увидеть:
Application ID: application_<timestamp>_<sequence>
Final status: SUCCEEDED
Идентификатор меняется при каждом запуске. Приветствие записывается в журнал контейнера задачи, а клиент выводит идентификатор приложения и итоговый статус. В этом запуске используются созданные вами клиент и ApplicationMaster, а не отдельный заранее собранный пример MapReduce.
Просмотр результатов выполнения приложения
Откройте Firefox на рабочем столе и перейдите по адресу:
http://localhost:8088
Найдите в списке приложений LabEx YARN Hello, используя идентификатор приложения, выведенный в терминале. Состояние приложения должно быть FINISHED, а итоговый статус — SUCCEEDED. Нажмите на идентификатор приложения, чтобы просмотреть подробную информацию. ResourceManager отслеживает приложение, ApplicationMaster управляет его контейнером задачи, а NodeManager выполняет эту задачу.
Итоги
Эта лабораторная работа продолжает изучение псевдораспределённого кластера Hadoop: вы познакомились с архитектурой и принципами работы YARN, его конфигурацией, а также методами разработки и мониторинга приложений. В курсе приведено много фрагментов кода и файлов конфигурации — внимательно изучите их.



