Spark é um ambiente de computação em cluster de software livre parecido com o Hadoop, mas com algumas diferenças úteis que o tornam superior em determinadas cargas de trabalho—a saber, o Spark habilita conjuntos de dados distribuídos na memória que otimizam as cargas de trabalho iterativas, além de consultas interativas.
O Spark é implementado na linguagem Scala e usa Scala como sua estrutura de aplicativos. Ao contrário do Hadoop, o Spark e a Scala criam uma integração sólida, na qual a Scala pode manipular com facilidade os conjuntos de dados distribuídos como objetos localmente coletivos.
Embora o Spark tenha sido criado para suportar tarefas iterativas em conjuntos de dados distribuídos, na verdade ele é complementar ao Hadoop e pode ser executado lado a lado no sistema de arquivos do Hadoop. Esse comportamento é suportado por uma estrutura de cluster de terceiros chamada Mesos. O Spark foi desenvolvido na University of California, Berkeley, Algorithms, Machines, and People Lab a fim de construir aplicativos de analítica de dados de larga escala e baixa latência.
Arquitetura de computação em cluster do Spark
Embora o Spark tenha semelhanças com o Hadoop, ele representa uma nova estrutura de computação em cluster com diferenças úteis. Primeira, o Spark foi projetado para um tipo específico de carga de trabalho na computação em cluster —a saber, aquelas que reutilizam um conjunto de dados de trabalho em operações paralelas (como algoritmos de aprendizagem de máquinas). Para otimizar esses tipos de cargas de trabalho, o Spark apresenta o conceito de computação em cluster na memória, onde os conjuntos de dados podem ser armazenados em cache na memória a fim de reduzir sua latência de acesso.
O Spark também apresenta uma abstração chamada resilient distributed datasets (RDDs). Uma RDD é uma coleção somente leitura de objetos distribuídos em um conjunto de nós. Essas coleções são resilientes, pois podem ser recriadas se uma parte do conjunto de dados for perdida. O processo de recriação de uma parte do conjunto de dados depende de um mecanismo de tolerância a falhas que mantém a linhagem (ou informações que permitem que a parte do conjunto de dados seja recriada com base no processo a partir do qual os dados foram gerados). Uma RDD é representada como um objeto de Scala e pode ser criada a partir de um arquivo; como uma fatia em paralelo (espalhada em nós); como uma transformação de outra RDD; e finalmente por meio da alteração da persistência de uma RDD existente, como solicitando o armazenamento em cache na memória.
Os aplicativos em Spark são chamados de drivers esses drivers implementam as operações realizadas em um único nó ou paralelamente em um conjunto de nós. Como o Hadoop, o Spark suporta um cluster de nó único ou um cluster com diversos nós. Para a operação de diversos nós, o Spark depende do gerenciador de cluster Mesos. O Mesos fornece uma plataforma eficiente para compartilhamento e isolamento de recursos para aplicativos distribuídos (consulte a Figura 1). Essa configuração permite que o Spark coexista com o Hadoop em um pool de nós compartilhado único.
Figura 1. O Spark depende do gerenciador de cluster Mesos para compartilhamento e isolamento de recursos.
Modelo de programação do Spark
Um driver pode realizar dois tipos de operações em um conjunto de dados: uma ação e uma transformação. Uma ação executa uma computação em um conjunto de dados e retorna um valor para o driver; uma transformação cria um novo conjunto de dados a partir de um conjunto de dados existente. Entre os exemplos de ação estão a realização de uma operação de Redução (usando uma função) e iteração de um conjunto de dados (executando uma função em cada elemento, parecido com a operação Mapear). Entre os exemplos de transformações estão a operação Mapear e a operação Cache (que solicita o armazenamento do novo conjunto de dados na memória).
Vamos analisar exemplos dessas duas operações em breve, mas primeiro, vamos conhecer a linguagem Scala.
Scala talvez seja um dos segredos mais bem guardados da Internet. É possível encontrar Scala em produção em alguns dos websites mais visitados da Internet, incluindo o Twitter, o LinkedIn e o Foursquare (com sua estrutura de aplicativo da Web, chamada Lift). Também há evidências para sugerir que as instituições financeiras se interessaram pelo desempenho da Scala (como o uso feito pela EDF Trading para precificação derivativa).
Scala é uma linguagem com diversos paradigmas, pois suporta recursos de linguagem associados a linguagens imperativas, funcionais e orientadas ao objeto de uma maneira tranquila e confortável. A partir da perspectiva de orientação do objeto, cada valor na Scala é um objeto. De forma parecida, a partir da perspectiva funcional, cada função é um valor. A Scala também é digitada de forma estática com um sistema de digitação expressivo e seguro.
Além disso, a Scala é uma linguagem de máquina virtual (VM) e é executada diretamente no Java™ Virtual Machine (JVM) usando o Java Runtime Environment versão 2 por meio de códigos de byte gerados pelo compilador da Scala. Essa configuração permite que a Scala execute praticamente em qualquer lugar no qual o JVM é executado (com o requisito de uma biblioteca de tempo de execução de Scala adicional). Também permite que a Scala explore o vasto catálogo de bibliotecas Java existentes, junto com seu código Java existente.
Finalmente, Scala é extensível. A linguagem (que significa Linguagem escalável) foi definida para extensões simples integradas tranquilamente à linguagem.
Vamos analisar alguns exemplos da linguagem Scala em ação. A Scala vem acompanhada de seu próprio intérprete, permitindo que você experimente com a linguagem de uma maneira interativa. Um tratamento útil da Scala está além do escopo deste artigo, mas é possível encontrar links para mais informações em Recursos.
A Listagem 1 começa nosso tour rápido da linguagem Scala
por meio de seu intérprete. Depois de iniciar a Scala, você recebe seu
prompt, por meio do qual é possível avaliar de forma interativa as expressões e
programas. Comece criando duas variáveis—uma
imutável (vals, chamada designação única ) e outra mutável
(vars). Observe que quando você tenta mudar
b (seu var), obtém o êxito, mas um erro retorna quando você tenta mudar para seu
val.
Listagem 1. Variáveis simples na Scala
$ scala
Welcome to Scala version 2.8.1.final (OpenJDK Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = 1
a: Int = 1
scala> var b = 2
b: Int = 2
scala> b = b + a
b: Int = 3
scala> a = 2
<console>6: error: reassignment to val
a = 2
^
|
Em seguida, crie um método simples que calcula e retorna o quadrado de um
Int. A definição de um método na Scala começa com
def, seguido pelo nome do método e uma lista dos
parâmetros; em seguida, você a define para o número de instruções (neste exemplo,
um). Nenhum valor de retorno é especificado, pois ele poder ser inferido a partir do próprio método.
Observe como isso é parecido com a atribuição de um valor para uma variável. Eu
demonstro esse processo em um objeto chamado 3
e uma variável de resultado chamada res0 (que o intérprete da
Scala cria automaticamente para você). Tudo isso está exibido na Listagem 2.
Listagem 2. Um método simples em Scala
scala> def square(x: Int) = x*x square: (x: Int)Int scala> square(3) res0: Int = 9 scala> square(res0) res1: Int = 81 |
Em seguida, vamos analisar a criação de uma classe simples em Scala (consulte a Listagem 3). Você define uma classe
Dog simples que aceita um argumento
String (seu construtor de nome). Observe
aqui que a classe usa o parâmetro diretamente (sem definição do
parâmetro de classe no corpo da classe). Há um único método que
emite uma cadeia de caractere quando chamado. Você cria uma nova instância de sua classe e
invoca seu método. Observe que o intérprete insere as barras verticais:
elas não fazem parte do código.
Listagem 3. Uma classe simples em Scala
scala> class Dog( name: String ) {
| def bark() = println(name + " barked")
| }
defined class Dog
scala> val stubby = new Dog("Stubby")
stubby: Dog = Dog@1dd5a3d
scala> stubby.bark
Stubby barked
scala>
|
Depois de terminar, basta digitar :quit para sair do interpretador da
Scala.
A primeira etapa é fazer o download e configurar a Scala. Os comandos exibidos na Listagem 4 ilustram como fazer o download e preparar a instalação da Scala. Use a versão 2.8 da Scala, pois é ela que o Spark precisa, de acordo com a documentação.
Listagem 4. Instalando a Scala
$ wget http://www.scala-lang.org/downloads/distrib/files/scala-2.8.1.final.tgz $ sudo tar xvfz scala-2.8.1.final.tgz --directory /opt/ |
Para tornar a Scala visível, adicione as seguintes linhas ao seu .bashrc (se você estiver usando Bash como seu shell):
export SCALA_HOME=/opt/scala-2.8.1.final export PATH=$SCALA_HOME/bin:$PATH |
Em seguida, é possível testar sua instalação, conforme ilustrado na Listagem 5. Esse conjunto de comandos carrega as alterações no arquivo bashrc e realiza um teste rápido do shell do interpretador da Scala.
Listagem 5. Configurando e executando a Scala interativa
$ scala
Welcome to Scala version 2.8.1.final (OpenJDK Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> println("Scala is installed!")
Scala is installed!
scala> :quit
$
|
Conforme é exibido, você deve ver um prompt da Scala. É possível sair digitando
:quit. Observe que a Scala executa no contexto
do JVM, portanto isso também será necessário. Estou usando Ubuntu, que
vem com o OpenJDK por padrão.
Em seguida, obtenha a cópia mais recente da estrutura Spark. Para fazer isso, use o script exibido na Listagem 6.
Listagem 6. Fazendo o download e instalando a estrutura do Spark
wget https://github.com/mesos/spark/tarball/0.3-scala-2.8/ mesos-spark-0.3-scala-2.8-0-gc86af80.tar.gz $ sudo tar xvfz mesos-spark-0.3-scala-2.8-0-gc86af80.tar.gz |
Em seguida, defina a configuração do spark em ./conf/spar-env.sh com a seguinte linha para o diretório inicial da Scala:
export SCALA_HOME=/opt/scala-2.8.1.final |
A etapa final na configuração é a atualização de sua distribuição usando a ferramenta de criação simples (sbt).
sbt é uma ferramenta de criação para Scala e é usada
com a distribuição do Spark. Você realiza a etapa de atualização e compilação no
subdiretório mesos-spark-c86af80 como:
$ sbt/sbt update compile |
Observe que será necessário estar conectado à Internet ao executar essa etapa. Ao concluir, execute um teste rápido do Spark, como mostra a Listagem 7. Nesse teste, você solicita a execução do exemplo SparkPi, que calcula uma estimativa de pi (por meio de uma amostragem de ponto aleatória no quadrado da unidade). O formato exibido solicita o programa exemplo (spark.examples.SparkPi) e o parâmetro host, o que define o Mesos principal (nesse caso, seu host local, pois é um cluster de nó único) e o número de threads a ser usado. Perceba que na Listagem 7, duas tarefas foram executadas, mas são serializadas (a tarefa 0 começa e termina antes de a tarefa 1 começar).
Listagem 7. Executando um teste rápido do Spark
$ ./run spark.examples.SparkPi local[1] 11/08/26 19:52:33 INFO spark.CacheTrackerActor: Registered actor on port 50501 11/08/26 19:52:33 INFO spark.MapOutputTrackerActor: Registered actor on port 50501 11/08/26 19:52:33 INFO spark.SparkContext: Starting job... 11/08/26 19:52:33 INFO spark.CacheTracker: Registering RDD ID 0 with cache 11/08/26 19:52:33 INFO spark.CacheTrackerActor: Registering RDD 0 with 2 partitions 11/08/26 19:52:33 INFO spark.CacheTrackerActor: Asked for current cache locations 11/08/26 19:52:33 INFO spark.LocalScheduler: Final stage: Stage 0 11/08/26 19:52:33 INFO spark.LocalScheduler: Parents of final stage: List() 11/08/26 19:52:33 INFO spark.LocalScheduler: Missing parents: List() 11/08/26 19:52:33 INFO spark.LocalScheduler: Submitting Stage 0, which has no missing ... 11/08/26 19:52:33 INFO spark.LocalScheduler: Running task 0 11/08/26 19:52:33 INFO spark.LocalScheduler: Size of task 0 is 1385 bytes 11/08/26 19:52:33 INFO spark.LocalScheduler: Finished task 0 11/08/26 19:52:33 INFO spark.LocalScheduler: Running task 1 11/08/26 19:52:33 INFO spark.LocalScheduler: Completed ResultTask(0, 0) 11/08/26 19:52:33 INFO spark.LocalScheduler: Size of task 1 is 1385 bytes 11/08/26 19:52:33 INFO spark.LocalScheduler: Finished task 1 11/08/26 19:52:33 INFO spark.LocalScheduler: Completed ResultTask(0, 1) 11/08/26 19:52:33 INFO spark.SparkContext: Job finished in 0.145892763 s Pi is roughly 3.14952 $ |
Aumentando o número de encadeamentos, é possível não apenas aumentar a paralelização da execução de encadeamento, mas também executar a tarefa em menos tempo (como mostra a Listagem 8).
Listagem 8. Outro teste rápido do Spark com dois encadeamentos
$ ./run spark.examples.SparkPi local[2] 11/08/26 20:04:30 INFO spark.MapOutputTrackerActor: Registered actor on port 50501 11/08/26 20:04:30 INFO spark.CacheTrackerActor: Registered actor on port 50501 11/08/26 20:04:30 INFO spark.SparkContext: Starting job... 11/08/26 20:04:30 INFO spark.CacheTracker: Registering RDD ID 0 with cache 11/08/26 20:04:30 INFO spark.CacheTrackerActor: Registering RDD 0 with 2 partitions 11/08/26 20:04:30 INFO spark.CacheTrackerActor: Asked for current cache locations 11/08/26 20:04:30 INFO spark.LocalScheduler: Final stage: Stage 0 11/08/26 20:04:30 INFO spark.LocalScheduler: Parents of final stage: List() 11/08/26 20:04:30 INFO spark.LocalScheduler: Missing parents: List() 11/08/26 20:04:30 INFO spark.LocalScheduler: Submitting Stage 0, which has no missing ... 11/08/26 20:04:30 INFO spark.LocalScheduler: Running task 0 11/08/26 20:04:30 INFO spark.LocalScheduler: Running task 1 11/08/26 20:04:30 INFO spark.LocalScheduler: Size of task 1 is 1385 bytes 11/08/26 20:04:30 INFO spark.LocalScheduler: Size of task 0 is 1385 bytes 11/08/26 20:04:30 INFO spark.LocalScheduler: Finished task 0 11/08/26 20:04:30 INFO spark.LocalScheduler: Finished task 1 11/08/26 20:04:30 INFO spark.LocalScheduler: Completed ResultTask(0, 1) 11/08/26 20:04:30 INFO spark.LocalScheduler: Completed ResultTask(0, 0) 11/08/26 20:04:30 INFO spark.SparkContext: Job finished in 0.101287331 s Pi is roughly 3.14052 $ |
Construindo um aplicativo simples do Spark com a Scala
Para construir um aplicativo Spark, são necessários que o Spark e as suas dependências estejam em um
único arquivo Java archive (JAR). Crie esse JAR no diretório de nível superior do Spark
com sbt como:
$ sbt/sbt assembly |
O resultado é o arquivo ./core/target/scala_2.8.1/"Spark Core-assembly-0.3.jar"). Adicione esse arquivo ao seu caminho de classe de modo que fique acessível. Neste exemplo, você não usará esse JAR, pois o executará com o interpretador da Scala em vez de compilá-lo.
Para este exemplo, use a transformação padrão de MapReduce (exibida na Listagem 9). O exemplo começa com as importações necessárias para as classes Spark. Em seguida, defina sua classe
(SparkTest), com seu método principal, o que analisa
os argumentos para uso posterior. Esses argumentos definem o ambiente a partir do qual
o Spark será executado (nesse caso, um cluster de nó único). Em seguida,
crie seu objeto SparkContext , que informa ao
Spark como acessar seu cluster. Esse objeto exige dois parâmetros: o
nome do Mesos principal (passado) e o nome atribuído à tarefa
(SparkTest). Analise o número de fatias da
linha de comando, que informa ao Spark quantos encadeamentos devem ser usados para a tarefa.
O último item restante para configuração é a especificação do arquivo de texto a ser usado para
a operação MapReduce.
Finalmente, você chega ao principal do exemplo sobre o Spark, formado por um
conjunto de transformações. Com seu arquivo, invoque o método
flatMap para retornar uma RDD (por meio da
função especificada para dividir a linha de texto em tokens). Em seguida, essa RDD é
passada por meio do método map (que cria
os pares de chave-valor) e finalmente por meio do método
ReduceByKey , que agrega seus
pares de chave-valor. Isso é realizado passando os pares de chave-valor à função anônima
_ + _ . Essa função simplesmente
usa dois parâmetros (a chave e o valor) e retorna o resultado
anexando-os juntos (um String e uma Int). Esse valor é emitido como um arquivo de texto
(para o diretório de saída).
Listagem 9. MapReduce em Scala/Spark (SparkTest.scala)
import spark.SparkContext
import SparkContext._
object SparkTest {
def main( args: Array[String]) {
if (args.length == 0) {
System.err.println("Usage: SparkTest <host> [<slices>]")
System.exit(1)
}
val spark = new SparkContext(args(0), "SparkTest")
val slices = if (args.length > 1) args(1).toInt else 2
val myFile = spark.textFile("test.txt")
val counts = myFile.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
counts.saveAsTextFile("out.txt")
}
}
SparkTest.main(args)
|
Para executar seu script, basta solicitar a execução com:
$ scala SparkTest.scala local[1] |
É possível encontrar o arquivo de teste MapReduce no diretório de saída (como output/part-00000).
Outras estruturas grandes de analítica de dados
Desde que o Hadoop foi desenvolvido, diversos plataformas grandes de analítica de dados foram lançadas e que vale a pena dar uma olhada. Essas plataformas variam de simples ofertas com base em script até ambientes de produção parecidos com o Hadoop.
Uma das mais simples é chamada bashreduce, que, como o
nome sugere, permite a execução de operações do tipo MapReduce
em várias máquinas no ambiente Bash.
bashreduce depende do Secure Shell
(sem senha) para o cluster de máquinas que você planeja usar e depois existe
como um script por meio do qual você solicita tarefas via ferramentas ao estilo
UNIX® (sort,
awk, netcat e afins).
GraphLab é outra implementação interessante da abstração MapReduce que se concentra na implementação paralela de algoritmos de aprendizagem de máquina. No GraphLab, o estágio Map define as computações que podem ser realizadas independentemente e de forma isolada (em hosts separados) e o estágio Reduce combina os resultados.
Finalmente, um recém-chegado à cena de big data é o Storm do Twitter (por meio da aquisição da BackType). Storm é definido como o "Hadoop do processamento em tempo real" e se concentra no processamento do fluxo e na computação contínua (o fluxo resulta à medida que é computado). Storm é escrito em Clojure (um dialeto moderno da linguagem Lisp), mas suporta aplicativos escritos em qualquer linguagem (como Ruby e Python). O Twitter lançou o Storm como software livre em setembro de 2011.
Consulte Recursos para obter mais informações.
Spark é um acréscimo interessante à família crescente de soluções de análise de big data. Ele fornece não apenas uma estrutura eficiente para o processamento de conjuntos de dados distribuídos, mas o faz de uma maneira eficiente (por meio de scripts de Scala simples e claros). Spark e Scala estão sob desenvolvimento ativo. No entanto, com sua adoção em propriedades importantes da Internet, parece que ambos passaram de um software livre interessante para tecnologias fundamentais da Web.
Aprender
- EDF Trading: Implementing a domain-specific language for derivative
pricing with Scala: Scala foi adotada em vários segmentos de mercado,
incluindo comércio de ações. Saiba sobre um exemplo assistindo a esse vídeo.
-
Virtualização de aplicativos, passado e futuro (M. Tim Jones,
developerWorks, maio de 2011) apresenta uma introdução às linguagens de máquina virtual
e suas implementações.
- Ceylon: Avanço de verdade ou apenas outra linguagem? (M. Tim Jones,
developerWorks julho de 2011) explora outra linguagem de VM interessante (trabalho em andamento)
que depende do JVM.
-
First Steps
to Scala é uma ótima introdução à linguagem Scala (escrita parcialmente
por Martin Odersky, o designer da Scala). Essa extensa introdução
de 2007 cobre muitos aspectos da linguagem. Outro exemplo útil é
Code Examples for Programming in Scala, que fornece receitas em Scala
para vários padrões de código.
-
Distributed computing with Linux and Hadoop (Ken Mann e M. Tim
Jones, developerWorks, dezembro de 2008) fornece uma introdução à
arquitetura do Hadoop, incluindo as noções básicas do paradigma MapReduce para
processamento distribuído de dados em massa.
-
Distributed data processing with Hadoop (M. Tim Jones,
developerWorks 2010): encontre uma introdução prática ao Hadoop, incluindo
como configurar e usar um cluster de Hadoop de nó único, como configurar e usar
um cluster com vários nós e como desenvolver aplicativos map e reduce no ambiente do
Hadoop.
- developerWorks no Twitter: siga-nos para acompanhar as últimas notícias.Também é possível seguir este autor
no Twitter em M. Tim
Jones.
- Zona de software livre do developerWorks: você encontra muitas informações sobre instruções, ferramentas e atualizações de projetos para ajudá-lo a desenvolver com tecnologias de software livre e usá-las com produtos da IBM.
- Eventos interessantes: confira futuras conferências, exposições e webcasts interessantes para desenvolvedores de software livre IBM.
- Podcasts do developerWorks: escute entrevistas e explicações interessantes para desenvolvedores de software
- demos gratuitas on demand do developerWorks: Acompanhe nossas demos gratuitas e saiba mais sobre as tecnologias IBM e de software livre e funções dos produtos.
Obter produtos e tecnologias
-
Spark apresenta uma solução de análise
de dados na memória, escrita e suportada pela linguagem Scala.
-
A ferramenta simples de criação é a
solução de criação adotada pela linguagem Scala. Ela oferece um método simples
para pequenos projetos, além de recursos avançados para construções complexas.
-
Lift é a estrutura de aplicativo da web para Scala, parecida com a estrutura Rails
para Ruby. Veja o Lift em ação no Twitter e no Foursquare.
- Projeto Mesos: o Spark não suporta
a distribuição de cargas de trabalho nativamente, mas, em vez disso, depende deste
gerenciador de cluster que fornece isolamento de recursos e compartilhamento em uma
rede para aplicativos distribuídos.
bashreduce(Uma implementação com base no script Bash), GraphLab (focado na aprendizagem da máquina) e Storm (adquirido pelo Twitter com a BackType, um sistema de processamento de fluxo distribuído em tempo real escrito em Clojure): o Hadoop deu início a diversas plataformas de análise de big data. Além do Spark, é possível implementar arquiteturas de computação em paralelo com essas três ofertas.- Avalie os produtos IBM da maneira que for melhor para você: faça download da versão de teste de um produto, avalie um produto on-line, use-o em um ambiente de nuvem ou passe algumas horas na SOA Sandbox aprendendo a implementar Arquitetura Orientada a Serviços de modo eficiente. Temos versões de avaliação de diversos produtos de gerenciamento de
informações. Como você está interessado em analítica de dados, talvez queira
ver IBM
SPSS Text Analytics for Surveys, IBM
Cognos Business Intelligence e Cognos Express.
Discutir
- comunidade do developerWorks: Conecte-se a outros usuários do developerWorks enquanto explora os blogs, fóruns, grupos e wikis voltados para desenvolvedores. Ajude a desenvolver o software livre do mundo real na comunidade do developerWorks.

M. Tim Jones é arquiteto de firmware integrado e autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (agora em sua segunda edição), AI Application Programming (em sua segunda edição) e BSD Sockets Programming from a Multilanguage Perspective. Seu conhecimento em engenharia varia do desenvolvimento de kernels para naves espaciais geossíncronas até a arquitetura de sistemas embarcados e o desenvolvimento de protocolos de rede. Tim é arquiteto de plataforma da Intel e autor em Longmont, Colorado.