Baixe o app para aproveitar ainda mais
Prévia do material em texto
TECNOLOGIAS AVANÇADAS .................................................................. 3 INTRODUÇÃO AO HADOOP ................................................................... 3 Versões de Hadoop ................................................................................ 6 Sistema de Arquivos Distribuído ........................................................... 7 MAPREDUCE .......................................................................................... 7 MapReduce 1 ......................................................................................... 8 MapReduce 2 (YARN) ............................................................................ 9 Falhas .................................................................................................. 10 Map, Reduce e Shuffle ......................................................................... 13 Utilizando um Cliente SSH .................................................................. 29 CONCEITOS DO SISTEMA OPERACIONAL LINUX ................................ 33 Comandos do Linux ............................................................................. 36 Permissões de arquivo ........................................................................ 47 Hadoop Distributed Filesystem (HDFS) .............................................. 49 Blocos .................................................................................................. 50 NameNodes e DataNodes .................................................................... 50 HDFS Federado .................................................................................... 51 Alta Disponibilidade (HDFS High-Availability) .................................... 51 Entendendo o Sistema de Arquivos Distribuído .................................. 52 Comandos do Shell HDFS .................................................................... 56 JAVA AVANÇADO ................................................................................. 61 Eclipse ................................................................................................. 62 Criando um Projeto no Eclipse ............................................................ 66 Construindo o arquivo JAR .................................................................. 75 java –jar exemplo.jar .......................................................................... 80 Anotações ............................................................................................ 80 Maven .................................................................................................. 83 Resolvendo dependências ................................................................... 90 MAPREDUCE COM JAVA ....................................................................... 94 Dependências do projeto .................................................................... 98 Codificando o job MapReduce ........................................................... 105 Aplicativo ........................................................................................... 107 Funções combinadoras (combiner functions) ................................... 108 Construção do projeto ....................................................................... 110 Preparando o JAR do projeto ............................................................ 118 ADMINISTRAÇÃO DO CLUSTER ......................................................... 123 Gerenciamento de problema: estudo de caso com HBase ................ 124 BIBLIOGRAFIA .................................................................................. 135 TECNOLOGIAS AVANÇADAS INTRODUÇÃO AO HADOOP® A quantidade de dados armazenados no mundo está estimada em 16 Zettabytes (16 bilhões de Gigabytes - GB). Mas a projeção para 2020 é de 44 ZB. Somente o Facebook armazena 7 Petabytes (PB) por mês (IDC, 2016), sendo que 1 PB equivale a 1000 TB. São textos, sons, imagens, vídeos, enfim, tem-se o que se chama Big Data, que é definida em função de 3 V’s: - Grande Volume de dados (GB; TB; PB; ZB); - Variados formatos (texto, imagem, vídeo etc.); - Velocidade exponencial de crescimento. Para que se possa processar grandes massas de dados, opta-se pelo paralelismo de dados e controle (PACHECO, 1997), o que evita redimensionamento da capacidade de processamento (aumento de memória, CPU’s mais rápidas, e assim por diante) a cada incremento na quantidade de dados a processar. Um crescimento exponencial da quantidade a ser processada, levaria a uma constante readequação do sistema de computação. Visando processar dados de forma paralela, pode-se contar com um agrupamento de computadores, ou cluster, que deve oferecer comunicação de dados entre processos paralelos, balanceamento da carga e tolerância a falhas, e com Hadoop®, um framework para processamento em ambiente de Big Data. Desenvolvido pelo Yahoo!, atualmente é um projeto de código aberto (open source) de alto nível mantido pela The Apache™ Software Foundation. Um cluster Hadoop é uma plataforma de software que processa - de forma eficiente – um grande volume de informação, utilizando um grupo (cluster) de computadores ("nós" do cluster) trabalhando em paralelo, com os dados sendo distribuídos pelos nós, de forma replicada. Assim, caso ocorra uma falha em um nó, o dado replicado que está em outro nó é copiado para o nó onde a falha ocorreu. Ao passo que bancos de dados lidam bem com dados estruturados (organizados em entidades que possuem um formato definido, tais como tabelas de dados ou documentos XML), Hadoop lida bem com dados semiestruturados (como planilhas eletrônicas, que são organizadas em células, as quais podem conter qualquer tipo de dado) e dados não estruturados (que não possuem estrutura interna alguma, tais como textos e imagens). Processamento paralelo e distribuído de dados não é novidade. Em PACHECO (1997) são apresentados os principais conceitos que permitem ao leitor aprender as técnicas de programação paralela utilizando MPI (Message Passing Interface), uma biblioteca de extensões para C, C++ e Fortran, desenvolvida 1992 por universidades e empresas dos Estados Unidos e da Europa, e publicado em 1994. No MPI, os dados são acessados a partir de uma área de armazenamento na rede. O acesso a grandes quantidades de dados é um gargalo, pois requer grande largura de banda (de rede), o que faz com que vários nós fiquem ociosos (balanceamento de carga ruim). É bem mais rápido do que Hadoop, mas o esforço de programação é bem maior, além do que, não possui mecanismo de tolerância a falhas, a não ser que o programador cuide desse detalhe. Apenas um programa é criado, sendo executado por todos os nós do cluster de forma paralela. Cabe ao programador elaborar o código para cada nó do cluster, ou, um código para o nó mestre (pelo qual o processamento é iniciado) e outro código para os demais nós (escravos), bem como a lógica de distribuição dos dados pelos nós do cluster. O nó mestre fica responsável por decompor o problema em tarefas, distribuir o código a processar para todos os nós escravos, e enviar, para cada nó escravo, os dados a serem processados. Ao término dos trabalhos, os escravos enviam os resultados de seus processamentos ao mestre para que este possa gerar um resultado consolidado. Já Haddop trabalha com o conceito de Localização de dados (data locality). Os dados são organizados em um conjunto de pares <chave,valor>, e são distribuídos pelos nós por meio do mecanismo denominado MapReduce. Desta forma, o acesso a grandes quantidades de dados torna-se mais rápido. Por ser um framework, diminui, e muito, o esforço de programação, cujas tarefas repetitivas de controle e distribuição dos dados pelos nós e de tolerância a falhas, ficam a cargo das classes componentesdo framework, restando, ao programador, cuidar da lógica do negócio. O projeto Hadoop inclui os seguintes módulos (Hadoop, 2016): - Hadoop Common Utilitários comuns que suportam outros módulos do Hadoop. É um conjunto de componentes e interfaces para sistemas de arquivos distribuídos e E/S geral (serialização, Java RPC, estruturas de dados persistentes). - Hadoop Distributed File System (HDFS™) Sistema de arquivos distribuído que provê acesso de alto desempenho aos dados da aplicação. - Hadoop YARN Framework para agendamento dos trabalhos (job scheduling) e gerenciamento dos recursos do cluster. - Hadoop MapReduce Sistema baseado no YARN, para processamento paralelo de grandes massas de dados (large data sets). Existem outros projetos relacionados ao Hadoop. Abaixo, listam-se alguns desses projetos: - Ambari™ Uma ferramenta gráfica para provisionamento, monitoramento e gerenciamento de clusters Hadoop. - HBase™ Banco de dados distribuído, orientado a colunas (não relacional), que comporta tabelas enormes de dados, contendo bilhões de linhas e milhões de colunas. Roda sobre HDFS. - Hive™ datawarehouse distribuído. Gerencia dados armazenados em HDFS e provê uma linguagem de consulta de dados baseada em SQL, a qual é traduzida em tempo de execução para as tarefas (jobs) MapReduce. - Mahout™ Biblioteca escalável para aprendizado de máquina. - Pig™ Linguagem de fluxo de dados e ambiente de execução para exploração de bases de dados muito grandes. Pig roda em clusters com HDFS e Mapreduce. - ZooKeeper™ Coordenador de serviços centralizado de alta disponibilidade. Versões de Hadoop A série "1.x", continuação da série "0.20", processa os dados via "MapReduce". Já a versão "0.23", renomeada como "2.x", utiliza o "MapReduce 2", um novo mecanismo de processamento distribuído de dados, construído sobre o sistema YARN, que realiza o gerenciamento geral dos recursos utilizados na execução de aplicações distribuídas. As propriedades de configuração tiveram seus nomes alterados da versão 1.x para a versão 2.x, conferindo maior regularidade na nomeação. Por exemplo: ao nome da propriedade de configuração do namenode: dfs.name.dir foi alterado para dfs.namenode.name.dir, e o nome da propriedade do MapReduce mapred.job.name teve seu nome alterado para mapreduce.job.name. Sistemas construídos na versão 1.0.1 são compatíveis com servidores das versões 1.0.2 ou 1.1.0, mas não funcionam com um servidor da versão 2.0.0. Sistema de Arquivos Distribuído O esquema de alocação de arquivos em disco de um Sistema Operacional é denominado Sistema de Arquivos. Existem vários sistemas de arquivo, como, por exemplo, o NTFS (Windows) e o EXT4 (Linux), para citar alguns. O sistema de arquivos utilizado pelo Hadoop é o HDFS, um acrônimo para Hadoop Distributed FileSystem (Sistema de Arquivos Distribuído do Hadoop), projetado para armazenar arquivos muito grandes, com capacidade de recuperação muito veloz e grande escalabilidade (capacidade que um sistema distribuído tem de ser expandido em função de novas demandas de armazenamento). Em virtude de o HDFS ser distribuído, os arquivos nele armazenados podem ser acessados a partir de qualquer um dos nós do cluster. MAPREDUCE MapReduce é um framework que permite escrever aplicações que processam grandes quantidades de dados (vários Terabytes) em paralelo, de forma confiável e tolerantes a falhas, em grandes clusters formados por máquinas simples (commodity machines). O termo "commodity machines" pode ser entendido como "computadores que não foram especificamente projetados para serem parte de um cluster, mas que são adaptados para tal". Não se deve, porém, confundi-los com computadores de baixa qualidade, mas sim, hardware comum, de preço acessível. (WHITE, 2015). São computadores simples, mas com arquitetura de servidor, não de desktop ou de notebook. Um job MapReduce geralmente divide um conjunto de dados de entrada em partes independentes que são processados por mapas de tarefas (map tasks) de uma forma completamente paralela. O framework classifica as saídas dos mapas (maps), que são, em seguida, fornecidos como entrada para as tarefas de redução (reduce tasks). Tipicamente, tanto a entrada como a saída do job são armazenados num sistema de arquivos. O framework se encarrega de agendar tarefas, monitorando e reexecutando as tarefas que falharam. MapReduce 1 Nesta versão, o MapReduce consiste de um nó mestre (master) denominado NameNode, de outro nó mestre denominado JobTracker (rastreador de job), e os demais nós, os escravos (slaves) do cluster, agindo como DataNodes (nós de dados) e TaskTrackers (rastreadores de tarefa). O NameNode gerencia o namespace (espaço de nome) do sistema de arquivos e os metadados de todos os arquivos e diretórios. Esta informação é armazenada de forma persistente no disco local na forma de dois arquivos: o primeiro, a imagem do namespace (fsimage), e o segundo, um edit log (edits). O NameNode também conhece os DataNodes nos quais todos os blocos para um dado arquivo estão localizados. Porém, o NameNode não armazena esta informação de forma persistente, porque esta informação é reconstruída a partir dos DataNodes quando o sistema é iniciado. Os Datanodes são os "trabalhadores braçais" do cluster. Eles armazenam e recuperam blocos quando solicitados pelo NameNode, e, periodicamente, reportam ao NameNode os blocos que armazenam naquele momento. Sem o NameNode, o sistema de arquivos não pode ser usado, pois todos os arquivos no sistema de arquivos serão perdidos, uma vez que não se conseguirá reconstruí-los a partir dos blocos dos DataNodes. Para tornar o NameNode resiliente a falhas, pode-se salvar as informações do NameNode em múltiplos sistemas de arquivos (por exemplo, via NFS). Também é possível executar um SecondaryNameNode (NameNode Secundário), que, apesar do nome, não age como um segundo NameNode. O SecondaryNameNode tão somente realiza, de forma periódica, verificações (checkpoints). O processo de verificação (checkpoint) executa as seguintes tarefas: a. O SecondaryNameNode (SNN) solicita ao NameNode (NN) primário que envie os arquivos "edits" (edição de logs) e "fsimage". Novas operações serão inseridas em um novo arquivo "edits"; b. O SNN recupera os arquivos "fsimage" e "edits" do NN; c. O SNN carrega o "fsimage" na memória, aplica cada operação contida no "edits", e, em seguida, cria um novo arquivo "fsimage", consolidado; d. O SNN envia o novo "fsimage" de volta ao NN; e. O NN substitui o antigo "fsimage" pelo novo arquivo, e o antigo "edits" pelo novo arquivo "edits", ambos enviados pelo SNN (item d). O NN também atualiza o arquivo "fstime" para conter em que momento o checkpoint foi realizado. Observa-se que os requisitos de memória do SNN são idênticos aos do NN, uma vez que o SNN tem de carregar o "fsimage" na memória. Em grandes clusters, o SNN exige uma máquina dedicada. MapReduce 2 (YARN) MapReduce 2 (MRv2) é também chamado YARN, cujo significado é: Yet Another Resource Negotiator, valendo, também, o acrônimo: YARN Application Resource Negotiator. Em MapReduce 1, a gerência do agendamento das tarefas (job scheduling) nos TaskTracker e o monitoramento do progresso das tarefas (por exemplo, mantendo atualizado um contador de maps de saída) é realizada pelo JobTracker. YARN (MRv2) remedia as deficiências de escalabilidade do MapReduce clássico, pela divisão das responsabilidades do JobTracker em dois daemons (programas independentes, que rodam em background): - ResourceManager: gerencia o uso dos recursos pelo cluster; - ApplicationMaster: gerencia o ciclo de vida das aplicações sendo executadas no cluster. A ideia é que uma ApplicationMaster negociecom o ResourceManager a quantidade de recursos do cluster (descrito em termos contêineres, cada qual com sua limitação de memória) e, depois, execute processos específicos da aplicação nesses contêineres. Os contêineres são supervisionados por NodeManagers (gerenciadores de nós) em execução nos nós do cluster, o que garante que a aplicação não utilizará mais recursos do que os que foram alocados. Em YARN, cada instância de uma aplicação (MapReduce job) possui - durante o ciclo de vida da aplicação - uma ApplicationMaster dedicada, que recebe notícias sobre o progresso e o status das tarefas, e informa sobre o andamento dos trabalhos ao cliente que submeteu o job. Falhas -Falha em tarefas (tasks): Exceções em tempo de execução (runtime exceptions) e saídas repentinas da JVM são reportadas à ApplicationMaster, que "marca" a tarefa (task) como falha. Da mesma forma, a ausência de ping após um intervalo de tempo definido na propriedade mapreduce.task.timeout, também faz com que a tarefa seja marcada como falha. A figura 1 exibe trecho do arquivo mapred-default.xml e a propriedade mapreduce.task.timeout. Entre as tags <value> e </value> observa-se o valor 300000, referente ao total de milissegundos (ms) antes que uma tarefa (task) seja terminada, caso a tarefa não haja leitura de dados, escrita de um processamento ou atualização do status da tarefa. Um valor igual a 300.000 ms equivale ao tempo de 5 min, pois: 1000 ms = 1 s e 60 s = 1 min 300.000 ms = 300.000 ms x x = 5 min 1000 ms 1 s 60 s 1 min s Figura 1: Configuração do tempo de timeout A tarefa é marcada como falha após algumas tentativas (attempt) de execução, valor que pode ser configurado em mapreduce.map.maxattempts, para tarefas "map", e em mapreduce.reduce.maxattempts, para tarefas "reduce". Algumas aplicações podem ter seus resultados utilizados, mesmo que uma determinada porcentagem de tarefas esteja marcada como falha. Configura-se as porcentagens pelas propriedades: mapreduce.map.failures.maxpercent mapreduce.reduce.failures.maxpercent - Falha na Application Master: YARN tenta executar uma aplicação várias vezes no caso de falha. Por padrão, uma aplicação é marcada como "falha" se ela falha uma vez, número que pode ser configurado no arquivo yarn- default.xml na propriedade: https://www.google.com.br/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjYgcDm0MHNAhUEUZAKHe5dDoQQFggoMAA&url=https%3A%2F%2Fhadoop.apache.org%2Fdocs%2Fr2.4.1%2Fhadoop-yarn%2Fhadoop-yarn-common%2Fyarn-default.xml&usg=AFQjCNGTQGGdn7oZs6oVvlqZw9yj0e9IIw&bvm=bv.125596728,d.Y2I https://www.google.com.br/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjYgcDm0MHNAhUEUZAKHe5dDoQQFggoMAA&url=https%3A%2F%2Fhadoop.apache.org%2Fdocs%2Fr2.4.1%2Fhadoop-yarn%2Fhadoop-yarn-common%2Fyarn-default.xml&usg=AFQjCNGTQGGdn7oZs6oVvlqZw9yj0e9IIw&bvm=bv.125596728,d.Y2I yarn.resourcemanager.am.max-retries Uma ApplicationMaster envia pulsos (heartbeats) periódicos ao ResourceManager, que detecta se houve falha. Em havendo, inicia uma nova instância da aplicação em um novo contêiner (gerenciado por um NodeManager). Os estados das tarefas no momento da falha podem ser recuperados, de forma que as mesmas não precisem ser executadas novamente. Para tal, deve-se alterar a propriedade yarn.app.mapreduce.am.job.recovery.enable para true. Um novo endereço da ApplicationMaster em caso de falha terá de ser informado pelo ResourceManager aos clientes que possuem tarefas gerenciadas pela aplicação, o que causa um aumento no tempo de processamento. - Falha no NodeManager: Se um NodeManager falha, ele para de enviar pulsos (heartbeats) ao ResourceManager, o que acarreta na remoção do nó do pool de nós disponíveis do ResourceManager. O tempo que o ResourceManager espera antes de considerar que o NodeManager falhou, por não estar enviando mais pulsos, é configurado pela propriedade: yarn.resourcemanager.nm.liveness-monitor.expiry-interval-ms e seu valor padrão é igual a 600000 ms (10 minutos). Qualquer tarefa ou aplicação em execução em um NodeManager falho será recuperado. NodeManagers podem ser colocados em uma "lista negra" se o número de falhas para uma aplicação for alto. A lista negra é construída pela ApplicationMaster, que tentará reagendar as tarefas em diferentes nós se mais do que três tarefas falharem em um NodeManager. Esse valor pode ser configurado na propriedade: mapreduce.job.maxtaskfailures.per.tracker - Falha no Resource manager: É uma falha séria, pois sem o ResourceManager não se consegue acessar, nem os jobs, nem os contêineres das tarefas. Após a falha, o administrador do cluster deve "levantar" uma nova instância do ResourceManager, com a recuperação do estado salvo. O estado consiste dos NodeManagers bem como das aplicações em execução. Configura- se o armazenamento utilizado pelo ResourceManager pela propriedade: yarn.resourcemanager.store.class O padrão é: org.apache.hadoop.yarn.server.resourcemanager.recovery.MemStore que mantém o armazenamento em memória. Map, Reduce e Shuffle Para exemplificar como analisar uma base de dados com MapReduce, serão utilizados os dados de levantamento do clima do National Climatic Data Center (NCDC), disponível em http://www.ncdc.noaa.gov/, como proposto em WHITE (2015). Os dados (figura 2) são armazenados em linhas no formato ASCII, com cada linha sendo um registro, contendo informações, dentre outras: identificação da estação meteorológica, data e hora da observação, temperatura do ar (em ºC x 10), pressão atmosférica, etc. Figura 2: Registros de observações do NCDC A base é composta de vários arquivos pequenos, contendo os dados de cada uma das dezenas de milhares de estações meteorológicas para cada dia do ano. Por exemplo, o diretório relativo a 1901 contém 6 arquivos comprimidos (.gz), cada um deles com 1095 linhas; já em 2015, são 14.418 arquivos (.gz), alguns dos quais com mais de 18.000 linhas de dados. Como Hadoop trabalha bem com grandes arquivos, os conteúdos de vários arquivos pequenos de um dado ano, devem ser consolidados em um só arquivo por ano de coleta. Para obter os arquivos, pode-se utilizar um aplicativo FTP cliente, tal como FileZilla (figura 3): Figura 3: Cliente de FTP, FileZilla Na metade esquerda da ferramenta, aparecem detalhes do endereço local. A metade direita (endereço remoto) ainda não possui informação alguma, pois falta realizar a conexão. Para acessar o endereço de FTP onde estão disponíveis os arquivos do exemplo, deve-se configurar esse endereço na ferramenta. Para tal, clique em Arquivo -> Gerenciador de Sites... (figura 4): Figura 4: Iniciando a configuração do endereço FTP desejado Na janela que abre, relativa ao Gerenciador de Sites, dê um clique no botão Novo Site, e o renomeie como NCDC. Em seguida, preencha os campos como mostrado na figura 5 e clique em Ok: Figura 5: Cadastrando o endereço ftp.ncdc.noaa.gov no FileZilla Agora, na janela inicial do FileZilla, clique na tecla de atalho do Gerenciador de Sites (no alto, à esquerda). Figura 6: Realizando a conexão com o endereço remoto Uma vez conectado, os dados disponibilizados no endereço remoto aparecem na metade direita do aplicativo: Figura 7: Exibição dos dados do computador remoto Finalmente, navegue até o endereço remoto onde estão situados os arquivos de dados (/pub/data/noaa), selecione os arquivos desejados, dê um clique com o botão direito do mouse e clique em Baixar, para fazer o download dos arquivos desejados para o computador local. Figura 8: Fazendo o download dos arquivos MapReduce atua dividindo o processo em duas fases: a fase map e a fase reduce. Cada fase possui pareschave-valor (key-value) como entrada e saída, como tipo de dado tanto da chave como do valor f icando a cargo do programador. Deve-se especificar, também, duas funções: função map e função reduce. A entrada para a fase map será a linha dos dados da NCDC (base do clima): - A chave (key) será a posição (offset) da linha do dado. - O valor (value) será a própria linha, no formato texto. A função map é simples, tendo, por objetivo, extrair os dados referentes a ano e temperatura de cada linha de dados. A função map é uma fase de preparação de dados, de tal forma que a função reduce possa fazer o seu trabalho. No exemplo dado: encontrar a máxima temperatura para cada ano fornecido. A função map é também um bom lugar para se eliminar registros ruins, por exemplo, filtrando os registros cujos dados de temperatura sejam faltantes, suspeitos ou errôneos. Para visualizar a forma como a fase map trabalha, considere as seguintes linhas de dados de entrada (algumas colunas não utilizadas foram representadas por pontos): 0067011990999991950051507004...9999999N9+00001+999999999 99... 0043011990999991950051512004...9999999N9+00221+999999999 99... 0043011990999991950051518004...9999999N9- 00111+99999999999... 0043012650999991949032412004...0500001N9+01111+999999999 99... 0043012650999991949032418004...0500001N9+00781+999999999 99... Estas linhas são, então, fornecidas à função map como pares chave-valor: (0 , 0067011990999991950051507004...9999999N9+00001+999999999 99...) (106 , 0043011990999991950051512004...9999999N9+00221+999999999 99...) (212 , 0043011990999991950051518004...9999999N9- 00111+99999999999...) (318 , 0043012650999991949032412004...0500001N9+01111+999999999 99...) (424 , 0043012650999991949032418004...0500001N9+00781+999999999 99...) As chaves representam as posições das linhas dentro do arquivo (offsets). Essas chaves serão ignoradas na função map, que tão somente extrairá o ano e a temperatura do ar (mostradas em destaque): (0, 0067011990999991950051507004...9999999N9+00001+99999999999...) (106, 0043011990999991950051512004...9999999N9+00221+99999999999...) (212, 0043011990999991950051518004...9999999N9- 00111+99999999999...) (318, 0043012650999991949032412004...0500001N9+01111+99999999999...) (424, 0043012650999991949032418004...0500001N9+00781+99999999999...) A saída gerada pela função map é mostrada abaixo (os valores de temperatura são convertidos para o tipo inteiro): (1950 , 0) (1950 , 22) (1950 , −11) (1949 , 111) (1949 , 78) A saída da função map é processada pelo framework MapReduce antes de ser enviada à função reduce. Este processamento utiliza a chave para ordenar e agrupar os pares chave-valor. No exemplo dado, a entrada da função reduce seria: (1949 , [111 , 78] ) (1950, [0 , 22 , −11] ) Cada par contém um ano e uma lista de todas as temperaturas registradas para aquele ano. Tudo que a função reduce tem que fazer, então, é iterar sobre cada uma das listas e encontrar a maior temperatura lida para cada ano. Uma vez terminada a iteração, tem-se a saída final: a máxima temperatura global (registrada por todas as estações) para cada ano, como mostrado abaixo: (1949 , 111) (1950 , 22) MapReduce garante que a entrada para cada reduce seja ordenada pela chave. O processo pelo qual o sistema realiza a ordenação e transfere as saídas do map para o reduce é conhecido por shuffle. É o "coração" do MapReduce. Ambiente Virtual É uma boa prática, durante o desenvolvimento de aplicações Hadoop, executar o código inicial em um ambiente local de teste, e somente depois executá-lo no cluster. O ambiente de teste será composto da plataforma de dados Hortonworks Sandbox, que contém o Linux com o Hadoop instalado (a última versão é a HDP_2.4_Vmware_v3.ova), e o ambiente de virtualização VMware. Você pode utilizar ambos no seu computador pessoal para estudo. Antes de iniciar a instalação do VMware, talvez seja necessário configurar a BIOS do computador para habilitar a virtualização. Figura 9: Habilitando a virtualização na BIOS Caso a BIOS não seja configurada como comentada anteriormente, na instalação da máquina virtual surgirá uma janela de erro informando que a máquina real está com a virtualização desabilitada (figura 10). Figura 10: Mensagem de erro de virtualização desabilitada Se o seu computador não possuir suporte à virtualização, a mensagem de erro será outra, indicando que não há suporte a esse recurso. Uma vez obtido o VMware (Em junho de 2016 estava disponível em: http://br.hortonworks.com/downloads para download), ao executar o aplicativo surge a janela inicial de instalação (que pode variar em função da versão obtida): Figura 11: Janela inicial de instalação do VMware Clique em Finish para continuar a instalação do VMware. Figura 12: Término da primeira parte da instalação do VMware Execute o VMware Player: Figura 13: Execução do VMware Player Digite um endereço de e-mail válido, e depois em Continue: Figura 14: janela de informações da instalação do VMware Player Clique em Finish para finalizar a instalação Figura 15: Finalizando a instalação do VMware Clique, agora, em Open a Virtual Machine. Figura 16: Execução da máquina virtual Selecione o Sandbox (arquivo .ova) e clique em Abrir. Figura 17: Carregando a máquina virtual Clique em Import. Figura 18: Importação da máquina virtual para o ambiente do VMware Clique no nome da máquina virtual e, após, em Play virtual machine Figura 19: Executando a máquina virtual Caso surja este aviso, clique em OK. Figura 20: Janela de advertência do VMware A máquina virtual começa a ser executada. Figura 21: Início de execução da máquina virtual A janela abaixo exibe o carregamento de vários serviços do Linux e do Hadoop. Figura 22: Execução dos serviços de iniciação do Linux e do Hadoop Pronto! A máquina virtual está carregada. Anote o IP fornecido. O valor "192.168.187.128" poderá variar entre uma instalação e outra. Figura 23: Tela de carregamento exibindo o IP da máquina virtual Abra um navegador. Para ter acesso ao formulário de registro de primeiro acesso, utilize o endereço (IP) informado na figura 23: http://192.168.187.128/registration_form Figura 24: Janela de registro de primeiro acesso do Sandbox. Complete com seus dados e submeta o formulário. Surge, então, a janela inicial: Figura 25: Janela inicial de trabalhos do Sandbox O ambiente gráfico de execução de trabalhos no Hortonworks Sandbox, como mostrado na janela inicial, é executado na porta 8000: http://192.168.187.128:8000 (como informado na figura 25). Figura 26: Ambiente gráfico do Sandbox Na figura 25, além do IP:PORTA, são informados o Username: hue e o Password: 1111, caso seja necessário realizar o login (no modo gráfico). Este ambiente dá acesso ao Hive, ao PIG e ao ambiente do HDFS: Figura 27: Acessando o Hive do menu do Sandbox Utilizando um Cliente SSH Para manipular o servidor remoto, será utilizado, neste trabalho, um aplicativo cliente SSH, tal como o Bitvise SSH Client (https://www.bitvise.com/). Após a instalação, complete os campos abaixo e clique em Login: Host: 192.168.187.128 Login: hue Port: 22 Password: Hadoop Figura 28: Janela inicial do Bitvise SSH Client As informações para login via SSH (Username: hue e Password: hadoop) são mostradas na janela inicial (figura 25).A única alteração é que utilizaremos a porta 22 (padrão do SSH) ao invés da porta sugerida: 2222. Clique em Accept and Save na janela que aparece (figura 29). Figura 29: Janela de primeira conexão SSH Ao ser carregado, o Bitvise disponibiliza uma interface gráfica para transferência de arquivos entre as máquinas real e virtual. Figura 30: Gerenciador de arquivos do Bitvise E um terminal para execução de comandos do Linux e do shell HDFS. Figura 31: Terminal para execução de comandos E por que utilizar um ambiente em modo texto? Porque no modo texto pode-se realizar tarefas não previstas no modo gráfico, o que fornece flexibilidade ao profissional de TI. Assim sendo, é importante saber que o modo gráfico proporciona facilidades para aquelas tarefas que foram previstas, mas que o modo texto proporciona facilidades para tarefas personalizadas. A informação [hue@sandbox ~] é chamado prompt de comando ou, simplesmente, prompt. Figura 32: Prompt de comandos de um terminal Linux Os comandos Linux devem ser digitados após o prompt. Após cada digitação de comando, pressione ENTER para executá-lo. Para finalizar os trabalhos com a máquina virtual, deve-se executar alguns comandos Linux (lembre-se que o Linux é case-sensitive, ou seja, diferencia maiúsculas de minúsculas): a) Efetue login como root (comando su). Quando aparecer a palavra Password:, digite hadoop (nada será exibido na tela) e pressione a tecla ENTER. b) No prompt, digite shutdown –h now e pressione a tecla ENTER. Figura 33: Encerrando os trabalhos com a máquina virtual Após executar o comando shutdown, o sistema entra em atividade de encerramento, fechando os processos abertos. A máquina virtual recebe a solicitação e inicia o processo de desligamento. Pode-se acompanhar o encerramento do sistema pela janela do Sandbox: Figura 34: Processo de encerramento do sistema após o shutdown CONCEITOS DO SISTEMA OPERACIONAL LINUX O Linux, desenvolvido em 1991 por Linus Torvalds é um Sistema Operacional (SO) multitarefa e multiusuário (CAMPOS, 2003). Utiliza os conceitos de software livre, por isso, pode ser copiado e utilizado para qualquer fim, comercial ou não. Pode ser utilizado em modo texto (console) ou em modo gráfico, por meio do sistema de janelas conhecido por X Window (NEMETH et al., 2007). Por ser multiusuário, cada usuário tem uma área de disco privada para armazenamento de seus arquivos e um número de identificação denominado UID (User IDentification). Os usuários possuem limitações sobre o que podem fazer no sistema (execução, leitura e escrita de arquivos e diretórios), com exceção do usuário chamado root, um superusuário que tem permissão para fazer tudo, tanto em sua área privada, como na área privada de qualquer usuário. De forma a facilitar a concessão de permissões idênticas a vários usuários, estes são classificados por grupo (GID: Group IDentification). Assim, um usuário possui, além das suas permissões de usuário, as permissões atribuídas ao grupo do qual ele faz parte. No Linux, os arquivos são armazenados em um sistema de diretórios. Quem define a organização de diretórios e arquivos no disco, a quantidade de bytes em cada setor (geralmente, 4KB), o tamanho máximo (em bytes) de cada arquivo, dentre outras características, é o Sistema de Arquivos. São sistemas de arquivo o EXT4, o VFAT e o BTRFS, mas existem outros. Na instalação do Linux são criadas, obrigatoriamente, duas partições: / : chamado de raiz, é uma partição obrigatória, na qual o sistema é instalado. swap : área temporária do Linux (equivale ao C:\temp no Windows). A estrutura de diretórios do Linux organiza os diretórios e arquivos em árvore, sendo que o todos os diretórios são criados sob o diretório raiz ( / ). O Linux, ao contrário do Windows, não especifica letras para unidades de disco (C:, D: etc.). Quando uma unidade de disco deve ser lida no Linux, é criado um “ponto de montagem” dessa unidade em um diretório, o qual passa a representar a unidade de disco respectiva. Assim, a leitura do diretório equivale a ler o conteúdo da unidade de disco mapeada para aquele diretório. No Linux a extensão de um arquivo não define sua característica. Por exemplo, um arquivo executável tanto pode ter o nome: arq.exe, como arq.txt, ou somente arq. Dessa forma, para ser executável, um arquivo deve ter permissão de execução. Na instalação do Linux, são criados alguns diretórios específicos. Citam-se alguns a seguir: /boot Contém o kernel do Linux (parte principal do SO) e demais arquivos necessários à iniciação (boot) do sistema. /bin Contém aplicativos e utilitários em geral, como os comandos de leitura de conteúdo de arquivos (cat), criação de diretório (mkdir), cópia de arquivos (cp), compactação (tar, gzip), dentre outros. /dev Contém arquivos que fazem referências a dispositivos de hardware. /etc Contém arquivos e diretórios de configuração de aplicativos. /home Contém os diretórios dos usuários “não root”. Se existir a conta de usuário “jose_luiz”, então, há o diretório “/home/jose_luiz”. /root Contém arquivos e diretórios do usuário “root”. /usr É um diretório muito grande, e contém diversos arquivos executáveis, documentações etc. /var Contém informações de sistema, como logs, filas de impressão etc. Há vários outros diretórios, mas uma listagem completa foge ao escopo deste trabalho. Esquematicamente, representa-se a hierarquia de diretórios em árvore. Na figura 35, vê-se a representação para os diretórios anteriormente descritos: Figura 35: Representação de diretórios do Linux em árvore O sistema UNIX é orientado a arquivos. Tudo em um sistema UNIX (e no Linux, por consequência) é um arquivo. Para o Linux, um diretório, por exemplo, é um arquivo que contém os nomes de outros arquivos. Seus comandos são arquivos executáveis. Em Linux, um nome de arquivo pode conter até 255 caracteres, sendo que a extensão é informática para o usuário, e figurativa para o Linux. Por exemplo, o arquivo “conteudo.exe” pode ser um arquivo de texto. O que define se se trata de um arquivo executável são as permissões do arquivo. O Linux é sensível a maiúsculas e minúsculas (case-sensitive). Dessa forma, o nome “conteudo.exe” é diferente dos nomes “Conteudo.exe” e “conteudo.Exe”. Um arquivo sempre possui, além do nome, informações como: - Permissões / bin boot dev etc home root usr var - Quantidade de links (atalhos) - Proprietário do arquivo (usuário que o criou) - Grupo do arquivo (grupo do usuário criador) - Tamanho (bytes) - Data da criação - Hora da criação Isto pode ser visto com a execução do comando “ls -l”: Figura 36: Visualização das informações dos arquivos no Linux Comandos do Linux Um comando é um arquivo que executa uma determinada tarefa. Um comando pode, ou não, conter opções (geralmente um nome precedido de dois traços ou uma letra precedida de um traço) e/ou parâmetros. A seguir, são listados alguns comandos do Shell (programa que interpreta comandos do usuário). Lembre-se que o Linux é case-sensitive (diferencia maiúsculas de minúsculas): Comando: clear Limpa a tela do terminal. Comando: su Muda para o usuário especificado. Se nenhum usuário for especificado, assume o usuário root. Exemplos: su hue Abre a sessão com o usuário hue. su Abre a sessão com o usuário root. É o mesmo que: su root. O prompt altera o caractere de $ para #. Comando: exit Sai do console atual. Comando: passwd Altera a senha do usuário ativo (o usuário root pode alterar a senha de qualquer usuário). Comando: mkdir Cria um diretório (MaKe DIRectory). Exemplo: mkdir /home/users Cria o diretório users “embaixo” do diretório home (ou seja, users é um subdiretório do diretório home) Comando: useradd Cria um usuário. Exemplo: criar embaixo de /home o subdiretório ze. Em seguida, criar o usuário ze, associando-o ao diretório recém criado: /home/ze. Por final, alterar a senha do novo usuário para que ele possa efetuar login no sistema Passo 1: Abrir uma sessão como root su Passo 2: Criar o diretório ze mkdir /home/ze Passo 3: Criar o usuário (useradd –d <home> <nomeUsu>) useradd -d /home/ze ze Passo 4: Alterar a senha do usuário passwd ze Passo 5: Testar o usuário criado su ze Passo 6: Sair da sessão do usuário ze exit Passo 7: Limpar o terminal clear Comando: cd Mudar de diretório (Change Directory) Exemplo: cd /home/ze Vai para o diretório “home” do usuário “ze”. cd Retorna ao diretório home do usuário. cd ~ Também retorna ao diretório home do usuário. cd - Retorna ao último diretório acessado. Comando: pwd Exibe o diretório atual (Print Working Directory) Comando: file Informa o tipo de arquivo especificado. Exemplo: Seja o arquivo de texto (ASCII) arq_texto. Assim, executar: file arq_texto faz com o sistema exiba o seguinte: arq_texto: ASCII text Comando cat Exibe o conteúdo de um arquivo. cat arq_texto Comando: ls Lista o conteúdo de um diretório. Exemplo: ls Lista os arquivos do diretório atual. ls /etc Lista os arquivos do diretório /etc. ls –l /etc Lista (com detalhes) os arquivos do diretório /etc. ls –a /etc Lista os arquivos ocultos (cujos nomes iniciam com o caractere ponto “.”) do diretório /etc. ls –R /etc Lista os arquivos do diretório /etc e de todos os subdiretórios dele. ls . Lista os arquivos do diretório corrente (representado pelo ponto “.”). Supondo que o diretório /etc seja o diretório corrente, executar: ls . lista os arquivos de /etc, e executar: ls .. lista os arquivos do diretório hierarquicamente superior (representado pelos dois pontos consecutivos “..”). Supondo que o diretório /etc seja o diretório corrente, executar: ls .. lista os arquivos do diretório raiz ( / ), do qual /etc é um subdiretório. ls /etc/* O asterisco é um curinga que substitui qualquer ocorrência de caractere. O comando ls /etc/* equivale a ls /etc. Porém, se se deseja conhecer os arquivos .conf daquele diretório, deve-se executar: ls /etc/*.conf Dessa forma, serão listados todos os arquivos que, não importando o nome (*) terminem em “.conf”. Comando: cp Copia um arquivo (ou um conjunto de arquivos) de um diretório (origem) para outro (destino). Exemplo: copiar o arquivo fstab do diretório /etc para o diretório home do usuário atual (hue): Passo 1: Retornar ao diretório home do usuário cd Passo 2: Obter o diretório atual pwd Passo 2: Copiar o arquivo de /etc para esse diretório cp /etc/fstab /user/lib/hue Passo 4: Verificar que o arquivo foi copiado ls –l fstab Comentários: O diretório home do usuário neste ambiente é /usr/lib/hue. Porém, ao invés de fazer: cp /etc/fstab /user/lib/hue poderia ter sido executado: cp /etc/fstab ~ uma vez que o til (~) representa o diretório home do usuário ativo. Pode-se utilizar o caractere ponto ( . ), caso o diretório destino seja o diretório corrente: cp /etc/fstab . Caso o diretório de origem seja o corrente: cp ./fstab ~ Neste caso, o ponto ( . ) substitui “/etc” e o til substitui o diretório home do usuário hue (/usr/lib/hue). Caso o diretório de origem e destino sejam o corrente: cp ./fstab . Neste caso, o caractere ponto ( . ) substitui “/etc”. Comando: mv Move um arquivo (ou um conjunto de arquivos) de um diretório (origem) para outro (destino). Também é utilizado para renomear um arquivo (ou diretório). Comando: rmdir Remove (exclui) um diretório (que deve estar vazio). Comando: rm Apaga um arquivo. Exemplo: rm arq_texto Apaga o arquivo arq_texto do diretório atual. rm -i arq_texto Apaga o arquivo arq_texto do diretório atual somente se for confirmada ( y ) a remoção. rm –f arq_texto Apaga o arquivo arq_texto do diretório atual sem solicitar confirmação. rm –r ./teste Apaga os arquivos do diretório teste (subdiretório do diretório atual; observe o caractere ponto antes da barra) e de todos os seus subdiretórios. ls –rf ./teste Apaga os arquivos do diretório teste (subdiretório do diretório atual; observe o caractere ponto antes da barra) e de todos os seus subdiretórios sem solicitar confirmação. Tenha muito cuidado ao utilizar a opção “r” junto com a opção “f”. Ainda mais se você efetuou login no sistema como root. Comando: grep Pesquisa texto em arquivo. A opção “i” faz com a diferença entre maiúscula e minúscula seja ignorada: grep –i texto_a_pesquisar nome_do_arquivo Por exemplo, para saber se há a ocorrência do texto “devpts” em todos arquivos (*) do diretório “/etc”, executa-se: grep –i devpts /etc/* A opção “i” exibe, além do nome do arquivo, o conteúdo da linha onde o texto ocorre. Para exibir somente o nome do arquivo, utiliza-se a opção “l” (L minúsculo): grep -il devpts /etc/* Comando: sudo Permite a um usuário executar comandos como root (deve-se conhecer a senha deste). Exemplo: Supondo que você efetuou login como usuário não root (no caso deste trabalho, como “hue”), a execução do comando: grep –i devpts /etc/* produziu várias mensagens de “Acesso não permitido” (Permission denied), pois há arquivos que “hue” não possui permissão de leitura. Para que “hue” possa pesquisar os conteúdos de todos os arquivos, deve-se solicitar que o superusuário (su) faça (do) o trabalho: sudo grep –i devpts /etc/* Comando: ps Lista todos os processos em execução. Com opção “e” tem-se os identificadores de cada processo. Exemplo: ps –e Comando: | O comando pipe (representado pelo caractere que, em geral, fica na mesma tecla do caractere barra invertida “\”) permite a comunicação interprocessos, enviando o resultado de um processo para utilização do processo seguinte (após o pipe). Por exemplo, desejando-se saber se há processo java em execução, a listagem de “ps –e” é entregue ao comando “grep”, que filtra a ocorrência do texto “java”: ps –e | grep –i java Comando: kill Encerra um processo em execução (cujo PID pode ser obtido pelo comando ps). A opção “-9” encerra o processo instantaneamente. Exemplo: Supondo que um processo tem PID igual a 1962, e deseja-se encerrar esse processo: kill -9 1962 Comando: & Permite que um processo seja executado em segundo plano, liberando o terminal para um novo processo (multitarefa). Exemplo: Supondo que se deseja executar o arquivo binário (hipotético) de nome “teste” em segundo plano: teste & Comando: df Exibe o espaço (total/ocupado/livre) em disco. A opção “h” fornece uma leitura mais fácil de ler, representando o total de bytes em “K”, “M” ou “G”). Exemplo: df -h Comando: shutdown Permite ao superusuário finalizar a execução do SO. Com a opção “h” pode-se terminar após uma quantidade de minutos especificada, por exemplo, 10 minutos: shutdown –h 10 ou, imediatamente: shutdown –h now Comando: ln Cria um link direto (hard link) para arquivos (não é permitido criar links diretos para diretórios). Dessa forma, o arquivo passa a ter mais de um nome, e, se ele for removido, a sua “cópia de segurança” continuará válida. Antes de explicar esse comando, crie um arquivo texto contendo a listagem do diretório home do usuário “hue”; em seguida, liste o diretório no formato longo: ls > arq Crie, agora, um link direto eo associe ao arquivo arqLD: ln arq arqLD Já a opção “s” (para arquivos ou diretórios) faz com que seja criado um link simbólico (atalho). Se o arquivo para o qual o link simbólico aponta for removido, o link simbólico fica inutilizável (link quebrado). Crie, agora, um link direto e o associe ao arquivo arqLD: ln –s arq arqLS Pronto! Agora, execute o comando: ls –li arq*. Na listagem exibida pelo sistema, veem-se os dois arquivos (o original e seu link direto), sendo que a opção “i” exibe o inode (index node é o número de identificação único do arquivo no sistema de arquivos do Linux) como primeira informação. Figura 37: Inode do arquivo arq e de seu link direto arqLD Observe que arq e arqLD possuem o mesmo inode (2372284), demonstrando tratarem-se do mesmo arquivo. Já o inode de arqLS (2372286) demonstra que se trata de outro arquivo, diferente de arq e de arqLD. Por último, exclua arq e liste o diretório novamente: rm arq ls –li arq* Figura 38: Exibição de um link quebrado Observe que o link simbólico está “quebrado”, pois o arquivo original foi removido. Em compensação, o link direto, arqLD, continua válido, e pode ser manipulado normalmente (por exemplo, criando-se novo link direto por segurança). Entretanto, copiar o link direto por meio do comando cp, faz com que seja criado um novo arquivo (inode diferente). Por exemplo, observe os inodes diferentes caso seja adotado este procedimento: cp arqLD arq1 ls –li arq* Figura 39: Inode dos arquivos arq1 e arqLD Permissões de arquivo Todo arquivo (todo diretório também, haja vista que um diretório é considerado um arquivo pelo Linux) possui três níveis de permissão. Para entender melhor o conceito, execute o comando: ls –l /etc/fstab no que o sistema exibe: Figura 40: Exibição das permissões do arquivo fstab Esta linha: - r w - r - - r - - 1 root root 783 2014-12-16 20:24 /etc/fstab Traz as seguintes informações: 1: Se é arquivo (-), diretório (d) ou um link (l). 2: Permissões do usuário dono (owner) sobre o arquivo. 3: Permissões do grupo do usuário proprietário sobre o arquivo. 4: Permissões de outros usuários que não sejam o proprietário, ou que não estejam no grupo, sobre o arquivo. 5: Quantidade de links diretos. 6: Dono (proprietário) do arquivo. 7: Grupo do dono do arquivo. 8: Tamanho (bytes), data e hora de criação/modificação do arquivo. 9: nome (com o caminho) do arquivo. Para cada nível (dono, grupo e outros) existem três tipos permissões: - r w - r - - 1 root root ... /etc/fstab 1 2 3 5 6 7 8 9 r - - 4 r : Leitura (read). Pode visualizar o conteúdo do arquivo. w : Escrita (write). Pode alterar o conteúdo do arquivo. X : Execução (eXecution). Pode executar o arquivo. No exemplo fornecido (figura 40), vê-se que o arquivo fstab, localizado em /etc pode ser lido e alterado pelo root (dono do arquivo), somente lido pelo grupo do dono (o nome do grupo também é root) e por outros usuários. A figura 41 exibe dois arquivos e um link no diretório home do usuário: Figura 41: Permissões Observe que o arquivo arq1 e o link direto arqLD, podem ser lidos e alterados (editados), tanto pelo dono (hue), como pelo grupo (hue). Os demais usuários só podem ler seu conteúdo. Já o link simbólico arqLS pode ser lido, alterado e executado por todos os usuários. As permissões podem ser alteradas tanto para o usuário dono (u = user), como para o grupo (g = group) e para outros usuários (o = others) pelo comando chmod. O sinal de mais (+) adiciona uma permissão e o sinal de menos (-) remove uma dada permissão. Para exemplificar, caso um arquivo chamado “teste” tenha as seguintes características: -rw-rw-r-- 1 hue hue 198 2016-06-30 02:33 teste Executar: chmod u-w+x,g-r+x,o+wx-r teste faz com que uma nova listagem longa produza: -r-x-wx-wx 1 hue hue 195 2016-06-30 03:32 teste Hadoop Distributed Filesystem (HDFS) HDFS é um sistema de arquivos distribuído, ou seja, gerencia o armazenamento de arquivos em máquinas fisicamente separadas (em rede). Por ser baseado em rede, possui muito mais complicações do que sistemas de arquivos de discos regulares, como, por exemplo, a tolerância às falhas dos nós com nenhuma perda de dados. HDFS foi projetado para: - Armazenar arquivos muito grandes (gigabytes, terabytes, ou mesmo, petabytes); - Escrever uma vez e ler muitas vezes: uma análise envolve uma grande parte de uma base de dados, se não toda ela. Assim, otimiza-se o processo lendo toda a base de dados ao invés da leitura registro a registro; - Funcionar em máquinas simples (commodity hardware). Entretanto, HDFS não foi projetado para: - Acesso a dados com baixa latência(*): aplicativos que requerem acesso de baixa latência para os dados não vão funcionar bem com HDFS, que é otimizado para elevadas taxas de transferência (throughput), conseguido à custa de latência. HBase é, atualmente, a melhor escolha para o acesso de baixa latência; Obs.: Tempo de latência é a soma dos tempos de: posicionamento no setor que contém os dados (latência rotacional) + posicionamento na trilha que contém os dados (busca). O tempo total de acesso aos dados de um disco, é igual à soma dos tempos de: latência + transferência (do disco para a memória) - Muitos arquivos pequenos: o número de arquivos é limitado pela quantidade de memória do NameNode, pois o mesmo contém metadados do sistema de arquivos na memória. Como regra geral, cada arquivo, diretório e bloco, ocupa cerca de 150 bytes. Para um milhão de arquivos, cada um ocupando um bloco, serão necessários, pelo menos, 300 MB de memória; - Modificação de arquivos: após salvos em HDFS, os arquivos não podem ser modificados, o que favorece uma alta taxa de transferência (throughput). Blocos Um sistema de arquivos para um disco simples lida com dados em bloco, cujo tamanho define a quantidade mínima de dados que pode ser lida ou escrita. Assim sendo, se um sistema de arquivos define que o tamanho do bloco é 1KB (1024 bytes), mesmo que um arquivo contenha 10 bytes de tamanho, ele ocupará 1024 bytes em disco ao ser salvo. Naturalmente, um arquivo maior ocupará vários blocos para seu armazenamento (por exemplo, um arquivo de 9,5 KB ocupará 10 blocos). O HDFS também divide os dados em blocos que, por padrão, ocupam 64MB. Porém, ao contrário dos sistemas de arquivos para discos simples, em HDFS, arquivos menores do que o tamanho do bloco não ocupam todo o espaço. Blocos HDFS são largos se comparados com blocos em discos simples para minimizar o custo com a procura dos dados (latência). NameNodes e DataNodes O NameNode gerencia o espaço de nome (namespace) do sistema de arquivos, por meio de metadata para todos os blocos, arquivos e diretórios na árvore. Os DataNodes são usados como armazenamento comum de blocos por todos os Namenodes do cluster. Reportam-se periodicamente ao NameNode, enviando heartbeats (batimentos cardíacos) periódicos, que servem como "sinais de vida", e listas com os blocos armazenados no momento do envio destes relatórios. HDFS Federado O NameNode mantém uma referência ao namespace (arquivo, diretório e bloco) do sistema de arquivos em memória. Clusters muito grandes possuem um fator de limitação de escala. HDFS Federado, introduzido a partir da versão 2.x (release series), permite a inclusão de NameNodes, cada qual gerenciando uma porção do namespace, ou seja, é um cluster que possui múltiplos namespaces, cada qual sendo gerenciado por um NameNode. Por exemplo, um NameNode pode gerenciar os arquivos sob o diretório "/user", e, um segundo NameNode os arquivos sob "/share". Os NameNodes federados são independentes, e não necessitam de coordenação uns com os outros. A configuraçãoé compatível com versões antigas, e permite a configuração de um NameNode único, existente, sem qualquer alteração. A nova configuração foi concebida de tal forma que todos os nós no cluster tenham a mesma configuração, sem a necessidade da implantação de configuração diferente com base no tipo do nó no cluster. Alta Disponibilidade (HDFS High-Availability) Replicar o metadado do NameNodes em vários sistemas de arquivos, e usar o NameNode Secundário para criar pontos de checagem (checkpoints) protege contra a perda de dados, mas não fornece alta disponibilidade do sistema de arquivos. O NameNode continua sendo um único ponto de falha (SPOF – Single Point Of Failure). Se ele falhar, todos os clientes, incluindo os jobs MapReduce seriam incapazes de ler, escrever ou listar os arquivos, porque o NameNode é o único repositório de metadados e do mapeamento "arquivo-bloco". Em um evento como esse, todo o sistema Hadoop estará - efetivamente - fora de serviço, até que um novo NameNode possa ser colocado online. A versão 2.x do Hadoop remediou esta situação, adicionando suporte para HDFS de alta disponibilidade (HA). Nesta implementação há um par de NameNodes numa configuração "ativo - em espera" (active-standby). Em caso de falha do NameNode ativo, o NameNode em espera (standby) assume suas funções, para continuar atendendo a solicitações do cliente sem interrupção significativa. Se o NameNode ativo falhar, o NameNode em espera pode assumir muito rapidamente (em algumas dezenas de segundos), pois tem o estado mais recente disponível em memória, tanto do log da última edição, como do mapeamento de bloco atualizado. Na prática, o tempo real de substituição (failover) observado é longo (em torno de um minuto ou mais), em função de o sistema ter de decidir que o NameNode ativo falhou. Observação: Failover é quando uma máquina substitui outra, no caso de falha desta última. Entendendo o Sistema de Arquivos Distribuído Seja o cluster composto por um switch (na parte superior da imagem) e quatro máquinas, como mostrado na figura 42. Figura 42: Cluster com um switch e quatro máquinas (nós do cluster) Quando o usuário acessa o cluster e executa o comando para listar arquivos (ls) ele está interagindo com o Linux. Porém, para processar arquivos no ambiente de execução do Hadoop, o usuário necessita acessar arquivos armazenados no HDFS. Para tal, utiliza-se hdfs dfs” (ou "hadoop fs") antes dos comandos a serem executados no HDFS, de tal forma que a execução se dê no Hadoop, e não no Linux. Em virtude de o HDFS ser distribuído, os arquivos nele armazenados podem ser acessados a partir de qualquer um dos nós do cluster. Supondo que cada máquina do cluster da figura 42 possua um disco rígido (HD) de 1,5 TB, particionado de tal forma que 0,5 TB seja formatado para uso do Linux e 1,0 TB seja formatado para uso do Hadoop (HDFS), tem-se um esquema de compartilhamento igual ao mostrado na figura 43. Switc h Nós do cluster Figura 43: Compartilhamento de disco entre nós do cluster Pela figura 43 vê-se que o total de armazenamento compartilhado por todos os nós do cluster é de 4TB. Dessa forma, listar o diretório de qualquer nó, faz com que sejam exibidos os diretórios e arquivos daquele nó somente. Porém, a listagem dos arquivos e diretórios do HDFS exibe o mesmo conteúdo, independentemente do nó em que se execute o comando de listagem, comprovando que se trata de um recurso compartilhado por todos os nós do cluster. Por exemplo, a listagem do diretório “/home” do no02 (segunda máquina do cluster da figura 42, de cima para baixo) produz o seguinte Figura 44: Listagem do diretório /home do nó 02 do cluster Observe que, nesta listagem, não há um diretório chamado “users” entre os diretórios “tez” e “yarn”. Já a listagem do no03 (terceira máquina) produz o seguinte: Figura 45: Listagem do diretório /home do nó 03 do cluster Observe que, na listagem da figura 45, há o diretório “users” entre os diretórios “tez” e “yarn”, cujo detalhe está ampliado na figura 46. Figura 46: Exibição do diretório “users” em no03 Já a execução dos comandos “hdfs dfs –ls /” (ou “hadoop fs –ls /”) e “hdfs dfs –ls /user” (ou “hadoop fs –ls /user”), tanto do nó 02, como do nó 03, produz o mesmo resultado: Figura 47: Listagem de diretórios do HDFS nos nós 02 e 03 Isto comprova, independentemente do nó em que ocorre o acesso, que se trata do mesmo sistema de arquivos, ou seja, o sistema enxerga todos os HDs de todos os nós do cluster que estejam formatados com HDFS, como sendo "um mesmo HD". Comandos do Shell HDFS Entendida a distribuição de arquivos pelo HDFS e o porquê de os dados estarem neste ambiente (os dados têm de ser compartilhados por todos os nós do cluster), o passo seguinte é mostrar comandos do Shell HDFS. A sintaxe é a seguinte: hdfs dfs -comando argumentos Comando: appendToFile Adiciona arquivos do sistema de arquivos local para o sistema de arquivos destino (HDFS). Uso: hdfs dfs -appendToFile <localsrc> <dest> Exemplo: hdfs dfs -appendToFile localfile /hdfsDir/file Comando: cat Exibe o conteúdo do arquivo. Uso: hdfs dfs -cat URI [URI ...] Exemplo: hdfs dfs -cat /hdfsDir/file Comando: copyFromLocal Copia arquivos do sistema de arquivos local para HDFS. Similar ao comando put. Uso: hdfs dfs -copyFromLocal [-f] <localsrc> URI Exemplo: hdfs dfs -copyFromLocal localfile /hdfsDir/file Comando: copyToLocal Copia arquivos do sistema de arquivos HDFS para o sistema de arquivos local. Similar ao comando get. Uso: hdfs dfs -copyToLocal [-f] URI <localsrc> Exemplo: hdfs dfs -copyToLocal /hdfsDir/file localfile Comando: cp Copia arquivo(s) da origem (HDFS) para o destino (HDFS). Uso: hdfs dfs -cp [-f] URI [URI ...] <dest> Exemplo: hdfs dfs -cp /hdfsDir/file1 /hdfsDir/file2 /hdfsDir/dir Comando: du Exibe o tamanho dos arquivos e diretórios. Uso: hdfs dfs -du [-s] [-h] URI [URI ...] Exemplo: hdfs dfs -du -h hdfsDir/file /hdfsDir Comando: expunge Esvazia a lixeira. Uso: hdfs dfs -expunge Comando: get Copia arquivo(s) do sistema de arquivos (HDFS ) para o sistema de arquivos local. Uso: hdfs dfs -get <src> <localdst> Exemplo: hdfs dfs -get /hdfsDir/file localfile Comando: ls Lista os arquivos do diretório. Uso: hdfs dfs -ls [-R] <args> Exemplo: hdfs dfs -ls /hdfsDir/file Comando: mkdir Cria um diretório no sistema de arquivos (HDFS). Uso: hdfs dfs -mkdir <paths> Exemplo: hdfs dfs -mkdir /hdfsDir/dir1 /hdfsDir/dir2 Comando: mv Move arquivos da origem (HDFS) para o destino (HDFS). Não é permitido mover arquivos entre sistemas de arquivos (de HDFS para local, e vice- versa). Uso: hdfs dfs -mv URI [URI ...] <dest> Exemplo: hdfs dfs -mv /hdfsDir/file1 /hdfsDir/file2 Comando: put Copia arquivos do sistema de arquivos local para o sistema de arquivos (HDFS). Uso: hdfs dfs -put <localsrc> <dest> Exemplo: hdfs dfs -put localfile /hdfsDir/file Comando: rm Apaga arquivos no sistema de arquivos (HDFS). Uso: hdfs dfs -rm [-f] [-r|-R] [-skipTrash] URI [URI ...] Exemplo: hdfs dfs -rm /hdfsDir/file JAVA AVANÇADO Java é uma Linguagem de Programação orientada a objetos, projetada para ser portável entre diferentes plataformas de hardware e software, ou seja, um programa criado no ambiente Windows pode ser executado no ambiente Linux ou UNIX. Javalhe permite escrever programas para desktop, ou construir páginas Web, que podem ser acessadas por um navegador. É uma linguagem compilada, o que significa que seu código-fonte deve ser compilado. Ao passo que outras linguagens criam, com a compilação, um código-objeto (código-fonte traduzido para linguagem de máquina) seguido de um código- executável final (como C e C++ por meio da linkedição), Java cria, com a compilação, um código intermediário denominado Bytecode, igualmente em código binário, mas que necessita de uma máquina virtual Java (ou JVM, Java Virtual Machine) para ser executado. Assim, todo sistema que contiver uma JVM instalada, poderá executar o Bytecode da mesma forma. E é isso que confere à Java a flexibilidade de rodar em qualquer plataforma. Eclipse Para criar códigos em Java, pode-se utilizar um editor de textos comum. Porém, para ganhos de desempenho pode-se utilizar um IDE (Integrated Development Environment), ambiente de desenvolvimento integrado que realiza edição de texto, compilação e execução, além de outras tarefas, como depuração do código-fonte e refatoração (refactoring), que é a alteração do código mantendo as mesmas funcionalidades. É uma técnica que visa a procura e a eliminação de bugs (problemas) num sistema de software. Há ótimos IDEs para Java, dentre eles, Eclipse e Netbeans. Neste trabalho será utilizado o Eclipse IDE for Java Developers Neon (nome da versão 4.6), e que pode ser obtido em: https://www.eclipse.org/downloads/eclipse- packages/. Feito o download, descompacte o arquivo .zip em uma pasta de sua preferência e execute o Eclipse (eclipse.exe). Aparece, em seguida a janela de abertura do Eclipse na versão selecionada: Figura 48: Janela de abertura do Eclipse Neon Em seguida, deve-se informar ao Eclipse um local no HD para conter os arquivos dos projetos. Este local é chamado Workspace. Figura 49: Definindo o diretório do Workspace Após clicar o botão OK, surge o ambiente de desenvolvimento. Feche a janela de Boas-vindas (aba Welcome, no canto superior esquerdo). Figura 50: Ambiente de desenvolvimento do Eclipse É mostrada, então, a “bancada de trabalho” (workbench), com as funcionalidades pertinentes à perspectiva Java. Figura 51: Janela da “bancada de trabalho” (workbench) da perspectiva Java Uma perspectiva define funcionalidades úteis para uso dentro daquela perspectiva. Para trabalhar com depuração (debug), por exemplo, deve-se alterar da perspectiva Java para a Debug, clicando em: Window –> Perspective -> Open Perspective -> Other... Figura 52: Utilizando o menu perspectiva Em seguida, deve-se selecionar a perspectiva desejada (Debug): Figura 53: Seleção da perspectiva Debug Clique em OK. Pronto. Observe que a bancada de trabalho (workbench) é alterada de acordo com a perspectiva selecionada: Figura 54: Workbench da perspectiva Debug Retorne à perspectiva Java. Criando um Projeto no Eclipse Para compilação dos códigos-fonte a serem criados no projeto, o Eclipse necessita da JDK. Dessa forma, deve-se obter a Java SE (JDK + JRE) para os trabalhos de compilação (JDK) e execução (JRE). Obs.: A máquina virtual utilizada neste trabalho utiliza a versão 7 de Java (Java SE Development Kit 7u79). Por isso, certifique-se que esta versão está instalada em seu computador. Ela pode ser obtida em: http://www.oracle.com/technetwork/pt/java/javase/do wnloads/jdk7-downloads-1880260.html Em seguida, configure o ambiente de compilação. Para tal, clique em: Window- > Preferences. Na janela que surge, expanda a opção Java e clique em Compile. Certifique-se que a versão 1.7 será utilizada. Figura 55: Definição da versão do compilador Java Em seguida, expanda o item Installed JREs; clique em Execution Environments, em JavaSE-1.7, selecione jdk1.7 e clique em OK. Figura 56: Configuração do ambiente de execução Caso seja necessário, adicione uma JRE ao workspace: a) Clique em Add... Figura 57: Configuração do ambiente de execução b) Selecione Standard VM. Clique em Next >. Figura 58: Configuração do ambiente de execução c) Configure o parâmetro JRE home, informando o diretório de instalação da JDK1.7 (não use JRE). Para tal, clique em Directory... e, para terminar, em Finish. Figura 59: Configuração do parâmetro JRE home d) Selecione, na configuração da JRE instalada, a JDK1.7. Figura 60: Seleção da JRE padrão para o workspace e) Para terminar, clique em OK. Figura 61: Adicionando JRE ao Workspace Pronto! JRE configurada no sistema. Proceda como exibido na figura 56. Agora, crie um novo projeto (File -> New -> Java Project): Figura 62: Iniciando um projeto no Eclipse Em New Java Project, digite um nome para o projeto (por exemplo, prjTeste). Observe a JRE do projeto (JavaSE-1.7). Clique em Next. Figura 63: Nomeando o novo projeto A próxima janela diz respeito a configurações adicionais (como a pasta onde será criado o bytecode gerado pelo projeto: Default output folder). Clique em Finish. Figura 64: Configurações adicionais O Eclipse exibe detalhes do projeto na área denominada Package Explorer, como, por exemplo, a pasta src. Figura 65: Visualizando o projeto no Package Explorer Para criar uma classe em prjTeste, basta clicar sobre src com o botão direito do mouse e, depois em: New -> Class. Figura 66: Criando uma classe no projeto Digite Exemplo como nome da classe, e crie a função main: Figura 67: Definindo o nome da classe Observe que o nome da classe aparece no Package Explorer: Figura 68: Código incial da classe recém-criada A próxima etapa é complementar o código já preparado pelo Eclipse. Digite a linha de comando abaixo no método main: System.out.println("Primeiro Exemplo!"); Clique em Salvar. Figura 69: Alterando o código da classe Toda vez que um código for alterado, o Eclipse realizará a compilação deste código – automaticamente – caso a opção de construção (Build) automática (Automatically) do projeto esteja ativada (Project -> Build Automatically). Figura 70: Opção Buid Automacally Uma vez construído o projeto, pode-se executá-lo. No caso deste projeto, que é muito simples, basta que se dê um clique na tecla de atalho Run. A saída é mostrada na janela Console. Figura 71: Executando um projeto por dentro do Eclipse Um projeto Java é um conjunto de recursos que podem envolver classes, imagens, arquivos de configuração etc. O Eclipse consegue executar o projeto, ou melhor dizendo, executar o aplicativo (classe Java que contém o método main) porque as configurações do projeto são de seu conhecimento. Porém, para que se possa executar um projeto Java fora do Eclipse, é necessário a compactação do projeto em um arquivo JAR (Java ARchive), baseado no formato de arquivo ZIP padrão com um arquivo de manifesto opcional, que armazena e providencia informações sobre o conteúdo do arquivo JAR (ARNOLD, GOSLING e HOLMES, 2007). Construindo o arquivo JAR Clique com o botão direito sobre o projeto, e, depois, em Export... Figura 72: Iniciando a exportação de projeto Expanda a opção Java. Selecione JAR file. Clique em Next >. Figura 73: Selecionando exportação para arquivo JAR Na janela Jar File Specification, o checkbox antes do nome do projeto deve estar selecionado. Clique em Browse... Figura 74: Seleção do projeto a ser exportado O campo JAR file deve conter o nome (e a pasta) do arquivo JAR a ser gerado pela exportação.Caso seja necessário, expanda o projeto e selecione os arquivos desejados. Figura 75: Conferindo a seleção de arquivos do projeto a ser exportado Clique em Next >. Na janela seguinte (Jar Packaging Options) clique em Next >. Figura 76: Oções de empacotamento Na janela Jar Manifest Specification, marque o radiobutton Generate the manifest file e clique em Browse... (Main class). Figura 77: Configuração do arquivo de manifesto Selecione a classe principal (Main Class), a que contém o método main. Figura 78: Definindo a classe principal no manifesto Finalize a exportação clicando em Finish. Figura 79: Finalizando a exportação Agora, por meio do Bitvise, envie o arquivo JAR para o Linux. Figura 80: Exportando o arquivo para a máquina virtual Para testar o arquivo JAR, execute-o no terminal. A sintaxe de execução de um arquivo JAR por meio de Java é a seguinte: java –jar exemplo.jar No terminal fica como exibido a figura 81. Figura 81: Execução do projeto por meio do arquivo JAR Anotações Anotações (Annotations) são metadados que auxiliam o compilador, documentando o código-fonte, seja para detectar erros, seja para suprimir mensagens de advertências (warnings), ou auxiliar ferramentas de de software na geração de códigos, arquivos XML, dentre outras possibilidades. Ao contrário dos comentários, anotações podem ser processadas por ferramentas automáticas, apresentando informação de forma clara e padronizada. Permitem ao desenvolver marcar classes e métodos, sem, contudo, fazer parte do código. Declara-se um tipo de anotação com a seguinte sintaxe: public @interface AnotacaoNome { tipo atributoDeAnotação1(); tipo atributoDeAnotação2(); } São tipos válidos para atributos de anotação: tipos primitivos (int, float, boolean, etc.), String, classes, anotações (não pode haver recursividade), enumeração e array unidimensional de um dos tipos acima. Os atributos de anotação possuem sintaxe igual a dos métodos, mas se comportam como atributos de uma classe; são delimitados por chaves e podem ser iniciados com valores a partir da declaração do tipo de anotação. Para tal, usa-se a cláusula default após o nome do elemento, seguido do valor a ser atribuído a ele. Uma vez declarada a anotação, pode-se utilizá-la em uma classe pela especificação do caractere @, seguido do nome da anotação e, delimitado por parênteses, os elementos de anotação (recebendo valores compatíveis com seus tipos) separados por vírgula. Pode-se criar anotações ou utilizar anotações predefinidas (como @Override ou @Deprecated), cada qual com uma funcionalidade específica. Criando Anotações com o Eclipse Inicie um novo projeto no Eclipse e siga os passos abaixo: a) Adicione uma anotação: File -> New -> Annotation b) Insira o código da anotação: package nome_pacote; public @interface AnotacaoNome { String attr1(); String attr2(); } c) Adicione uma classe: File -> New -> Class d) Insira o código da classe: package nome_pacote; @AnotacaoNome ( attr1 = "valor 1" , attr2 = "valor 2" ) public class NomeClasse { public static void main(String[] args) { // TODO Auto-generated method stub // Código do método main } } Anotações predefinidas A seguir, são apresentadas algumas anotações predefinidas: Anotação: Deprecated Função: Um elemento que recebe essa anotação tem seu uso desencorajado. Anotação: Override Função: utilizada quando o método da subclasse deve sobrescrever o método da superclasse utilizando a mesma assinatura, ou seja, mesmo tipo de retorno, mesmo nome e os mesmos parâmetros (quantidade, nomes e tipos). Os blocos de comando que os métodos definem podem ser diferentes, mas as assinaturas dos métodos devem idênticas. Anotação: SuppresWarnings Função: As mensagens de advertência devem ser suprimidas para o elemento anotado. Elemento requerido: String[] value Obs: Alguns valores válidos para value: all : suprime todos as mensagens de advertência boxing : suprime mensagens de advertência relativas a processos de conversão de empacotamento (boxing/unboxing), quando um elemento é convertido para sua classe (int para Integer, por exemplo), e vice-versa Para exemplificar, crie a anotação Autoria: package br.estacio.pos.bigdata.tecnologiaAvancada; import java.lang.annotation.Documented; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Documented @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface Autoria { String autor(); String data(); double versao() default 1.0; Agora, crie a classe UsaAnotacoes: package br.estacio.pos.bigdata.tecnologiaAvancada; import java.lang.SuppressWarnings; @SuppressWarnings( { "all" } ) @Autoria (autor = "Multitecnus" , data = "15/03/2011" ) public class UsaAnotacoes { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println ("Utilizando annotation"); } } Maven A confecção de um projeto, em geral, envolve a utilização de código externo ao do projeto ora em desenvolvimento. Essa dependência se resolve com a importação de arquivos JAR no início de cada código. Por meio de um site de busca, as dependências podem ser encotnradas, baixadas e adicionadas ao projeto. Entretanto, alguns arquivos JAR dependem da importação de outros arquivos JAR, o que causa subdependências que podem se aprofundar em vários níveis. Uma forma de automatizar a resolução de dependências de um projeto, é utilizar o Apache Maven™, uma ferramenta de gerenciamento e compreensão (software comprehension) de projetos de software. O Maven é baseado no modelo de objeto de projeto, ou POM (Project Object Model), em que um arquivo XML (pom.xml) descreve todo o projeto e detalhes de configuração, tal como os diretórios com os códigos-fonte (/src/main/java) e de teste (src/main/test), a versão do projeto, suas dependências, dentre outras informações. Assim, na execução da tarefa, Maven procura o POM e lê as informações lá contidas. Com Maven, o projeto conta com um repositório, local (padrão) ou remoto, no qual estão os artefatos dos quais o projeto depende. POM (Project Object Model) Chamado em Maven 1 de project.xml, este arquivo, unidade de trabalho fundamental em um projeto Maven, foi renomeado para pom.xml a partir de Maven 2. É um arquivo XML que contém informação sobre o projeto e detalhes de configuração, e que é lido por Maven quando da execução de uma fase. O POM padrão para Maven é chamado de Super POM, e todo POM o estende. O mínimo requerido por um POM é: - Tag root <project> </<project> - Versão do modelo (atualmente, utiliza-se 4.0.0 por padrão) - Identificação do grupo - Identificação do artefato (projeto) - Versão do artefato No formato XML ficaria como: <project> <modelVersion>4.0.0</modelVersion> <groupId>id.do.grupo</groupId> <artifactId>nome.artefato</artifactId> <version>1</version> </project> Um exemplo de arquivo POM com dependência adicionada: Figura 82: Exemplo de arquivo POM com dependência Criando um Projeto Maven Para criar um projeto Maven, clique em File -> New -> Other... Figura 83: Iniciando um novo projeto Na janela Select a wizard, selecione Maven Project: Figura 84: Iniciando um projeto Maven Em seguida, marque o checkbox Create a simple project: Figura 85: Criando o projeto Maven sem utilizar templates Na janela Configure Project serão inseridas as seguintes informações:
Compartilhar