2.3 Hadoop MapReduce
2.3.3 Sistema de Escalonamento
O Hadoop começou utilizando uma forma básica de escalonamento: a fila (FIFO). As tarefas eram agendadas e esperavam por sua vez pela ordem de chegada. Porém, a estratégia não era muito eficiente, pois uma tarefa poderia utilizar apenas parte dos recursos disponíveis para ela, deixando outras em espera, apesar da disponibilidade de recursos. Para melhorar, posteriormente introduziram o conceito de prioridades5, o qual coloca à frente da fila as tarefas com as maiores prioridades. No entanto, essa abordagem também pode ser ineficiente se não houver algo mais sofisticado, como preemptividade, pois uma tarefa de baixa prioridade pode ser demasiadamente longa e deixar outra de maior prioridade na fila. Ou ainda, em ambiente multi-usuário, tarefas de baixa prioridade sofrer com inanição. Apesar disso, as versões contemporâneas do Hadoop ainda fazem uso do escalonamento FIFO, mas permitem a utilização de outros escalonadores. Além do FIFO, que é o padrão, estão disponíveis escalonador justo (fair scheduler) e escalonador por capacidade (capacity scheduler).
O escalonador justo suporta múltiplos usuários6, preempção e prioridades. Ele busca distribuir os recursos de forma uniforme, permitindo uma parcela média de utilização entre usuários. Logo, um usuário que submete mais trabalhos que outro não irá receber mais recursos por isso. No entanto, caso exista apenas um usuário, esse utilizará todo o cluster. Na versão MRv1 do Hadoop, o escalonador justo utiliza o conceito de pools e slots para escalonar tarefas.
5Método setJobPriority() na classe JobClient. 6Considera-se usuário uma aplicação MapReduce
Cada usuário tem um pool, e cada pool tem uma quantidade de slots, de modo que cada slot é relacionado a uma tarefa de mapeamento ou redução. Portanto, os trabalhos novos com suas tarefas vão ocupando slots livres. Ainda, o escalonador oferece a possibilidade de personalizar a capacidade mínima/máxima de slots para o pool em arquivo XML. Entretanto, slots não têm restrições à utilização de recursos (CPU e memória), adotando capacidade máxima. Dessa forma, uma tarefa com prioridade baixa e execução longa vai deixar na fila outra de prioridade alta, exceto se for pausada e entregar o slot. Numa outra situação, uma tarefa de mapeamento pode utilizar todo o recurso enquanto que uma outra de redução estaria sem recurso. Nesse sentido, houve uma melhora significativa com o YARN MRv2, pois o escalonamento do escalonador justo ocorre com base na utilização quantificada de recursos, e não com slots com capacidade ilimitada, como no escalonador justo da versão MRv1. Por exemplo, em uma negociação entre os daemons gerente de recursos e mestre de aplicação, a aplicação ganha o direito de utilizar determinada quantidade de recursos (CPU e memória) em uma máquina (gerente de nó), e não o todo da máquina, como ocorre em slots.
O escalonador de capacidade foi desenvolvido para suportar o compartilhamento de recursos entre vários clientes, os quais são normalmente empresas. Essas empresas podem fazer uso de equipamentos comuns no cluster, mas estão logicamente separadas. Dessa forma, o escalonador de capacidade visa escalonar trabalhos para múltiplos inquilinos. O escalonador deve oferecer ao inquilino garantias de que suas aplicações terão recursos mínimos. Nesse modelo, a vantagem é que a união das empresas financia a manutenção do sistema. Em contrapartida, as necessidades desses inquilinos no cluster são variáveis, pois ora sub-utilizam, ora super-utilizam recursos. Assim, um inquilino pode utilizar em algum momento os recursos que não estão sendo utilizados por outros inquilinos. Portanto, a elasticidade é uma característica fundamental para o escalonador, valorizando a relação melhor custo benefício.
2.3.4 Sistema de Arquivos Distribuído do Hadoop - HDFS
O HDFS - Hadoop Distributed File System foi projetado tendo como referência o Google File System (GFS), para ser o sistema de arquivos distribuído do Hadoop. Possui código aberto implementado em Java, e sua proposta é trabalhar com grande volume de dados em máquinas de alto ou baixo custo, conectadas em rede local. O volume de dados pode atingir a ordem de petabytes, o que significa uma potencial divisão entre hosts, compatível com a capacidade de cada um deles. Logo, a tolerância a falhas é essencial no HDFS, devido,
DataNode A DataNode P DataNode Q
Arquivo
Workers Bloco1 Bloco2 Bloco3
Cliente HDFS Bloco2 Bloco1 Bloco3 Escreva DataNodes A,P,Q Quero Escrever Bloco1,2,3 Bloco2 Bloco3 FsImage EditLog FsImage EditLog FsImage Mescla Mescla Novo EditLog Status
NameNode Secondary NameNode
Após Mesclar
64 MB
Bloco1
64 MB 64 MB
Figura 8 – Armazenamento de blocos de arquivos no HDFS
Adaptado de (HEDLUND, 2011)
especialmente, ao número de máquinas que o sistema pode envolver. Em caso de falha em alguma máquina do HDFS, o sistema deve, de forma transparente, detectar e recuperar, reiniciando ou transferindo o trabalho para outra máquina apta. A arquitetura utilizada é a gerente/trabalhador, composta pelo gerente do tipo nó de nome (NameNode) e os trabalhadores do tipo nó de dados (DataNode), contendo ainda o recuperador de estado, do tipo nó de nome secundário, como descrito na Seção 2.3.1.
O HDFS trabalha com blocos de dados, de forma semelhante ao que foi especificado para o GFS. Dessa forma, antes do armazenamento físico no HDFS, ocorre a divisão dos dados em blocos de tamanhos fixos, que por padrão é 64 MB. Isso também é feito em sistemas de arquivos tradicionais, que normalmente possuem blocos pequenos, na ordem de bytes. Entretanto, como o HDFS trabalha com arquivos grandes, um arquivo pode possuir vários blocos e estar em um ou vários hosts. Além disso, o HDFS replica blocos em hosts diferentes, sendo uma forma de aumentar o nível de segurança. Assim como no GFS, por padrão, o HDFS replica três cópias de blocos na rede, sendo esse parâmetro configurável. Na distribuição, nós de dadospodem estar próximos fisicamente, como conectados no mesmo switch de rede (mesmo armário de telecomunicação), ou podem estar distantes fisicamente, como conectados através de backbonesde rede (dois ou mais armários de telecomunicação). No segundo caso, por questão de desempenho e confiabilidade, para recuperação de falha e escalonamento, duas das réplicas devem estar próximas fisicamente (mesmo armário). Além disso, o nó de nomes não armazena blocos, ficando essa tarefa para os nós de dados.
nome: FsImage e EditLog. O primeiro é onde estão as informações sobre blocos de arquivos, como localização de réplicas e espaço de nomes (namespaces) de diretórios e arquivos. O segundo é semelhante, porém é mais dinâmico, pois armazena o registro de todas as alterações que ocorrem nos metadados dos arquivos. Portanto, a tendência é que o EditLog vá crescendo infinitamente. Porém, para evitar esse aumento excessivo, o nó de nomes secundário faz uma có- pia do EditLog e FsImage, mesclando-os e enviando cópia para ao nó de nomes primário. Então, o nó de nomes cria outro arquivo EditLog vazio para iniciar novo ciclo. Esse procedimento de segurança é um ponto de verificação (checkpoint). Em caso de falha no nó de nomes, faz-se uma reinicialização do servidor gerente e, após reinício, o gerente faz a mesclagem do EditLog com o FsImage, gerando novo FsImage para leitura e configuração do cluster. Em caso de perda do arquivo FsImage, o nó de nomes secundário contém a cópia, embora alterações que não foram mescladas estarão perdidas. O ponto de verificação é feito mediante um tempo configurável no Hadoop. Portanto, as funções do nó de nomes secundário são limpar periodicamente o arquivo log EditLog e manter uma cópia de segurança do arquivo FsImage. A Figura 8 mostra uma visão de alto nível das transações com blocos de arquivos, FsImage e EditLog.