Introdução
A partir do Hadoop 2.0, foi introduzido o novo modelo de gerenciamento de recursos do YARN, que melhora a utilização do cluster, o gerenciamento unificado de recursos e o compartilhamento de dados. Com base na configuração de um cluster Hadoop pseudo-distribuído, esta seção apresenta a arquitetura, o princípio de funcionamento, a configuração, o desenvolvimento e as técnicas de monitoramento do framework YARN.
Este laboratório exige conhecimentos básicos de programação Java.
As etapas de desenvolvimento incluem os arquivos Java completos. Cole cada arquivo inteiro no seu editor e, em seguida, veja como o cliente envia uma aplicação e como o ApplicationMaster solicita e inicia um contêiner de tarefa.
Arquitetura e componentes do YARN
Nesta etapa, explore a arquitetura do YARN e as funções de seus componentes.
Introduzido no Hadoop 0.23 como parte do MapReduce 2.0 (MRv2), o YARN revolucionou o gerenciamento de recursos e o agendamento de tarefas em clusters Hadoop:
- Separação das funções do JobTracker: o
MRv2separa as funções doJobTrackerem daemons distintos: oResourceManager, responsável pelo gerenciamento de recursos, e oApplicationMaster, responsável pelo agendamento e monitoramento de tarefas. - ResourceManager global: cada aplicação tem um
ApplicationMastercorrespondente. A aplicação pode ser um trabalho MapReduce ou um DAG que descreve o trabalho. - Framework de processamento de dados: o
ResourceManager, oSlavee oNodeManagerformam um framework no qual o ResourceManager administra os recursos de todas as aplicações. - Componentes do ResourceManager: o
Scheduleraloca recursos com base em restrições como capacidade e filas, enquanto oApplicationsManagergerencia o envio de trabalhos e a execução do ApplicationMaster. - Alocação de recursos: os requisitos de recursos são definidos por contêineres de recursos, que incluem itens como memória, CPU, disco e rede.
- Função do NodeManager: o NodeManager monitora o uso de recursos dos contêineres e envia informações ao ResourceManager e ao Scheduler.
- Tarefas do ApplicationMaster: o ApplicationMaster negocia contêineres de recursos com o Scheduler, acompanha o estado e monitora o progresso.
A figura a seguir mostra a relação entre esses componentes:

O YARN mantém a compatibilidade da API com as versões anteriores, permitindo a transição sem interrupções para a execução de tarefas MapReduce. Conhecer a arquitetura e os componentes do YARN é essencial para gerenciar recursos e agendar tarefas com eficiência em clusters Hadoop.
Iniciar os daemons do Hadoop
Nesta etapa, inicie os daemons do Hadoop necessários para executar a aplicação YARN.
Antes de estudar os parâmetros de configuração e as técnicas de desenvolvimento de aplicações YARN, inicie os daemons do Hadoop para que eles fiquem disponíveis.
Primeiro, clique duas vezes no terminal Xfce da área de trabalho. Em seguida, digite o comando abaixo para mudar para o usuário hadoop:
su - hadoop
Dica: a senha do usuário 'hadoop' é 'hadoop'.
Depois de mudar de usuário, você poderá iniciar os daemons relacionados ao Hadoop, incluindo os frameworks HDFS e YARN.
Digite os comandos a seguir no terminal para iniciar os daemons:
/home/hadoop/hadoop/sbin/start-dfs.sh
/home/hadoop/hadoop/sbin/start-yarn.sh
Quando a inicialização terminar, você poderá executar o comando jps para verificar se os daemons correspondentes estão em execução.
hadoop:~$ jps
3378 NodeManager
3028 SecondaryNameNode
3717 Jps
2791 DataNode
2648 NameNode
3240 ResourceManager
Preparar o arquivo de configuração
Nesta etapa, vamos conhecer o arquivo yarn-site.xml, um dos principais arquivos de configuração do Hadoop, e ver quais configurações do cluster YARN podem ser definidas nele.
Para evitar alterações acidentais no arquivo de configuração, é melhor copiá-lo para outro diretório e abrir a cópia.
Digite o comando a seguir no terminal para criar um diretório para o arquivo de configuração:
mkdir /home/hadoop/hadoop_conf
Em seguida, copie o arquivo de configuração principal do YARN, yarn-site.xml, do diretório de instalação para o diretório recém-criado.
Digite o comando a seguir no terminal para fazer a cópia:
cp /home/hadoop/hadoop/etc/hadoop/yarn-site.xml /home/hadoop/hadoop_conf/yarn-site.xml
Agora, use o editor vim para abrir o arquivo e conferir seu conteúdo:
vim /home/hadoop/hadoop_conf/yarn-site.xml
Como funciona o arquivo de configuração
Nesta etapa, examine os parâmetros de configuração usados pelo cluster Hadoop em execução.
No framework YARN, há duas funções importantes: ResourceManager e NodeManager. Portanto, cada item de configuração do arquivo define uma configuração para um desses dois componentes.
Este arquivo aceita muitos itens de configuração, mas, por padrão, não contém configurações personalizadas. Por exemplo, o arquivo que abrimos agora contém apenas o atributo aux-services, definido durante a configuração anterior do cluster Hadoop pseudo-distribuído, como mostra o exemplo a seguir:
hadoop:~$ cat /home/hadoop/hadoop/etc/hadoop/mapred-site.xml
...
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
Esse item de configuração define os serviços dependentes que precisam ser executados no NodeManager. O valor especificado é mapreduce_shuffle, que indica que o YARN precisa executar o serviço padrão exigido pelos programas MapReduce.
Isso significa que os itens de configuração que não aparecem no arquivo não funcionam? Não exatamente. Quando os parâmetros de configuração não são especificados explicitamente no arquivo, o framework YARN do Hadoop lê os valores padrão armazenados em arquivos internos. Todos os itens definidos explicitamente no arquivo yarn-site.xml substituem os valores padrão. Assim, o sistema Hadoop pode se adaptar a diferentes cenários de uso.
Itens de configuração do ResourceManager
Entender e configurar corretamente as opções do ResourceManager no arquivo yarn-site.xml é essencial para gerenciar recursos e executar trabalhos com eficiência em um cluster Hadoop. Veja a seguir um resumo dos principais itens de configuração relacionados ao ResourceManager:
yarn.resourcemanager.address: disponibiliza aos clientes o endereço para enviar e encerrar aplicações. A porta padrão é 8032.yarn.resourcemanager.scheduler.address: disponibiliza ao ApplicationMaster o endereço para solicitar e liberar recursos. A porta padrão é 8030.yarn.resourcemanager.resource-tracker.address: disponibiliza ao NodeManager o endereço para enviar heartbeats e obter tarefas. A porta padrão é 8031.yarn.resourcemanager.admin.address: disponibiliza aos administradores o endereço para executar comandos de gerenciamento. A porta padrão é 8033.yarn.resourcemanager.webapp.address: endereço da interface Web para consultar informações do cluster. A porta padrão é 8088.yarn.resourcemanager.scheduler.class: especifica o nome da classe principal do scheduler (por exemplo, FIFO, CapacityScheduler ou FairScheduler).- Configuração de threads:
yarn.resourcemanager.resource-tracker.client.thread-countyarn.resourcemanager.scheduler.client.thread-count
- Alocação de recursos:
yarn.scheduler.minimum-allocation-mbyarn.scheduler.maximum-allocation-mbyarn.scheduler.minimum-allocation-vcoresyarn.scheduler.maximum-allocation-vcores
- Gerenciamento do NodeManager:
yarn.resourcemanager.nodes.exclude-pathyarn.resourcemanager.nodes.include-path
- Configuração de heartbeat:
yarn.resourcemanager.nodemanagers.heartbeat-interval-ms
Esses parâmetros permitem ajustar o comportamento do ResourceManager, a alocação de recursos, o gerenciamento de threads, o controle do NodeManager e os intervalos de heartbeat em um cluster Hadoop. Conhecer esses itens ajuda a prevenir problemas e a manter o funcionamento correto do cluster.
Itens de configuração do NodeManager
Configurar as opções do NodeManager no arquivo yarn-site.xml é essencial para gerenciar recursos e tarefas com eficiência em um cluster Hadoop. Veja a seguir um resumo dos principais itens de configuração relacionados ao NodeManager:
yarn.nodemanager.resource.memory-mb: especifica a memória física total disponível para o NodeManager. Esse valor permanece constante durante a execução do YARN.yarn.nodemanager.vmem-pmem-ratio: define a proporção entre a memória virtual e a memória física alocada. O valor padrão é2.1.yarn.nodemanager.resource.cpu-vcores: define o número total de CPUs virtuais disponíveis para o NodeManager. O valor padrão é8.yarn.nodemanager.local-dirs: caminho para armazenar resultados intermediários no NodeManager. É possível configurar vários diretórios.yarn.nodemanager.log-dirs: caminho para o diretório de logs do NodeManager. É possível configurar vários diretórios.yarn.nodemanager.log.retain-seconds: tempo máximo de retenção dos logs do NodeManager. O valor padrão é 10800 segundos (3 horas).
Esses parâmetros permitem ajustar a alocação de recursos, o gerenciamento de memória, os caminhos dos diretórios e a retenção de logs para otimizar o desempenho e o uso de recursos pelo NodeManager em um cluster Hadoop. Conhecer esses itens ajuda a manter o funcionamento correto do cluster e a execução eficiente das tarefas.
Consulta de itens de configuração e valores padrão
Para explorar todos os itens de configuração disponíveis no YARN e em outros componentes comuns do Hadoop, consulte os arquivos de configuração padrão fornecidos pelo Apache Hadoop. Use os links a seguir para acessar as configurações padrão:
Itens de configuração do YARN:
Arquivos de configuração comuns:
- core-default.xml (core-site.xml)
- hdfs-default.xml (hdfs-site.xml)
- mapred-default.xml (mapred-site.xml)
Ao consultar essas configurações padrão, você encontrará descrições detalhadas de cada item e sua finalidade. Isso ajuda a entender o papel de cada parâmetro na arquitetura do Hadoop.
Depois de revisar as configurações, feche o editor vim para concluir a consulta às opções de configuração do Hadoop.
Criar diretórios e arquivos do projeto
Nesta etapa, crie os arquivos-fonte da aplicação. Vamos montar uma aplicação YARN completa e mínima: um cliente envia o ApplicationMaster, que solicita um contêiner de tarefa para imprimir uma saudação.
Primeiro, crie o diretório do projeto. Digite o comando a seguir no terminal:
mkdir /home/hadoop/yarn_app
Em seguida, crie dois arquivos de código-fonte no projeto.
O primeiro arquivo é Client.java. Use o comando touch no terminal para criá-lo:
touch /home/hadoop/yarn_app/Client.java
Depois, crie o arquivo 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
Escrever o código do cliente
Nesta etapa, escreva o cliente completo que enviará a aplicação. Continue usando o usuário hadoop. Abra o arquivo-fonte:
vim /home/hadoop/yarn_app/Client.java
Substitua todo o conteúdo do arquivo pelo código abaixo, incluindo a declaração do pacote e as instruções de importação. No Vim, digite :set paste e pressione Enter. Em seguida, pressione i para entrar no modo de inserção. Cole o arquivo completo e espere todas as linhas aparecerem. Depois, pressione Esc e digite :wq para salvar e sair.
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 se conecta ao ResourceManager e obtém um ID de aplicação. O cliente copia o JAR para o HDFS e o declara como o recurso local app.jar, para que o YARN possa disponibilizá-lo no diretório de trabalho do ApplicationMaster. O contexto de inicialização fornece o classpath e o comando Java; o contexto de envio especifica a fila e os recursos do contêiner.
O classpath usa as bibliotecas Hadoop instaladas, compartilhadas pelos contêineres neste laboratório de nó único. Não é necessário baixar dependências com Maven ou Gradle. Este exemplo foi criado para o cluster do laboratório, que não usa Kerberos.
Depois do envio, o cliente consulta o relatório da aplicação até que ela chegue a um estado final e verifica o resultado. O método killApplication só é usado se a aplicação ultrapassar o limite de três minutos. Na última etapa, vamos compilar e executar as duas classes.
Escrever o código do ApplicationMaster
Nesta etapa, escreva o ApplicationMaster completo. Ele se registra no ResourceManager, solicita um contêiner, inicia uma saudação por meio do NodeManager e informa o resultado da tarefa.
Abra o arquivo usando o usuário hadoop:
vim /home/hadoop/yarn_app/ApplicationMaster.java
Substitua todo o conteúdo do arquivo pelo código abaixo. Digite :set paste e pressione Enter. Em seguida, pressione i. Cole o arquivo completo e espere todas as linhas aparecerem. Depois, pressione Esc e digite :wq para salvar e sair.
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 gerencia o registro e as solicitações de recursos. Cada chamada a allocate envia um heartbeat e retorna os contêineres recém-alocados e os estados dos contêineres concluídos. NMClient executa o comando no contêiner alocado. Esse loop de consulta síncrona mantém o exemplo autocontido, sem classes de callback ou métodos auxiliares indefinidos.
A tarefa imprime Hello-from-YARN no log do contêiner. Um código de saída igual a zero faz com que o ApplicationMaster encerre o registro com o estado SUCCEEDED. Em seguida, o cliente informa esse estado final. O ResourceManager pode arredondar os 256 MB solicitados para cima, até o valor mínimo de alocação. Enquanto aguarda, o loop continua enviando heartbeats.
Processo de inicialização da aplicação
Nesta etapa, compile e execute as duas classes Java que você escreveu e, em seguida, consulte a aplicação na interface Web do ResourceManager. Continue no terminal usando o usuário hadoop.
Compilar e iniciar a aplicação
Acesse o diretório dos arquivos-fonte:
cd /home/hadoop/yarn_app
Crie o diretório de saída:
mkdir -p classes
Compile os dois arquivos-fonte completos usando as bibliotecas Hadoop já instaladas na VM. A opção --release 8 gera classes compatíveis com o runtime Java 8 do Hadoop, mesmo que o compilador padrão seja mais recente:
javac --release 8 -cp "$(/home/hadoop/hadoop/bin/hadoop classpath --glob)" -d classes Client.java ApplicationMaster.java
Uma mensagem sobre APIs obsoletas não é um problema; a compilação não deve apresentar erros. Empacote as classes compiladas:
jar cf yarn-app.jar -C classes .
Envie a aplicação com o cliente e salve a saída. O último argumento é o JAR que o cliente enviará ao HDFS para o 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
Aguarde a conclusão da aplicação. Entre as mensagens de log do Hadoop, você deverá ver:
Application ID: application_<timestamp>_<sequence>
Final status: SUCCEEDED
O ID muda a cada execução. A saudação é gravada no log do contêiner da tarefa, enquanto o cliente exibe o ID da aplicação e o resultado final. Nesta execução, você usará seu próprio cliente e ApplicationMaster, e não um exemplo MapReduce pré-compilado separado.
Consultar os resultados da execução da aplicação
Abra o Firefox na área de trabalho e acesse:
http://localhost:8088
Na lista de aplicações, localize LabEx YARN Hello usando o ID exibido no terminal. O estado deve ser FINISHED e o estado final deve ser SUCCEEDED. Clique no ID da aplicação para consultar os detalhes. O ResourceManager acompanha a aplicação; o ApplicationMaster gerencia o contêiner da tarefa, e o NodeManager executa esse contêiner.
Resumo
Com base na configuração de um cluster Hadoop pseudo-distribuído, este laboratório apresenta a arquitetura, o princípio de funcionamento, a configuração, o desenvolvimento e as técnicas de monitoramento do framework YARN. O curso fornece diversos trechos de código e arquivos de configuração. Leia-os com atenção.



