Depois de passar um bom tempo sem escrever nenhum post por aqui, este post marca início de vários post que pretendo escrever sobre diversas ferramentas que andei usando nos últimos tempos.
Porque instalação de hadoop, o primeiro? Nos últimos meses estou participando de um projeto relacionado a manipulação de BigData, tive uma certa dificuldade para fazer o setup de um single node no meu computador e conversando com outros desenvolvedores estes também tiveram dificuldades ou até desistiram de instalar. Há uma série de detalhes que combinados entre si fazem da instalação mais complexa que deveria.
O Apache Hadoop é um projeto para computação distribuída. Ele permite o processamento de grandes volumes de dados em clusters usando simples modelos de programação. Ele oferece o HDFS, que nada mais é que um sistema de arquivos distribuído com oferece um alto throughput. Yarn e o MapReduce que permite a execução em paralelo de grande volume de dados.
Passos iniciais
Para simplificar a instalação, use o HomeBrew antes de instalar, faça um brew update para atualizar as fórmulas (Dica do Bruno Carvalho
)
1 2 3 | $ brew update $ brew install hadoop |
Isto instalará os arquivos no diretório: /usr/local/Cellar/hadoop/VERSAO/libexec/. Você pode criar variável de ambiente para este path: HADOOP_HOME. Para facilitar adicione a pasta lib no path no arquivo .bash_profile:
1 2 3 | $ echo 'export JAVA_HOME="$(/usr/libexec/java_home)"' >> ~/.bash_profile $ echo 'export HADOOP_HOME=/usr/local/Cellar/hadoop/1.1.2/libexec' >> ~/.bash_profile $ echo 'export PATH=$PATH:$HADOOP_HOME/bin' >> ~/.bash_profile |
Você pode ter visto em várias pessoas falando que é preciso criar um usuário hadoop, mas isto não é necessário. Pode ser bom para testes futuros com permissionamento e tudo mais.
Configurando SSH
O Hadoop usa SSH para inicialização dos serviços em background e acesso do master node aos slaves para parar e iniciar os serviços. Isto também é usando para a configuração de Secondary Name Nodes. Portanto o próximo passo é habilitar o SSH:
Faça o teste:
1 | $ ssh localhost |
Uma vez feito isso, copie sua chave ssh para a authorized_keys evitando que você precise digitar a senha.
1 2 | $ ssh-keygen -t dsa -P “” -f ~/.ssh/id_dsa $ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys |
Configurando o Hadoop
Será necessário criar 3 diretórios necessários para o hadoop salvar os arquivos do sistema de arquivos, os metadados deste sistema de arquivos e os metadados dos jobs. Para facilitar a organização crie um diretório hadoop dentro do diretório raiz do usuário.
1 2 3 4 | $ mkdir -p ~/hadoop/data $ mkdir -p ~/hadoop/name $ mkdir -p ~/hadoop/store $ mkdir -p ~/hadoop/temp |
Neste ponto falta fazer os acertos necessários nos xmls para finalizar a instalação. Depois de fazer inúmeras vezes esta instalação e passar a conhecer melhor os parâmetros, as configurações a seguir são as mínimas necessárias para fazer o single node funcionar. Ao abrir os arquivos você notará uma série de parâmetros, porém deixe apenas o mínimo para não gerar conflitos.
Configurações do HDFS
O primeiro é o HDFS. Edite o arquivo HADOOP_HOME/conf/hdfs-site.xml, que a princípio não precisamos informar mais que o diretório onde serão armazenados os dados do sistema de arquivo e onde serão gravados os metadados do mesmo. A terceira propriedade é o número de replicações dos arquivos, como estamos usando single node o valor é 1. Definir o web.ugi aqui é para definir qual será o usuário usado no webview, quando acessar os logs teria uma mensagem falando que você não tem o usuário webuser, usuário padrão. Para maiores informações de como configurar confira este link:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>dfs.data.dir</name> <value>/Users/${user.name}/hadoop/data</value> </property> <property> <name>dfs.name.dir</name> <value>/Users/${user.name}/hadoop/namenode</value> </property> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.web.ugi</name> <value>${user.name},staff</value> </property> </configuration> |
Configurações hadoop core
Outro arquivo a ser editado é o core-site.xml que contem as configurações básicas do hadoop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>hadoop.tmp.dir</name> <value>/Users/${user.name}/hadoop/tmp</value> </property> <property> <name>mapred.system.dir</name> <value>/Users/${user.name}/hadoop/store</value> </property> <property> <name>fs.default.name</name> <value>hdfs://localhost:50001</value> </property> </configuration> |
Aqui foi preciso só informar a localização da pasta de arquivos temporários do hadoop e o system dir do JobTracker. Além disso foi informado host do serviço do HDFS. A porta informada neste campo será usa durante o startup e todos os clientes a usarão para se conectar via RPC no HDFS.
Configurações Map Reduce
Vamos agora as configurações para o JobTracker e TaskTracker. Primeiro o arquivo mapred-site.xml fica assim:
1 2 3 4 5 6 7 8 9 | <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>mapred.job.tracker</name> <value>localhost:50002</value> </property> </configuration> |
Os demais arquivos de configurações podem deixar da maneira como está. Quase tudo pronto, o último passo é formatar o namenode.
Formatação do namenode
Este passo se faz necessário pois o hadoop cria blocos de 64MB, por padrão sendo configurável, para otimizar o armazenamento de grandes arquivos. A formatação é o marco inicial para o funcionamento do sistema de arquivos.
1 | $ $HADOOP_HOME/bin/hadoop namenode -format |
Este comando deve gerar um output semelhante a este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 13/03/28 16:41:34 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = marcossousa/192.168.1.43 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 1.1.2 STARTUP_MSG: build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.1 -r 1440782; compiled by 'hortonfo' on Thu Jan 31 02:03:24 UTC 2013 ************************************************************/ 13/03/28 16:41:34 INFO util.GSet: VM type = 64-bit 13/03/28 16:41:34 INFO util.GSet: 2% max memory = 19.83375 MB 13/03/28 16:41:34 INFO util.GSet: capacity = 2^21 = 2097152 entries 13/03/28 16:41:34 INFO util.GSet: recommended=2097152, actual=2097152 13/03/28 16:41:34 INFO namenode.FSNamesystem: fsOwner=marcossouza 13/03/28 16:41:34 INFO namenode.FSNamesystem: supergroup=supergroup 13/03/28 16:41:34 INFO namenode.FSNamesystem: isPermissionEnabled=true 13/03/28 16:41:34 INFO namenode.FSNamesystem: dfs.block.invalidate.limit=100 13/03/28 16:41:34 INFO namenode.FSNamesystem: isAccessTokenEnabled=false accessKeyUpdateInterval=0 min(s), accessTokenLifetime=0 min(s) 13/03/28 16:41:34 INFO namenode.NameNode: Caching file names occuring more than 10 times 13/03/28 16:41:35 INFO common.Storage: Image file of size 117 saved in 0 seconds. 13/03/28 16:41:35 INFO namenode.FSEditLog: closing edit log: position=4, editlog=/Users/marcossouza/hadoop/namenode/current/edits 13/03/28 16:41:35 INFO namenode.FSEditLog: close success: truncate to 4, editlog=/Users/marcossouza/hadoop/namenode/current/edits 13/03/28 16:41:35 INFO common.Storage: Storage directory /Users/marcossouza/hadoop/namenode has been successfully formatted. 13/03/28 16:41:35 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at marcossousa/192.168.1.43 ************************************************************/ |
Iniciando o hadoop
Caso a operação falhar, verifique se as configurações estão corretas. Nunca se esqueça que os diretórios criados acima devem estar obrigatoriamente vazios. Pronto! Agora é só iniciar
1 | $ $HADOOP_HOME/bin/start-all.sh |
A saída será algo parecido com o snippet abaixo:
1 2 3 4 5 | starting namenode, logging to /usr/local/Cellar/hadoop/1.1.2/libexec/bin/../logs/hadoop-marcossouza-namenode-marcossousa.out localhost: starting datanode, logging to /usr/local/Cellar/hadoop/1.1.2/libexec/bin/../logs/hadoop-marcossouza-datanode-marcossousa.out localhost: starting secondarynamenode, logging to /usr/local/Cellar/hadoop/1.1.2/libexec/bin/../logs/hadoop-marcossouza-secondarynamenode-marcossousa.out starting jobtracker, logging to /usr/local/Cellar/hadoop/1.1.2/libexec/bin/../logs/hadoop-marcossouza-jobtracker-marcossousa.out localhost: starting tasktracker, logging to /usr/local/Cellar/hadoop/1.1.2/libexec/bin/../logs/hadoop-marcossouza-tasktracker-marcossousa.out |
Validando a instalação
Verifique se as portas:
50001 – RPC NameNode
50002 – RPC Jobtracker
50070 – Webconsole namenode
50075 – Webconsole datanone
50030 – JobTracker
Rodando o comando abaixo deve vir pelo menos 6 como resultado:
1 | $ ps aux | grep java | wc -l |
Acessando http://localhost:50070 você verá esta página do datanode:
Acessando http://localhost:50030 você verá esta página do jobtracker:
Isto indica que o hadoop foi instalado com sucesso!
Rodando o primeiro Job Map Reduce
Para fazer o teste completo vamos rodar um exemplo que faz a contagem de palavras. Para isso faça download de 3 livros no formato TXT e mova-os para o HDFS e depois rode o job.
Inicie fazendo o download dos arquivos TXT nos links abaixo para a pasta `/tmp`.
- The Outline of Science, Vol. 1 (of 4) by J. Arthur Thomson
- The Notebooks of Leonardo Da Vinci
- Ulysses by James Joyce
Agora crie um diretório no HDFS e copie os arquivos para lá:
1 2 | $ hadoop fs -mkdir /first_test $ hadoop fs -moveFromLocal /tmp/pg*.txt /first_test |
Pronto, basta rodar o exemplo a partir do HADOOP_HOME, apenas para pegar o jar com exemplos de jobs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | me@marcossousa /usr/local/Cellar/hadoop/1.1.2/libexec (master) $ bin/hadoop jar hadoop*examples*.jar wordcount /first_test /first_test/output 13/03/28 16:51:49 INFO input.FileInputFormat: Total input paths to process : 3 13/03/28 16:51:49 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 13/03/28 16:51:49 WARN snappy.LoadSnappy: Snappy native library not loaded 13/03/28 16:51:49 INFO mapred.JobClient: Running job: job_201303310236_0002 13/03/28 16:51:50 INFO mapred.JobClient: map 0% reduce 0% 13/03/28 16:51:58 INFO mapred.JobClient: map 66% reduce 0% 13/03/28 16:52:02 INFO mapred.JobClient: map 100% reduce 0% 13/03/28 16:52:06 INFO mapred.JobClient: map 100% reduce 33% 13/03/28 16:52:08 INFO mapred.JobClient: map 100% reduce 100% 13/03/28 16:52:09 INFO mapred.JobClient: Job complete: job_201303310236_0002 13/03/28 16:52:09 INFO mapred.JobClient: Counters: 26 13/03/28 16:52:09 INFO mapred.JobClient: Job Counters 13/03/28 16:52:09 INFO mapred.JobClient: Launched reduce tasks=1 13/03/28 16:52:09 INFO mapred.JobClient: SLOTS_MILLIS_MAPS=15680 13/03/28 16:52:09 INFO mapred.JobClient: Total time spent by all reduces waiting after reserving slots (ms)=0 13/03/28 16:52:09 INFO mapred.JobClient: Total time spent by all maps waiting after reserving slots (ms)=0 13/03/28 16:52:09 INFO mapred.JobClient: Launched map tasks=3 13/03/28 16:52:09 INFO mapred.JobClient: Data-local map tasks=3 13/03/28 16:52:09 INFO mapred.JobClient: SLOTS_MILLIS_REDUCES=10528 13/03/28 16:52:09 INFO mapred.JobClient: File Output Format Counters 13/03/28 16:52:09 INFO mapred.JobClient: Bytes Written=880838 13/03/28 16:52:09 INFO mapred.JobClient: FileSystemCounters 13/03/28 16:52:09 INFO mapred.JobClient: FILE_BYTES_READ=2214875 13/03/28 16:52:09 INFO mapred.JobClient: HDFS_BYTES_READ=3671851 13/03/28 16:52:09 INFO mapred.JobClient: FILE_BYTES_WRITTEN=3914093 13/03/28 16:52:09 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=880838 13/03/28 16:52:09 INFO mapred.JobClient: File Input Format Counters 13/03/28 16:52:09 INFO mapred.JobClient: Bytes Read=3671523 13/03/28 16:52:09 INFO mapred.JobClient: Map-Reduce Framework 13/03/28 16:52:09 INFO mapred.JobClient: Map output materialized bytes=1474367 13/03/28 16:52:09 INFO mapred.JobClient: Map input records=77931 13/03/28 16:52:09 INFO mapred.JobClient: Reduce shuffle bytes=1474367 13/03/28 16:52:09 INFO mapred.JobClient: Spilled Records=255966 13/03/28 16:52:09 INFO mapred.JobClient: Map output bytes=6076101 13/03/28 16:52:09 INFO mapred.JobClient: Total committed heap usage (bytes)=673505280 13/03/28 16:52:09 INFO mapred.JobClient: Combine input records=629172 13/03/28 16:52:09 INFO mapred.JobClient: SPLIT_RAW_BYTES=328 13/03/28 16:52:09 INFO mapred.JobClient: Reduce input records=102324 13/03/28 16:52:09 INFO mapred.JobClient: Reduce input groups=82335 13/03/28 16:52:09 INFO mapred.JobClient: Combine output records=102324 13/03/28 16:52:09 INFO mapred.JobClient: Reduce output records=82335 13/03/28 16:52:09 INFO mapred.JobClient: Map output records=629172 |
O Resultado é parecido com o valor acima
Nos próximos posts irei abordar mais sobre algumas configurações do hadoop e bugs também.
