DevSecOps

25 out, 2018

DevOps – HDFS (Hadoop Distributed File System): primeiros passos

Publicidade

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:

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

 

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:

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:

Parabéns a você que chegou até aqui!