De volta aqui nessa jornada em apreender, evoluir e não ficar parado. Quem me conhece sabe que eu sou do litoral Paulista, e lá o pessoal costuma citar o trecho de um samba do Zeca Pagodinho, que diz: “Camarão que dorme a onda leva”. Conta a história de alguém se lamentado, e nós não queremos isso. Então vamos ao objetivo.
Falaremos sobre como levantar o ambiente, comandos básicos de manipulação de arquivos do cluster, build com o Maven e, por fim, utilizando a técnica map reduce para contagem de palavras.
Este artigo representa as minhas anotações referentes ao estudo. À medida que irei evoluindo, é aqui que eu vou direcionar esse assunto. Pode ser que depois de um tempo sejam adicionadas novas informações.
O primeiro passo é obter a imagem do CDH 5.13, diretamente no link da Cloudera, referência no assunto quando se trata de Big Data. Existem diversas opções – eu normalmente prefiro o Docker, mas sinta-se a vontade para obter a plataforma que se sente mais a vontade.
Obtendo o ambiente — Essa abordagem falhou:
- Download QuickStarts for CDH 5.13 | Cloudera
- Link: https://www.cloudera.com/downloads/quickstart_vms/5-13.html
- Cloudera QuickStart virtual machines (VMs) include everything you need to try CDH, Manager, Impala, and Cloudera
- www.cloudera.com
Optei pelo Docker, porque normalmente dispende menor espaço de armazenamento no disco, mas curiosamente tem mais de 4GB. Vou concluir o download e conferir o conteúdo. Me surpreenderam ainda mais os 7GB depois de descompactado. Esperava obter somente o docker-compose.yml ou um Dockefile.
No diretório, encontrei o arquivo: “cloudera-quickstart-vm-5.13.0–0-beta-docker.tar.gz“. Para descompactar, fazemos desta forma:
$ tar -vzxf cloudera-quickstart-vm-5.13.0–0-beta-docker.tar.gz cloudera-quickstart-vm-5.13.0–0-beta-docker/cloudera-quickstart-vm-5.13.0–0-beta-docker.tar
cloudera-quickstart-vm-5.13.0–0-beta-docker/cloudera-quickstart-vm-5.13.0–0-beta-docker.tar
Percebemos que foi criado um subdiretório: “cloudera-quickstart-vm-5.13.0–0-beta-docker”. Acesse esse diretório e você verá o arquivo: “cloudera-quickstart-vm-5.13.0–0-beta-docker.tar”.
Vamos ver o que encontraremos:
$ tar -tf cloudera-quickstart-vm-5.13.0–0-beta-docker.tar | egrep “.yml|yaml”
Nenhum docker-compose.yml?
No entendimento, encontrei este link: https://tuhrig.de/difference-between-save-and-export-in-docker/
Também não foi possível realizar o carregamento?
$ docker load < cloudera-quickstart-vm-5.13.0–0-beta-docker.tar
open /var/lib/docker/tmp/docker-import-927734140/bin/json: no such file or directory
A minha versão do Docker:
$ docker --version
Docker version 18.06.1-ce, build e68fc7a
Acredito que entender o que deu certo é importante, mas o que não deu é tão importante quanto, e através desses passos que chegaremos lá.
Obtendo o ambiente — Sucesso:
Vamos na referência principal do assunto Docker Hub. Não pretendo manter imagens que consomem espaço no disco, por isso que pretendo que funcione via Docker. Encontrei um repo interessante – vamos baixar:
$ git clone https://github.com/chali/hadoop-cdh-pseudo-docker.git
Acesse o diretório que foi criado: “hadoop-cdh-pseudo-docker” e realize o build:
$ time docker build -t cdh5-pseudo-distro .
O comando time, serve para exibir o tempo de duração do processo. Aqui, demorou 14 minutos e 11 segundos.
real 14m11,74s
user 0m0,37s
sys 0m0,16s
Para executar, utilizaremos o docker-compose abaixo:
version: '3'
services:
ddh5:
restart: always
image: cdh5-pseudo-distro
ports:
- 8020:8020
- 50070:50070
- 50010:50010
- 50020:50020
- 50075:50075
- 8030:8030
- 8031:8031
- 8032:8032
- 8033:8033
- 8088:8088
- 8040:8040
- 8042:8042
- 10020:10020
- 19888:19888
- 11000:11000
- 8888:8888
- 18080:18080
- 9999:9999
Para inicializar:
$ docker-compose up -d
Relação dos serviços provisionados
- name node — http://localhost:50070
- resource manager — http://localhost:8088
- job history server — http://localhost:19888
- oozie console — http://localhost:11000
- hue — http://localhost:8888
- spark history server — http://localhost:18080
Se chegou a este ponto, todos os serviços estão UP. Os últimos da lista demoraram alguns minutos para iniciar completamente.
Vamos acessar o Docker em modo interativo, que é nada mais nada menos que a linha de comando.
$ docker exec -it hadoopcdhpseudodocker_ddh5_1 bash
Realizaremos a instalação de alguns componentes que não estão na imagem, como é somente um ambiente de estudo, esta forma atende. Se fosse um outro tipo de ambiente, deveríamos incluir no build:
Embora em produção, eu não vejo como uma boa prática mais de um node do cluster na mesma máquina.
# cat /etc/*release* | egrep -i “id|name”
Resultado:
DISTRIB_ID=Ubuntu
DISTRIB_CODENAME=trusty
NAME=”Ubuntu”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=”Ubuntu 14.04.5 LTS”
VERSION_ID=”14.04"
Percebemos que este sistema operacional é Ubuntu, então utilizaremos o apt.
Instalaremos o Git, o Curl e o Maven, que muitos dizem consumir metade da internet.
apt update && apt install git curl maven tree -y
Pronto, realizada as devidas instalações! Vamos alterar para o usuário do serviço: hdsf, e criar os diretórios conforme abaixo:
root@1199277c77f4:/# su - hdfs
hdfs@1199277c77f4:~$ hdfs dfs -ls /
Found 3 itemsdrwxrwxrwt — hdfs supergroup 0 2018–09–30 02:03 /tmp
drwxr-xr-x — hdfs supergroup 0 2018–09–30 02:09 /user
drwxr-xr-x — hdfs supergroup 0 2018–09–30 02:03 /var
Dataset
Segundo a Wikipedia, a definição:
Um conjunto de dados ou “dataset” é uma coleção de dados normalmente tabulados. Por cada elemento (ou indivíduo) se indicam várias características. Cada coluna representa uma variável particular. Cada linha corresponde a um determinado membro do conjunto de dados em questão. Cada valor é conhecido como um dado. O conjunto de dados pode incluir dados para um ou mais membros, correspondente ao número de linhas.
Encontrei esse portal do governo brasileiro que contém alguns datasets que podemos explorar:
- Conjuntos de dados – Portal Brasileiro de Dados Abertos
- Base de dados contendo os Ocupantes de Cargos de Gerência e Direção em Empresas Estatais e suas Subsidiárias. Os dados
- dados.gov.br
Poderia selecionar qualquer um, mas o que me chamou a atenção, foi esse:
Resgates do Tesouro Direto
Este conjunto de dados apresenta o volume financeiro de resgates ocorridos no Tesouro Direto em determinado mês. Os resgates são divididos em três grupos – os títulos recomprados.
Baixar de um repositório blockchain para a home do usuário hdfs com o comando curl:
CupomJurosTesouroDireto.csv
$ curl --insecure -s https://www.tesourotransparente.gov.br/ckan/dataset/f30db6e4-6123-416c-b094-be8dfc823601/resource/de2af5cf-9dbd-4566-b933-da6871cce030/download/CupomJurosTesouroDireto.csv > CupomJurosTesouroDireto.csv
RecomprasTesouroDireto.csv
$ curl --insecure -s https://www.tesourotransparente.gov.br/ckan/dataset/f30db6e4-6123-416c-b094-be8dfc823601/resource/30c2b3f5-6edd-499a-8514-062bfda0f61a/download/RecomprasTesouroDireto.csv > RecomprasTesouroDireto.csv
VencimentosTesouroDireto.csv
$ curl --insecure -s https://www.tesourotransparente.gov.br/ckan/dataset/f30db6e4-6123-416c-b094-be8dfc823601/resource/9180ec46-5d73-49ab-bd26-f16e2b323f74/download/VencimentosTesouroDireto.csv > VencimentosTesouroDireto.csv
Pronto! Feito essa parada – opa, o Download, vamos conferir o arquivo:
$ ls -lrt *.csv
-rw-rw-r — 1 hdfs hdfs 17362 Sep 30 14:09 CupomJurosTesouroDireto.csv
-rw-rw-r — 1 hdfs hdfs 1916891 Sep 30 14:09 RecomprasTesouroDireto.csv
-rw-rw-r — 1 hdfs hdfs 5456 Sep 30 14:09 VencimentosTesouroDireto.csv
Criaremos o diretório lá no cluster:
$ hdfs dfs -mkdir -p /user/cloudera/resgates-do-tesouro-direto
Vamos levar o arquivo para o local que acabamos de criar.
$ hdfs dfs -put ./*.csv /user/cloudera/resgates-do-tesouro-direto
Para listar os arquivos:
$ hdfs dfs -ls /user/cloudera/resgates-do-tesouro-direto
Found 3 items
Resposta esperada:
-rw-r--r-- 1 hdfs supergroup 17362 2018-09-30 14:21 /user/cloudera/resgates-do-tesouro-direto/CupomJurosTesouroDireto.csv
-rw-r--r-- 1 hdfs supergroup 1916891 2018-09-30 14:21 /user/cloudera/resgates-do-tesouro-direto/RecomprasTesouroDireto.csv
-rw-r--r-- 1 hdfs supergroup 5456 2018-09-30 14:21 /user/cloudera/resgates-do-tesouro-direto/VencimentosTesouroDireto.csv
Exercícios
Vamos verificar a quantidade de replicas do arquivo: RecomprasTesouroDireto.csv, existentes no cluster:
$ hadoop fs -stat %r /user/cloudera/resgates-do-tesouro-direto/RecomprasTesouroDireto.csv
A resposta é 1. Ou seja, há somente uma réplica deste arquivo.
Ajustaremos esse valor que inicialmente possuía o valor definido 1 para 3, e em seguida pediremos que exiba a informação da quantidade de replicação do determinado arquivo:
$ hadoop fs -setrep 3 /user/cloudera/resgates-do-tesouro-direto/RecomprasTesouroDireto.csv
Replication 3 set: /user/cloudera/resgates-do-tesouro-direto/RecomprasTesouroDireto.csv
$ hadoop fs -stat %r /user/cloudera/resgates-do-tesouro-direto/RecomprasTesouroDireto.csv
3
Podemos observar que os comandos possuem similaridade com ambientes Unix/Linux. É necessário utilizar o prefixo: “hdfs dfs”, e depois o comando tradicional seguidos por “-”. Para obter ajuda, utilize: “hdfs dfs -help”.
Abaixo segue a listagem:
$ hdfs dfs -help
Usage: hadoop fs [generic options]
[-appendToFile <localsrc> … <dst>]
[-cat [-ignoreCrc] <src> …]
[-checksum <src> …]
[-chgrp [-R] GROUP PATH…]
[-chmod [-R] <MODE[,MODE]… | OCTALMODE> PATH…]
[-chown [-R] [OWNER][:[GROUP]] PATH…]
[-copyFromLocal [-f] [-p] [-l] <localsrc> … <dst>]
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> … <localdst>]
[-count [-q] [-h] [-v] [-x] <path> …]
[-cp [-f] [-p | -p[topax]] <src> … <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> …]]
[-du [-s] [-h] [-x] <path> …]
[-expunge]
[-find <path> … <expression> …]
[-get [-p] [-ignoreCrc] [-crc] <src> … <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {-n name | -d} [-e en] <path>]
[-getmerge [-nl] <src> <localdst>]
[-help [cmd …]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [<path> …]]
[-mkdir [-p] <path> …]
[-moveFromLocal <localsrc> … <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> … <dst>]
[-put [-f] [-p] [-l] <localsrc> … <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] <src> …]
[-rmdir [ — ignore-fail-on-non-empty] <dir> …]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[ — set <acl_spec> <path>]]
[-setfattr {-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> …]
[-stat [format] <path> …]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> …]
[-touchz <path> …]
[-usage [cmd …]]
Assim fica mais fácil. Eu, particularmente, acho incrível o quanto o conhecimento é concatenado. É só lembrar que há uma camada de controle e é necessário respeitar as condições.
Map Reduce
O Map Reduce é uma abordagem que diversas referencias utilizam a citação:
- “Dividir para conquistar” – Sun Tzu
Assim como na guerra ou na resolução de prolemas complexos, é necessário quebrar o problema principal em partes menores e resolvê-los um de cada vez. Isso trará confiança e segurança a cada passo que se evolui.
Essa etapa consiste em agrupar e organizar a informação, como organizar uma coleção qualquer. Poderiam ser músicas, filmes ou livros e todos esses cenários conseguimos organizar de acordo com o exemplo:
- Musicas: pop rock, mpb, edm
- Filmes: ação, drama, comédia
- Livros: romance, ficção, infantil
Também é possível, ter uma visão diferente ou por outros atributos: data de lançamento, autor, diretor ou editora, assim como o mapeamento que poderia ser país de origem, idioma ou público alvo. Enfim, o importante nesse passo é admitir que a granularidade informacional poderá ser abrangente, mas também precisa fazer sentido.
Abaixo, um diagrama para exemplificar:
Vamos baixar o código fonte que faz a contagem das palavras. Esse é o nosso objetivo: contar as palavras, analisar e assim estabelecer a direção para o resultado final.
Iremos compilar o código que será responsável pelo processamento e obteremos do repositório no GitHub que atenderá as nossas expectativas. O clone:
$ git clone https://github.com/emirandacombr/fundamentos-big-data.git
Acessaremos o diretório: “fundamentos-big-data” e inspecionaremos.
$ cd fundamentos-big-data.git/
tree
.
|-- README.md
|-- codigo
| |-- hadoop
| | |-- DeficitSuperavit
| | | |-- README.md
| | | |-- pom.xml
| | | `-- src
| | | `-- main
| | | `-- java
| | | `-- com
| | | `-- fundamentosbigdata
| | | |-- DeficitSuperavitDriver.java
| | | |-- DeficitSuperavitMapper.java
| | | `-- DeficitSuperavitReducer.java
| | `-- WordCount
| | |-- README.md
| | |-- pom.xml
| | `-- src
| | `-- main
| | `-- java
| | `-- com
| | `-- fundamentosbigdata
| | `-- WordCount.java
| `-- spark
| `-- WordCount
| |-- README.md
| |-- pom.xml
| `-- src
| `-- main
| `-- scala
| `-- com
| `-- fundamentosbigdata
| `-- SparkWordCount.scala
|-- dados
| |-- NASA_access_log_Aug95.gz
| |-- NYSE_daily.txt
| |-- NYSE_dividends.txt
| |-- README.md
| |-- SummaryOfReceiptsOutlaysSurplusesDeficits.txt
| |-- adult.data.csv
| |-- baseball.txt
| |-- baseballdatabank-master_2016-03-02.zip
| |-- center_earth.txt
| |-- hero-network.csv.zip
| |-- ml-10m.zip
| `-- sfpd.csv.zip
|-- exerc\303\255cios
| `-- README.md
`-- scripts
|-- flume
| |-- README.md
| |-- spool-to-hdfs.properties
| `-- twitter-flume.conf
|-- hbase
| `-- README.md
|-- hdfs
| `-- README.md
|-- hive
| `-- README.md
|-- pig
| `-- README.md
|-- spark
| `-- README.md
`-- sqoop
`-- README.md
31 directories, 34 files
O código fonte: “/var/lib/hadoop-hdfs/fundamentos-big-data/codigo/hadoop/WordCount/src/main/java/com/fundamentosbigdata/WordCount.java”.
A partir da estrutura dos repositórios locais, encontramos o diretório: “código”, e dois níveis abaixo o arquivo “pom.xml”. Para quem ainda não está acostumado, trata do arquivo de configuração e apontamentos do Maven.
Maven
Segundo a Wikipedia, a definição:
Apache Maven, ou Maven, é uma ferramenta de automação de compilação utilizada primariamente em projetos Java. Ela é similar à ferramenta Ant, mas é baseada em conceitos e trabalhos diferentes em um modo diferente. Também é utilizada para construir e gerenciar projetos escritos em C#, Ruby, Scala e outras linguagens. O projeto Maven é hospedado pela Apache Software Foundation, que fazia parte do antigo Projeto Jakarta.
Hora da magica acontecer! O código Java e o repositório são do Eduardo Miranda.
Novamente, utilizo o comando time para saber em quanto tempo será executado. A primeira vez demora um pouco para baixar os artefatos referentes ao build.
$ cd
$ time mvn -f ./fundamentos-big-data/codigo/hadoop/WordCount/pom.xml clean package
Aqui o tempo de execução do build foi menor que cinco minutos, e o melhor é que tudo ocorreu com sucesso.
Acessaremos a home caso não esteja nesse local, e assim criaremos um diretório lá no cluster para a entrada de dados:
$ cd
$ hadoop fs -mkdir -p /user/cloudera/wordcount/input
Em nosso exemplo, o código está separado por “;”. Vamos adequar essa entrada e substituir esse caractere “;” por um espaço simples ” “, para que o código principal entenda e conte corretamente.
Executar somente uma única vez este passo.
$ sed ‘s/ /_/g;s/;/ /g’ RecomprasTesouroDireto.csv > $.tmp && mv $.tmp RecomprasTesouroDireto.txt
Faremos a movimentação do arquivo para este novo diretório:
$ hadoop fs -put RecomprasTesouroDireto.csv /user/cloudera/wordcount/input
Confira a entrada:
$ hadoop fs -ls /user/cloudera/wordcount/input
Found 1 items
-rw-r--r-- 1 hdfs supergroup 1916891 2018-09-30 15:17 /user/cloudera/wordcount/input/RecomprasTesouroDireto.csv
Rode o comando descrito abaixo:
$ cd
$ cd ./fundamentos-big-data/codigo/hadoop/WordCount
$ hadoop jar target/WordCount-1.0-SNAPSHOT.jar com.fundamentosbigdata.WordCount /user/cloudera/wordcount/input /user/cloudera/wordcount/output
Retorno do processamento :
18/09/30 21:08:27 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
18/09/30 21:08:28 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.
18/09/30 21:08:28 INFO input.FileInputFormat: Total input paths to process : 1
18/09/30 21:08:28 INFO mapreduce.JobSubmitter: number of splits:1
18/09/30 21:08:29 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1538338998981_0002
18/09/30 21:08:29 INFO impl.YarnClientImpl: Submitted application application_1538338998981_0002
18/09/30 21:08:29 INFO mapreduce.Job: The url to track the job: http://8668ed0c576d:8088/proxy/application_1538338998981_0002/
18/09/30 21:08:29 INFO mapreduce.Job: Running job: job_1538338998981_0002
18/09/30 21:08:35 INFO mapreduce.Job: Job job_1538338998981_0002 running in uber mode : true
18/09/30 21:08:35 INFO mapreduce.Job: map 100% reduce 0%
18/09/30 21:08:38 INFO mapreduce.Job: map 100% reduce 100%
18/09/30 21:08:39 INFO mapreduce.Job: Job job_1538338998981_0002 completed successfully
18/09/30 21:08:40 INFO mapreduce.Job: Counters: 56
File System Counters
FILE: Number of bytes read=1470678
FILE: Number of bytes written=2206033
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=3834122
HDFS: Number of bytes written=811667
HDFS: Number of read operations=35
HDFS: Number of large read operations=0
HDFS: Number of write operations=10
Job Counters
Launched map tasks=1
Launched reduce tasks=1
Other local map tasks=1
Total time spent by all maps in occupied slots (ms)=0
Total time spent by all reduces in occupied slots (ms)=0
TOTAL_LAUNCHED_UBERTASKS=2
NUM_UBER_SUBMAPS=1
NUM_UBER_SUBREDUCES=1
Total time spent by all map tasks (ms)=1499
Total time spent by all reduce tasks (ms)=1524
Total vcore-milliseconds taken by all map tasks=0
Total vcore-milliseconds taken by all reduce tasks=0
Total megabyte-milliseconds taken by all map tasks=0
Total megabyte-milliseconds taken by all reduce tasks=0
Map-Reduce Framework
Map input records=29511
Map output records=147555
Map output bytes=2507111
Map output materialized bytes=735323
Input split bytes=141
Combine input records=147555
Combine output records=49365
Reduce input groups=49365
Reduce shuffle bytes=735323
Reduce input records=49365
Reduce output records=49365
Spilled Records=98730
Shuffled Maps =1
Failed Shuffles=0
Merged Map outputs=1
GC time elapsed (ms)=428
CPU time spent (ms)=6050
Physical memory (bytes) snapshot=1152999424
Virtual memory (bytes) snapshot=5476859904
Total committed heap usage (bytes)=942669824
Peak Map Physical memory (bytes)=575365120
Peak Map Virtual memory (bytes)=2736181248
Peak Reduce Physical memory (bytes)=577634304
Peak Reduce Virtual memory (bytes)=2740678656
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=1916891
File Output Format Counters
Bytes Written=543121
Acima consta os detalhes referentes ao processamento.
Vamos conferir lá na saída:
$ hadoop fs -ls /user/cloudera/wordcount/output
Found 2 items
-rw-r--r-- 1 hdfs supergroup 0 2018-09-30 21:08 /user/cloudera/wordcount/output/_SUCCESS
-rw-r--r-- 1 hdfs supergroup 539638 2018-09-30 21:08 /user/cloudera/wordcount/output/part-r-00000
Encontramos o arquivo: “part-r-00000“, diferente de 0 bits em seu conteúdo:
$ hadoop fs -cat /user/cloudera/wordcount/output/part-r-00000
E lá no final do arquivo de saída, os últimos dez registros, será exibido o seguinte resultado:
Quantidade 1
Tesouro_IGPM+_com_Juros_Semestrais 2230
Tesouro_IPCA+ 4539
Tesouro_IPCA+_com_Juros_Semestrais 7355
Tesouro_Prefixado 6529
Tesouro_Prefixado_com_Juros_Semestrais 5513
Tesouro_Selic 3344
Tipo_Titulo 1
Valor 1
Vencimento_do_Titulo 1
Na camada de atuação DevOps para desenvolvermos, o pipeline com os outros desenvolvedores do time. É importante conhecer o processo de build e como executar. É o ponto de partida para automação do fluxo de integração contínua e entrega contínua.
Processos sempre poderão ser melhorados, caso tenha uma sugestão ou queira conversar, entre em contato!
Fonte:
- https://github.com/emirandacombr/fundamentos-big-data
- https://www.cloudera.com/documentation/enterprise/5-13-x/topics/quickstart_vm_administrative_information.html
Parabéns a você que chegou até aqui!