Haddop, MapReduce e Spark Fabrício Olivetti de França Universidade Federal do ABC
Tópicos 1. Conceitos Básicos 2. MapReduce 3. Spark 4. Transformações Básicas 5. Ações Básicas 1
Conceitos Básicos
Hadoop Como vimos na aula inicial, muitas bases de dados de interesse prático necessitam de mais espaço do que os maiores HDs podem suportar. Uma solução inicial é dividir os dados em vários HDs. 2
Hadoop Exemplo: log de requisições http em um servidor de páginas de internet. Dado um computador central que fará o gerenciamento das requisições e HDs externos conectados por rede. Operacionalização: um HD é escolhido para armazenar o log atual. Ao atingir 98% da capacidade, outro HD é escolhido. 3
Hadoop Quantos problemas vocês conseguem enumerar? 4
Hadoop Quantos problemas vocês conseguem enumerar? Se um HD falha, perdemos aqueles dados para sempre. 4
Hadoop Quantos problemas vocês conseguem enumerar? Se um HD falha, perdemos aqueles dados para sempre. Se um HD falha, perdemos as amostras de todo um período, criando um viés estatístico. 4
Hadoop Quantos problemas vocês conseguem enumerar? Se um HD falha, perdemos aqueles dados para sempre. Se um HD falha, perdemos as amostras de todo um período, criando um viés estatístico. Se a comunicação com o HD atual falhar, o que fazer? 4
Hadoop Quantos problemas vocês conseguem enumerar? Se um HD falha, perdemos aqueles dados para sempre. Se um HD falha, perdemos as amostras de todo um período, criando um viés estatístico. Se a comunicação com o HD atual falhar, o que fazer? Se o computador central falhar? 4
Hadoop Distributed File System Criado para tratar essas questões de confiabilidade ao mesmo tempo que minimiza custos. Suporta arquivos muito grandes e gerencia milhares de nós ao mesmo tempo. Assume a possibilidade de lidar com hardware de baixo custo. Duplicação de arquivos para lidar com falhas. Detecção de falhas para previnir possibilidade de perdas. Computação otimizada: o processamento é feito onde os dados residem. Executa em máquinas e sistemas heterogêneos. 5
Arquitetura Geral Distribuído com um pouco de centralização. Nós principais: principais máquinas com poder alto de processamento e armazenamento. Nós principais gerenciam o envio e recebimento de tarefas de processamento para os outros nós (TaskTracker). Nós principais gerenciam os locais onde os dados devem residir, dados mais utilizados estão mais próximos (DataNode). Nós centrais mantém um mapa dos arquivos e diretórios do sistema distribuído (NameNode). 6
Arquitetura Geral Nós centrais envia as tarefas para os nós principais (JobTracker). Pensado em leituras frequentes de lotes de arquivos. Escrita de arquivo é custosa, geralmente Write-Once, Read-Many. Escrito em Java com suporte a Python. 7
NameNode Armazena os metadados típicos de um sistema de arquivo. Apenas um servidor armazenando o NameNode, ele deve ser o mais importante, estável e seguro. Cuida da criação de réplicas de blocos sempre que ocorre falha em um DataNode. 8
DataNode Armazena os dados de arquivos. Suporta qualquer sistema de arquivo (FAT, NTFS, ext, etc.). Notifica o NameNode sobre os blocks que ele possui (ao substituir um NameNode ele requisita tal informação). Arquivos são armazenados em blocos de 64MB por padrão. Envia um relatório periódico ao NameNode. Envio de dados inteligente, tem preferência pelo envio aos DataNodes mais próximos. 9
Estratégias de Armazenamento O NameNode réplica cada bloco de arquivo 2 vezes em um rack local e uma vez em outro rack. Réplicas adicionais podem ser distribuídos aleatoriamente para outros nós. Ao requisitar um certo bloco, esse é recuperado do nó mais próximo ao cliente. Em caso de falha (falta de relatório periódico), o NameNode escolhe outros DataNodes para replicar. Otimiza o balanceamento do armazenamento e comunicação de rede. 10
Estratégias de Corretude Usa CRC32 para validar os dados. Calcula checksum para cada 512 bytes de dados, DataNode armazena o crc. Cliente recebe os dados e seus respectivos checksums. Em caso de falha de verificação, cliente reporta e recebe de outra réplica. 11
Comandos básicos hadoop dfs -mkdir /diretorio hadoop dfs -cat /diretorio/arquivo.txt hadoop dfs -rm /diretorio/arquivo.txt Conta com interface Web: http://host:port/dfshealth.jsp 12
Exercício Supondo um cluster com 4 racks e 100 nós por rack, supondo também a probabilidade de falha de um nó é de 1%. Calcule a probabilidade de perda irreparável de um bloco de dados nas configurações padrões. 13
Exercício Supondo um cluster com 4 racks e 100 nós por rack, supondo também a probabilidade de falha de um nó é de 1%. Calcule a probabilidade de perda irreparável de um bloco de dados nas configurações padrões. P(n i = falha ) = 0.01 ( ) 400 P(n nós falharam ) = 0.01 n 0.99 n n ( n 3) P(perda de dados nnósfalharam) = ( 400 3 400 ( 400 P(perda de dados) = n n=3 ) ) 0.01 n 0.99 n ( n 3) ( 400 ) 3 13
MapReduce
Modelo MapReduce Modelo de programação distribuída. Dean, Jeffrey, and Sanjay Ghemawat. MapReduce: simplified data processing on large clusters. Communications of the ACM 51.1 (2008): 107-113. Ideias: Unix pipeline e básico de Programação Funcional: Trabalha com stream de dados. 14
Modelo MapReduce Modelo de programação distribuída. Dean, Jeffrey, and Sanjay Ghemawat. MapReduce: simplified data processing on large clusters. Communications of the ACM 51.1 (2008): 107-113. Ideias: Unix pipeline e básico de Programação Funcional: cat input grep sort uniq -c cat > output input > map > shuffle & sort > reduce > output Trabalha com stream de dados. 14
MapReduce Figura 1: Fonte: UT Dallas. 15
Modelo MapReduce Balanceamento de carga otimizado. Recuperação rápida de falhas. Possibilidade de reprocessar em caso de falhas. Processamento duplicado em caso de lentidão. Otimizações locais. 16
Word Count Mapper Entrada: linhas de texto Saída: chave = palavra, valor = 1 Reducer Entrada: chave = palavra, valor = lista de contagens Saída: chave = palavra, valor = soma 17
MapReduce Figura 2: Fonte: UT Dallas. 18
MapReduce mapper :: Token -> (Token, Integer) reducer :: [(Token, [Integer])] -> [(Token, Integer)] mapper token = (token, 1) reducer xs = map (\ (k,vs) -> (k, sum vs)) xs 19
Combiners Uma forma de minimizar a carga dos Reducers, gerando uma avaliação parcial em cada nó. É executado localmente, geralmente é igual ao próprio reducer. 20
Modelo MapReduce Funciona bem para programas pequenos e manipulações simples dos dados. Aplicações de larga escala são difíceis de serem implementadas. Problema de performance. 21
Exercício No exemplo de contagem de palavras, o que deve ser feito entre o mapper e o reducer feito em Haskell para que ele funcione? 22
Exercício No exemplo de contagem de palavras, o que deve ser feito entre o mapper e o reducer feito em Haskell para que ele funcione? DICA Considere a saída do mapper e a entrada do reducer: mapper :: Token -> (Token, Integer) reducer :: [(Token, [Integer])] -> [(Token, Integer)] 22
Spark
Spark: Além do MapReduce De tal forma a facilitar o desenvolvimento de aplicações e generalização de tarefas comuns no MapReduce, foi criada a plataforma Spark. Mais eficiente: computação distribuída + multithreading. Linguagem estendida. Compartilhamento de Dados mais rápido. Árvore de processamento. Suporte a Scala, Java, Python, R. 23
Resilient Distributed Dataset: RDD Abstração principal do Spark: A base de dados é um objeto. Aplica operações nesses objetos, como métodos Pode estar armazenado em Hadoop, sistema de arquivo comum ou até na memória (transparente). Transformações (paralelas) e Ações (saída de dados). Refaz operações em caso de falhas. 24
Operações em uma RDD Transformações f :: RDD -> RDD: Avaliação Preguiçosa. Ex.: map, reduce, filter. RDDs podem ser de listas de valores ou lista de tuplas chave-valor [(K, V)]. Ações f :: RDD -> a: Gera computação. Ex.: count, saveastextfile, collect. 25
Directed Acyclic Graph: DAG No MapReduce do Hadoop, cada operação Map-Reduce é independente uma da outra, mesmo quando as tarefas estão interligadas. Considere o problema de retornar a contagem de palavras ordenadas pela frequência: mapper1 :: Linha -> [(Palavra, Integer)] reducer1 :: [(Palavra, [Integer])] -> [(Palavra, Integer)] mapper2 :: (Palavra, Integer) -> [(Integer, Palavra)] reducer2 :: [(Integer, [Palavra])] -> [(Integer, [Palavra])] Qual a definição das funções mapper2 e reducer2? 26
Directed Acyclic Graph: DAG Primeiro, o Hadoop irá completar TODA a tarefa MapReduce1. Somente após a conclusão e escrita do arquivo de saída (escrita custa caro!), a tarefa MapReduce2 iniciará, para então gerar a resposta. 27
Directed Acyclic Graph: DAG No Spark, é feito um grafo direcionado e acíclico (árvore) de processamento que interliga as tarefas de MapReduce (ou outras transformações) para gerar o menor número de escritas possíveis. 28
Directed Acyclic Graph: DAG Uma vez que a RDD é imutável e as transformações devem ser puras, é possível fazer a composição dessas funções sem introduzir efeitos inesperados. 29
Transformações Básicas
Criando uma RDD Uma RDD pode ser criada a partir de uma coleção em memória ou um arquivo existente no sistema de arquivos (distribuídos ou não) 1. listacomidas = [ bife, alface, arroz ] comidasrdd = sc.parallelize(listacomidas, 2) textordd = sc.textfile(nomearquivo, 2) O segundo parâmetro é a quantidade de partições por nó local. O ideal é criar cerca de 2 partições por core (Porque?) 1 os comandos seguem a sintaxe Pyspark 30
MapReduce Similar ao map e fold do Haskell: # [Linha] -> [Int] -> [Int] -> Int textordd.map(lambda linha: length(linha)).reduce(lambda (l1, l2): l1 + l2) Nota: reduce é uma ação, e portanto força o processamento. 31
reducebykey Parecido com o procedimento que fizemos até então no Haskell: aplica uma função no resultado de groupbykey. sortbykey: # [Linha] -> [(Palavra, Int)] -> [(Palavra,[Int])] # -> [(Palavra, Int)] textordd.map(lambda linha: [(w,1) for w in linha.split()]).reducebykey(lambda f1,f2: f1+f2) 32
groupbykey Retorna o resultado de groupbykey. sortbykey após um map: # [Linha] -> [(Palavra, Int)] -> [(Palavra,[Int])] textordd.map(lambda linha: [(w,1) for w in linha.split()]).groupbykey() 33
filter Similar ao Haskell, remove da RDD todos os elementos que retorna falso para a função passada como parâmetro: # [Linha] -> [(Palavra, Int)] -> [(Palavra,[Int])] textordd.map(lambda linha: [(w,1) for w in linha.split()]).reducebykey(lambda f1,f2: f1+f2).filter(lambda (w, f): f > 3) 34
join Une a RDD de tuplas com outra RDD de tuplas dado que as chaves são do mesmo tipo: # [(Palavra, Int)] -> [(Palavra, Int)] # -> [(Palavra, (Int, Int))] freqpalavrardd.join(idfpalavrardd) 35
cartesian Une duas RDDs através de um produto cartesiano de seus elementos: # [(Palavra, Int)] -> [(Palavra, Int)] # -> [(Palavra, Int), (Palavra, Int)] freqpalavrardd.cartesian(freqpalavrardd) 36
Pipelines de processamento Conforme mencionado anteriormente, o retorno das transformações do Spark são intenções de computação, a sequência de transformações formam um pipeline de processamento a ser computado quando necessário. pipeline1 = RDD.transforma1().transforma2().transforma3() pipeline2 = pipeline1.transforma1().transforma2() pipeline3 = pipeline1.transforma1(pipeline2).transforma2() Dessa forma, o Spark consegue otimizar o processamento e evitar redundâncias. 37
Ações Básicas
Ações Básicas.collect(): retorna a RDD em memória..first(): retorna o primeiro elemento da RDD..take(n): retorna os n primeiros elementos da RDD. 38
Atividade 02 Complete o Laboratório Pré-processamento no Spark 39