APACHE SPARK
O QUE É APACHE SPARK?
Apache Spark é um mecanismo de computação unificado e um conjunto de bibliotecas de
processamento de dados em paralelo em clusters de computadores.
Apache Spark suporta processamento de dados em lote (batch) e em fluxo contínuo (streaming).
2
POR QUE APACHE SPARK?
Atualmente existem diversas plataformas para processamento de dados em larga escala, mas o
Apache Spark se destaca pela sua maturidade, facilidade de uso, diversidade de aplicações e
comunidade.
3
ARQUITETURA - COMPONENTES
4
https://image.slidesharecdn.com/introductiontospark-151103082829-lva1-app6892/95/introduction-to-apache-spark-5-
638.jpg?cb=1446624588
ARQUITETURA - VISÃO GERAL
5
ARQUITETURA - VISÃO GERAL
6
MODOS DE EXECUÇÃO
O Spark possui três modos de execução distintos:
• Cluster mode
• Client mode
• Local mode
7
MODO CLUSTER
É o modo mais comum de execução e o mais recomendado para o deploy em produção.
8
MODO CLIENTE
Esse modo é similar ao modo cluster, mas o processo Driver é executado na máquina cliente
(aquela que submeteu a aplicação).
9
MODO LOCAL
Nesse modo, a aplicação Spark é executada na mesma máquina que submete a aplicação. A
paralelização se dá através do uso de threads.
Esse modo é utilizado durante o desenvolvimento e depuração de uma aplicação.
10
A APLICAÇÃO SPARK
Uma aplicação Spark é composta (logicamente) por um processo Driver e vários processos
Executors.
Geralmente o utilizamos o seguinte comando para submeter uma aplicação Spark num cluster
Yarn:
sudo spark-submit --class com.thoughtworks.core.JobsExample --master yarn --deploy-mode
cluster s3://com.thoughtworks.training.de.recife/facilitador/de-training-0.1-SNAPSHOT.jar arg1
arg2
Ou o seguinte comando quando quero utilizar a API do AWS EMR:
aws emr add-steps --cluster-id j-2AXXXXXXGAPLF --steps Type=Spark,Name="Spark
Program”,ActionOnFailure=CONTINUE,Args=[--
class,org.apache.spark.examples.SparkPi,/usr/lib/spark/lib/spark-examples.jar,arg1,arg2]
11
COMPONENTES - DRIVER
O processo Driver é responsável por manter informação sobre o estado da aplicação, responder
ao comandos do programa ou entradas do usuário (spark-shell) e analisar, distribuir e agendar o
trabalho entre os Executors.
O processo Driver contem o ponto de entrada para a API do Spark chamado de SparkSession.
12
COMPONENTES - SPARK SESSION
A Spark Session é o ponto de entrada da API do Apache Spark. É através dela que o programa
do usuário manipula os dados processados pela Aplicação Spark.
Existe uma correspondência de um-pra-um entre uma Spark Session e uma Aplicação Spark.
13
val spark: SparkSession = SparkSession.builder()
.config(conf)
.getOrCreate()
COMPONENTES - EXECUTORS
Os processos Executors rodam nos worker nodes do cluster.
Eles são responsáveis por efetivamente executar o código Spark (transformações e ações) e
retornar o resultado para o processo Driver.
O código Spark executado pelos Executors é agrupado em Tasks.
14
COMPONENTES - TRANSFORMAÇÕES
As estruturas de dados do Spark (RDDs, Dataframes e Datasets) são imutáveis. Quando
desejamos alterar essas estruturas, o fazemos através de transformações que resultam em uma
nova instância de uma dessas estrutura de dados.
15
val sourceDataFrame = spark.read.csv("/path/to/a/csv/file")
val transformedDataFrame = sourceDataFrame.filter(“country = 'Brasil'")
COMPONENTES - AÇÕES
Transformações são operações lazy. Isso significa que quando um programa Spark é executado,
as transformações não são executadas à medida que o programa "encontra" essas instruções.
Ao invés disso, as transformações são enfileiradas até que uma Ação seja executada. Existem
três tipos de Ações: Visualização de dados no console, coleta de dados em objetos nativos e
escrita de dados.
16
val sourceDataFrame = spark.read.csv("/path/to/a/csv/file")
val transformedDataFrame = sourceDataFrame.filter("pais = 'Brasil'")
val recordCount = transformedDataFrame.count() //a transformação "filter' é executada
COMPONENTES - JOBS
Para cada Ação definida no código da Aplicação Spark, um Job é criado e enviado para
execução nos Worker nodes. Um Job é dividido em Stages.
17
val users = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle"))
val usersDF = spark.sparkContext.parallelize(users).toDF
println(s"Users before filter ${usersDF.count()}")
val filteresUsersDF = usersDF.where("Company = 'Google'")
println(s"Users after filter ${filteresUsersDF.count()}")
COMPONENTES - JOBS
18
Caption
COMPONENTES - STAGES
Um Job Spark é subdividido em Stages.
Um Job Spark é executado de forma distribuída em diferentes máquinas de um cluster (worker
nodes). Dessa forma a aplicação Spark pode se beneficiar da co-localidade dos dados, ou seja,
cada worker node contem parte dos dados a serem processados e executa as transformações e
ações somente nesses nos dados que possui. Também é dessa forma que o Spark obtém
paralelismo.
Entretanto, algumas operações requerem que os worker nodes troquem dados entre si. O nome
dado à essa troca de dados é Shuffle.
Para cada Shuffle que se faz necessário, um novo Stage é adicionado ao Job.
19
COMPONENTES - STAGES
val users = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle"))
val usersDS = spark.sparkContext.parallelize(users, 1).toDS
val mappedUsersDF = usersDS.map(u => s"Name: ${u.Name} - Company: ${u.Company}")
mappedUsersDF.collect().foreach(println)
20
COMPONENTES - STAGES
21
Caption
COMPONENTES - STAGES
val users = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle"))
val usersDF = spark.sparkContext.parallelize(users, 1).toDF
val mappedUsersDF = usersDF.withColumn("Initial", substring(col("Name"), 0, 1))
val groupedUsers = mappedUsersDF.groupBy("Initial").count()
groupedUsers.collect().foreach(println)
22
COMPONENTES - STAGES
23
Caption
COMPONENTES - TASKS
Tasks são a menor unidade de execução de uma aplicação Spark.
Um Stage é composto por Tasks.
O número de Tasks em um Stage tem uma correspondência de um-pra-um com o número de
partições do bloco de dados no qual a Task está operando. Caso tenhamos uma partição,
teremos uma Task. Caso tenhamos mil partições, teremos mil Tasks.
Tasks são enviadas para execução pelos Executors.
Controlando o número de Tasks nós controlamos o paralelismo da nossa Aplicação.
24
COMPONENTES - TASKS
val users = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle"))
val usersDS = spark.sparkContext.parallelize(users, 8).toDS
val mappedUsersDF = usersDS.map(u => s"Name: ${u.Name} - Company: ${u.Company}")
mappedUsersDF.collect().foreach(println)
25
COMPONENTES - TASKS
26
Caption
COMPONENTES - TASKS
27
Caption
RDD API
RDDs são coleções de dados distribuídas e foram a primeira API disponibilizada pelo Spark.
RDDs são hoje consideradas uma API de baixo nível e raramente precisam ser utilizadas.
O ponto de entrada para a API de RDDs é o SparkContext.
28
val words = "Uma coleção de palavras".split(" ")
val wordsRDD = spark.sparkContext.parallelize(words)
val upperCaseWordsRDD = wordsRDD.map(_.toUpperCase)
STRUCTURED API
A Structured API criou abstrações em cima das RDDs. São os Dataframes, Datasets, SQL
Tables e Views. Alguns dos benefícios dessas abstrações são:
• Estrutura tabular - facilita a estruturação, visualização e consulta dos dados (SQL)
• Permite optimizações por parte da engine do Spark (Catalyst).
29
STRUCTURED API - DATAFRAME
30
usersWithCustomSchemaDF
.filter("Age > 18")
.select("Name", "Age", "Address")
STRUCTURED API - DATASET
31
usersParquetDS.map(_.Name).as[User]
.filter(_.Company == "ThoughtWorks")
CATALOG API - TABLES E VIEWS
32
spark.sql("select * from enhanced_users")
spark.catalog.listTables().collectAsList().asScala.foreach(println)
val userCompany = spark.table("Users")
.selectExpr("concat(Name, ' - ', Company)")
STRUCTURED API - AGGREGATIONS
33
val usersGrouped = enhancedUsersDF.groupBy("Company")
usersGrouped.count()
usersGrouped.max("Age", "Salary")
usersGrouped.min("Age", "Salary")
usersGrouped.mean("Age", "Salary")
usersGrouped.avg("Age", "Salary")
usersGrouped.agg(col("Company")
usersGrouped.agg(expr("substring(Company,1,1) = 'T'"))
usersGrouped.agg(Map("Age" -> "max", "Salary" -> "avg"))
STRUCTURED API - JOINS
34
val enhancedUsersDF2 = usersParquetDF.join(ageSalaryDF, Seq("Name"), "left")
BROADCAST JOINS
35
val enhancedUsersBroadcastDF = usersParquetDF
.join(broadcast(ageSalaryDF), "Name")
STRUCTURED API - COALESCE
36
val employees = spark
.read
.option("inferSchema", true)
.option("header", true)
.csv("../data/csv/northwind/employees.csv")
.coalesce(4)
//original partitions number must be greater than target
STRUCTURED API - REPARTITION
37
val employees = spark
.read
.option("inferSchema", true)
.option("header", true)
.csv("../data/csv/northwind/employees.csv")
.repartition(4)
BATCH
38
val usersCSVDF = spark.read
.option("header", true)
.option("infer_schema", true)
.option("delimiter", ";")
.csv("../data/csv/users/")
STREAMING
39
val socketStreamDF = spark
.readStream
.format("socket")
.option("host", "localhost")
.option("port", 9999)
.load()
val wordCountsDF = socketStreamDF
.withColumn("timestamp", expr("CAST(parseTimestampWithTimezone(value) / 1000 AS TIMESTAMP)"))
.withWatermark("timestamp", "10 seconds")
.groupBy(window($"timestamp", "1 minutes", "30 seconds"), $"value")
.count()
val wordCountQuery =
wordCountsDF
.writeStream
.format("parquet")
.option("checkpointLocation", "../data/output/streaming-window/checkpoint")
.option("path", "../data/output/parquet/streaming-window")
.outputMode(OutputMode.Complete())
.queryName("WordCount")
.start()
wordCountQuery.awaitTermination()
STREAMING - WINDOW OPERATIONS
40
STREAMING - WATERMARK
41
STREAMING - GLOSSÁRIO
O que é?
• Window duration: É o intervalo de tempo em que ser acumular os dados que estão sendo processados, ex.: O total de
vendas das última duas horas.
• Slide duration: A frequência com que ser quer mover (atualizar) a janela, ex.: Atualize o total de vendas da última hora
a cada 5 minutos.
• Trigger: O intervalo em que se processa um batch de eventos. Não tem relação com a janela. Ex.: a pipeline processa
os micro-batches em intervalos de 1 segundo.
42
DATA STORAGE
As soluções de armazenamento mais comuns utilizadas por aplicacões Spark
são:
• HDFS
• S3
• Cassandra
Os dados quando armazenados são replicados e distribuídos de acordo a
solução utilizada.
Nos casos do S3 e Cassandra existe o que chamamos de consistência
eventual o que pode fazer com que leituras não estejam em sincronia com as
escritas.
43
DATA STORAGE - FORMATS
Os formatos mais utilizados para armazenamento de dados em plataformas
de dados são:
• Plain Text, CSV, JSON
• Parquet - https://parquet.apache.org/
• ORC - https://orc.apache.org/
• AVRO - https://avro.apache.org/
44
DATA STORAGE - PARTITIONING
45
spark.read
.option("delimiter", ";")
.option("header", true)
.option("infer_schema", true)
.csv(ordersBucket)
.write
.partitionBy("StoreId", "Timestamp")
.parquet(ordersParquetBucket)
DATA STORAGE - PARTITIONING
46
TESTING
47
class MyJobTest
extends FunSuite
with BatchRunner
with Matchers
with BeforeAndAfter
with BeforeAndAfterAll {
before {}
after {}
override def beforeAll(): {}
override def afterAll() {}
test("something should happen") {
val arg1 = 10
val arg2 = "something"
MyJob.main(Array(arg1, arg2))
val aDF = spark.read(…)
aDF.count() should be 100
}
}
DEPLOYMENT
Atualmente existem três opções de gerenciadores de clusters que podemos
utilizar para deployarmos uma aplicação Spark.
• YARN
• MESOS
• Spark Standalone Cluster
• Kubernetes
O serviço EMR da AWS utiliza o YARN como gerenciador de cluster.
48
EXERCÍCIOS
49
EXERCÍCIOS - OTIMIZAÇÃO
50
• Quais os valores ótimos de número de executors e memória para o nosso
cluster?
• Qual o número ótimo de partições para obtermos o máximo de paralelismo
nos nossos jobs?
EXERCÍCIOS - BATCH
51
• Qual o valor total de receita líquida?
• Qual o valor total de receita líquida por loja?
• Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais (receita líquida)?
• Quais os 10 produtos que mais geram receita (receita líquida)?
• Salve os dados de vendas no formato parquet e particionados por loja em um bucket/pasta diferente.
• Salve os dados de itens no formato parquet e particionados por produto em um bucket/pasta diferente.
• Salve os dados de produtos no formato JSON em um bucket/pasta diferente.
Streaming
Qual o valor total de receita líquida nos últimos 5 minutos?
Qual o valor total de receita líquida por loja nos últimos 5 minutos?
Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais (receita líquida)?
Quais os 10 produtos que mais geram receita nos últimos 5 minutos (receita líquida)?
PS: Receita líquida = (preço item - desconto item) * quantidade item
EXERCÍCIOS - STREAMING
52
• Qual o valor total de receita líquida nos últimos 5 minutos?
• Qual o valor total de receita líquida por loja nos últimos 5 minutos?
• Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais
(receita líquida)?
• Quais os 10 produtos que mais geram receita nos últimos 5 minutos
(receita líquida)?
EXERCÍCIOS - NORTHWIND DATABASE
53
Para perguntas e sugestões:
Contate me através de:
jsilva@thoughtworks.com
OBRIGADO

Apache spark intro

  • 1.
  • 2.
    O QUE ÉAPACHE SPARK? Apache Spark é um mecanismo de computação unificado e um conjunto de bibliotecas de processamento de dados em paralelo em clusters de computadores. Apache Spark suporta processamento de dados em lote (batch) e em fluxo contínuo (streaming). 2
  • 3.
    POR QUE APACHESPARK? Atualmente existem diversas plataformas para processamento de dados em larga escala, mas o Apache Spark se destaca pela sua maturidade, facilidade de uso, diversidade de aplicações e comunidade. 3
  • 4.
  • 5.
  • 6.
  • 7.
    MODOS DE EXECUÇÃO OSpark possui três modos de execução distintos: • Cluster mode • Client mode • Local mode 7
  • 8.
    MODO CLUSTER É omodo mais comum de execução e o mais recomendado para o deploy em produção. 8
  • 9.
    MODO CLIENTE Esse modoé similar ao modo cluster, mas o processo Driver é executado na máquina cliente (aquela que submeteu a aplicação). 9
  • 10.
    MODO LOCAL Nesse modo,a aplicação Spark é executada na mesma máquina que submete a aplicação. A paralelização se dá através do uso de threads. Esse modo é utilizado durante o desenvolvimento e depuração de uma aplicação. 10
  • 11.
    A APLICAÇÃO SPARK Umaaplicação Spark é composta (logicamente) por um processo Driver e vários processos Executors. Geralmente o utilizamos o seguinte comando para submeter uma aplicação Spark num cluster Yarn: sudo spark-submit --class com.thoughtworks.core.JobsExample --master yarn --deploy-mode cluster s3://com.thoughtworks.training.de.recife/facilitador/de-training-0.1-SNAPSHOT.jar arg1 arg2 Ou o seguinte comando quando quero utilizar a API do AWS EMR: aws emr add-steps --cluster-id j-2AXXXXXXGAPLF --steps Type=Spark,Name="Spark Program”,ActionOnFailure=CONTINUE,Args=[-- class,org.apache.spark.examples.SparkPi,/usr/lib/spark/lib/spark-examples.jar,arg1,arg2] 11
  • 12.
    COMPONENTES - DRIVER Oprocesso Driver é responsável por manter informação sobre o estado da aplicação, responder ao comandos do programa ou entradas do usuário (spark-shell) e analisar, distribuir e agendar o trabalho entre os Executors. O processo Driver contem o ponto de entrada para a API do Spark chamado de SparkSession. 12
  • 13.
    COMPONENTES - SPARKSESSION A Spark Session é o ponto de entrada da API do Apache Spark. É através dela que o programa do usuário manipula os dados processados pela Aplicação Spark. Existe uma correspondência de um-pra-um entre uma Spark Session e uma Aplicação Spark. 13 val spark: SparkSession = SparkSession.builder() .config(conf) .getOrCreate()
  • 14.
    COMPONENTES - EXECUTORS Osprocessos Executors rodam nos worker nodes do cluster. Eles são responsáveis por efetivamente executar o código Spark (transformações e ações) e retornar o resultado para o processo Driver. O código Spark executado pelos Executors é agrupado em Tasks. 14
  • 15.
    COMPONENTES - TRANSFORMAÇÕES Asestruturas de dados do Spark (RDDs, Dataframes e Datasets) são imutáveis. Quando desejamos alterar essas estruturas, o fazemos através de transformações que resultam em uma nova instância de uma dessas estrutura de dados. 15 val sourceDataFrame = spark.read.csv("/path/to/a/csv/file") val transformedDataFrame = sourceDataFrame.filter(“country = 'Brasil'")
  • 16.
    COMPONENTES - AÇÕES Transformaçõessão operações lazy. Isso significa que quando um programa Spark é executado, as transformações não são executadas à medida que o programa "encontra" essas instruções. Ao invés disso, as transformações são enfileiradas até que uma Ação seja executada. Existem três tipos de Ações: Visualização de dados no console, coleta de dados em objetos nativos e escrita de dados. 16 val sourceDataFrame = spark.read.csv("/path/to/a/csv/file") val transformedDataFrame = sourceDataFrame.filter("pais = 'Brasil'") val recordCount = transformedDataFrame.count() //a transformação "filter' é executada
  • 17.
    COMPONENTES - JOBS Paracada Ação definida no código da Aplicação Spark, um Job é criado e enviado para execução nos Worker nodes. Um Job é dividido em Stages. 17 val users = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle")) val usersDF = spark.sparkContext.parallelize(users).toDF println(s"Users before filter ${usersDF.count()}") val filteresUsersDF = usersDF.where("Company = 'Google'") println(s"Users after filter ${filteresUsersDF.count()}")
  • 18.
  • 19.
    COMPONENTES - STAGES UmJob Spark é subdividido em Stages. Um Job Spark é executado de forma distribuída em diferentes máquinas de um cluster (worker nodes). Dessa forma a aplicação Spark pode se beneficiar da co-localidade dos dados, ou seja, cada worker node contem parte dos dados a serem processados e executa as transformações e ações somente nesses nos dados que possui. Também é dessa forma que o Spark obtém paralelismo. Entretanto, algumas operações requerem que os worker nodes troquem dados entre si. O nome dado à essa troca de dados é Shuffle. Para cada Shuffle que se faz necessário, um novo Stage é adicionado ao Job. 19
  • 20.
    COMPONENTES - STAGES valusers = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle")) val usersDS = spark.sparkContext.parallelize(users, 1).toDS val mappedUsersDF = usersDS.map(u => s"Name: ${u.Name} - Company: ${u.Company}") mappedUsersDF.collect().foreach(println) 20
  • 21.
  • 22.
    COMPONENTES - STAGES valusers = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle")) val usersDF = spark.sparkContext.parallelize(users, 1).toDF val mappedUsersDF = usersDF.withColumn("Initial", substring(col("Name"), 0, 1)) val groupedUsers = mappedUsersDF.groupBy("Initial").count() groupedUsers.collect().foreach(println) 22
  • 23.
  • 24.
    COMPONENTES - TASKS Taskssão a menor unidade de execução de uma aplicação Spark. Um Stage é composto por Tasks. O número de Tasks em um Stage tem uma correspondência de um-pra-um com o número de partições do bloco de dados no qual a Task está operando. Caso tenhamos uma partição, teremos uma Task. Caso tenhamos mil partições, teremos mil Tasks. Tasks são enviadas para execução pelos Executors. Controlando o número de Tasks nós controlamos o paralelismo da nossa Aplicação. 24
  • 25.
    COMPONENTES - TASKS valusers = List(User("John", "ThoughtWorks"), User("Jane", "Google"), User("Bob", "Oracle")) val usersDS = spark.sparkContext.parallelize(users, 8).toDS val mappedUsersDF = usersDS.map(u => s"Name: ${u.Name} - Company: ${u.Company}") mappedUsersDF.collect().foreach(println) 25
  • 26.
  • 27.
  • 28.
    RDD API RDDs sãocoleções de dados distribuídas e foram a primeira API disponibilizada pelo Spark. RDDs são hoje consideradas uma API de baixo nível e raramente precisam ser utilizadas. O ponto de entrada para a API de RDDs é o SparkContext. 28 val words = "Uma coleção de palavras".split(" ") val wordsRDD = spark.sparkContext.parallelize(words) val upperCaseWordsRDD = wordsRDD.map(_.toUpperCase)
  • 29.
    STRUCTURED API A StructuredAPI criou abstrações em cima das RDDs. São os Dataframes, Datasets, SQL Tables e Views. Alguns dos benefícios dessas abstrações são: • Estrutura tabular - facilita a estruturação, visualização e consulta dos dados (SQL) • Permite optimizações por parte da engine do Spark (Catalyst). 29
  • 30.
    STRUCTURED API -DATAFRAME 30 usersWithCustomSchemaDF .filter("Age > 18") .select("Name", "Age", "Address")
  • 31.
    STRUCTURED API -DATASET 31 usersParquetDS.map(_.Name).as[User] .filter(_.Company == "ThoughtWorks")
  • 32.
    CATALOG API -TABLES E VIEWS 32 spark.sql("select * from enhanced_users") spark.catalog.listTables().collectAsList().asScala.foreach(println) val userCompany = spark.table("Users") .selectExpr("concat(Name, ' - ', Company)")
  • 33.
    STRUCTURED API -AGGREGATIONS 33 val usersGrouped = enhancedUsersDF.groupBy("Company") usersGrouped.count() usersGrouped.max("Age", "Salary") usersGrouped.min("Age", "Salary") usersGrouped.mean("Age", "Salary") usersGrouped.avg("Age", "Salary") usersGrouped.agg(col("Company") usersGrouped.agg(expr("substring(Company,1,1) = 'T'")) usersGrouped.agg(Map("Age" -> "max", "Salary" -> "avg"))
  • 34.
    STRUCTURED API -JOINS 34 val enhancedUsersDF2 = usersParquetDF.join(ageSalaryDF, Seq("Name"), "left")
  • 35.
    BROADCAST JOINS 35 val enhancedUsersBroadcastDF= usersParquetDF .join(broadcast(ageSalaryDF), "Name")
  • 36.
    STRUCTURED API -COALESCE 36 val employees = spark .read .option("inferSchema", true) .option("header", true) .csv("../data/csv/northwind/employees.csv") .coalesce(4) //original partitions number must be greater than target
  • 37.
    STRUCTURED API -REPARTITION 37 val employees = spark .read .option("inferSchema", true) .option("header", true) .csv("../data/csv/northwind/employees.csv") .repartition(4)
  • 38.
    BATCH 38 val usersCSVDF =spark.read .option("header", true) .option("infer_schema", true) .option("delimiter", ";") .csv("../data/csv/users/")
  • 39.
    STREAMING 39 val socketStreamDF =spark .readStream .format("socket") .option("host", "localhost") .option("port", 9999) .load() val wordCountsDF = socketStreamDF .withColumn("timestamp", expr("CAST(parseTimestampWithTimezone(value) / 1000 AS TIMESTAMP)")) .withWatermark("timestamp", "10 seconds") .groupBy(window($"timestamp", "1 minutes", "30 seconds"), $"value") .count() val wordCountQuery = wordCountsDF .writeStream .format("parquet") .option("checkpointLocation", "../data/output/streaming-window/checkpoint") .option("path", "../data/output/parquet/streaming-window") .outputMode(OutputMode.Complete()) .queryName("WordCount") .start() wordCountQuery.awaitTermination()
  • 40.
    STREAMING - WINDOWOPERATIONS 40
  • 41.
  • 42.
    STREAMING - GLOSSÁRIO Oque é? • Window duration: É o intervalo de tempo em que ser acumular os dados que estão sendo processados, ex.: O total de vendas das última duas horas. • Slide duration: A frequência com que ser quer mover (atualizar) a janela, ex.: Atualize o total de vendas da última hora a cada 5 minutos. • Trigger: O intervalo em que se processa um batch de eventos. Não tem relação com a janela. Ex.: a pipeline processa os micro-batches em intervalos de 1 segundo. 42
  • 43.
    DATA STORAGE As soluçõesde armazenamento mais comuns utilizadas por aplicacões Spark são: • HDFS • S3 • Cassandra Os dados quando armazenados são replicados e distribuídos de acordo a solução utilizada. Nos casos do S3 e Cassandra existe o que chamamos de consistência eventual o que pode fazer com que leituras não estejam em sincronia com as escritas. 43
  • 44.
    DATA STORAGE -FORMATS Os formatos mais utilizados para armazenamento de dados em plataformas de dados são: • Plain Text, CSV, JSON • Parquet - https://parquet.apache.org/ • ORC - https://orc.apache.org/ • AVRO - https://avro.apache.org/ 44
  • 45.
    DATA STORAGE -PARTITIONING 45 spark.read .option("delimiter", ";") .option("header", true) .option("infer_schema", true) .csv(ordersBucket) .write .partitionBy("StoreId", "Timestamp") .parquet(ordersParquetBucket)
  • 46.
    DATA STORAGE -PARTITIONING 46
  • 47.
    TESTING 47 class MyJobTest extends FunSuite withBatchRunner with Matchers with BeforeAndAfter with BeforeAndAfterAll { before {} after {} override def beforeAll(): {} override def afterAll() {} test("something should happen") { val arg1 = 10 val arg2 = "something" MyJob.main(Array(arg1, arg2)) val aDF = spark.read(…) aDF.count() should be 100 } }
  • 48.
    DEPLOYMENT Atualmente existem trêsopções de gerenciadores de clusters que podemos utilizar para deployarmos uma aplicação Spark. • YARN • MESOS • Spark Standalone Cluster • Kubernetes O serviço EMR da AWS utiliza o YARN como gerenciador de cluster. 48
  • 49.
  • 50.
    EXERCÍCIOS - OTIMIZAÇÃO 50 •Quais os valores ótimos de número de executors e memória para o nosso cluster? • Qual o número ótimo de partições para obtermos o máximo de paralelismo nos nossos jobs?
  • 51.
    EXERCÍCIOS - BATCH 51 •Qual o valor total de receita líquida? • Qual o valor total de receita líquida por loja? • Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais (receita líquida)? • Quais os 10 produtos que mais geram receita (receita líquida)? • Salve os dados de vendas no formato parquet e particionados por loja em um bucket/pasta diferente. • Salve os dados de itens no formato parquet e particionados por produto em um bucket/pasta diferente. • Salve os dados de produtos no formato JSON em um bucket/pasta diferente. Streaming Qual o valor total de receita líquida nos últimos 5 minutos? Qual o valor total de receita líquida por loja nos últimos 5 minutos? Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais (receita líquida)? Quais os 10 produtos que mais geram receita nos últimos 5 minutos (receita líquida)? PS: Receita líquida = (preço item - desconto item) * quantidade item
  • 52.
    EXERCÍCIOS - STREAMING 52 •Qual o valor total de receita líquida nos últimos 5 minutos? • Qual o valor total de receita líquida por loja nos últimos 5 minutos? • Quais os 10 produtos mais vendidos (quantidade) e seus respectivos totais (receita líquida)? • Quais os 10 produtos que mais geram receita nos últimos 5 minutos (receita líquida)?
  • 53.
  • 54.
    Para perguntas esugestões: Contate me através de: jsilva@thoughtworks.com OBRIGADO