SlideShare uma empresa Scribd logo
1 de 49
Baixar para ler offline
Apache Spark
Structured Stream
Um moedor de dados em tempo real quase real
Eiti Kimura
Datafest Out/2018
Apache Spark
Structured Stream
● IT Coordinator and Software Architect at Movile
● Msc. in Electrical Engineering
● Apache Cassandra MVP (2014/2015 e 2015/2016)
● Apache Cassandra Contributor (2015)
● Cassandra Summit Speaker (2014 e 2015)
● Strata Hadoop World Singapore Speaker (2016)
● Spark Summit Speaker (2017)
● RedisConf Speaker (2018)
Eiti Kimura
eitikimura
a Movile company
building strong relations
Sumário
● Introdução ao Apache Spark
● Nova API Structured Streaming
● Caso de uso de uma aplicação de
processamento em "tempo real"
● Lições aprendidas
By Alexander Savchuk
Introdução ao Apache Spark
Apache Spark™ is a fast and general engine
for large-scale data processing.
Em que o Apache Spark é usado?
● Processos de ETL
● Consultas Interativas (SQL)
● Análise de dados avançada
● Machine Learning/Deep Learning
● Streaming sobre grandes datasets
Funcionamento Apache Spark
Arquitetura do Apache Spark
Stream de Dados
Structured Stream
API de alto nível para desenvolvimento
de aplicações contínuas de
processamento de stream de dados,
integrando com storages de forma
consistente e tolerante a falhas.
Apache Spark Structured Stream
• Nova API de alto nível
• Junção de dados contínua com conteúdo estático
• Integrações com diversas fontes de dados (File, Kafka)
• Tolerante a falhas (checkpoints)
• Tratamento de eventos desordenados (watermark)
Processamento Batch com DataFrames
input = spark.read
.format("csv")
.load("source-path")
result = input
.select("device", "signal")
.where("signal > 15")
result.write
.format("parquet")
.save("dest-path")
Leitura de um arquivo CSV
Aplicação de filtros e seleção
Escrita em formato parquet
Processamento Streaming com DataFrames
input = spark.readStream
.format("csv")
.load("source-path")
result = input
.select("device", "signal")
.where("signal > 15")
result.writeStream
.format("parquet")
.start("dest-path")
Leitura de um arquivo CSV Stream
Aplicação de filtros e seleção
Escrita em formato parquet Stream
Substitui read por readStream
Código não muda!
Substitui write por writeStream
e save por start
Apache Spark Structured Stream
Premissas de desenvolvimento Stream
input data source (S3, HDFS, Kafka, Dir)
processing batch (query,
functions, expressions)
output data (append, complete, update)
triggers (when to update the results)
Tipos de Entrada de Dados (Input Sources)
● File: arquivos em um diretório (parquet, json, csv)
● Kafka: obtém dados de e um tópico do Kafka (versão
>= 0.10.0)
● Socket: lê as informações de uma conexão via Socket,
usado para testes.
INPUT
Modos de Output, saída de dados
● Complete: todas as linhas resultantes do
processamento são direcionadas para saída de dados
● Update: somente as linhas que sofreram alterações ao
longo da última execução
● Append: somente as novas linhas geradas no
processamento
OUTPUT
Tipos de Saída de Dados (Output Sinks)
● File: armazena a saída em um diretório (parquet, orc,
json, csv)
● Kafka: armazena a saída e um ou mais tópicos do
Kafka (Apache Spark 2.3)
● Foreach: executa um processamento de forma
arbitrária nos registros de saída (personalizável)
● Memory/Console: registra as alterações e imprime no
console (usado para debug)
Tolerância a Falhas com Checkpoints
Checkpointing: gravação de
metadados (ex: offsets) em
write ahead logs em disco
(S3/HDFS) para recuperação
em caso de falhas.
Tratamento de dados desordenados (Watermarking)
'Moedor' de dados em tempo real
quase real
USE CASE
Processo de ETL tradicional
minutes / seconds
Processo com Structured Streaming
Subscription &
Billing System a.k.a
SBSSBS
Arquitetura do Processador Contínuo
Arquitetura do Processador Contínuo
Arquitetura do Processador Contínuo
Arquitetura do Processador Contínuo
Amostra de Dados CSV (Gzipped)
838,2,5500000000,100015,"{""authCode"":""3215"",""transactionIdAuth"":""101170622042837
4938""}",SUBSCRIPTION_050,0.5,11,0,1,14,Subscription renew.,2017-07-18
13:22:59.518,,,19,PRE,false,Charge Fail. CTN[31984771092][PRE][GSM]: Without
Credit.,,,,0,458,,engine2dc2,23,3,5,2017-07-18
13:22:59.544,,FE1952B0-571D-11E7-8A17-CA2EE9B22EAB,NT0359
838,2,5500000000,100008,"{""authCode"":""9496"",""transactionIdAuth"":""117170703192540
9718""}",SUBSCRIPTION_099,0.99,11,0,1,14,Subscription renew.,2017-07-18
13:22:58.893,,,19,PRE,false,Charge Fail. CTN[21976504467][PRE][GSM]: Without
Credit.,,,,0,1074,,engine2dc2,24,3,5,2017-07-18
13:22:58.928,,3ADF36D0-6040-11E7-9619-A2D6E78E4511,NT0360
703,2,5500000000,100004,"{""authCode"":""6838"",""transactionIdAuth"":""118170706120694
8526""}",SUBSCRIPTION_299,2.99,11,0,1,14,Subscription renew.,2017-07-18
13:22:59.246,,,19,PRE,false,Charge Fail. CTN[84994640470][PRE][GSM]: Without
Credit.,,,,0,748,,engine2dc2,24,3,5,2017-07-18 13:22:59.254, NT0299
Fonte de Entrada de Dados
val streamReader = spark.readStream
.format("csv")
.option("header", false)
.option("latestFirst", "true")
.option("maxFilesPerTrigger", "10")
.option("charset", "UTF-8")
.option("mode", "DROPMALFORMED")
.schema(ReadSchemas.csvTransactionSchema)
.load("hdfs://YOUR_PATH/20*/*/*/*.gz")
val conf = new SparkConf().setAppName("Structured Streaming")
val spark = SparkSession.builder()
.config(conf).getOrCreate()
fragmento de código Scala
INPUT
Estrutura na definição de um Schema
StructField("origin_id", IntegerType, true)
Nome do campo
Tipo do campo
pode ser nulo?
Estrutura na definição de um Schema
StructField("origin_id", IntegerType, true),
StructType(Array(
...
))
Definição de Schema de Leitura de Dados
// the csv data schema
def csvTransactionLogSchema = StructType {
StructType(Array(
StructField("id", StringType, true),
StructField("application_id", IntegerType, true),
StructField("carrier_id", IntegerType, true),
StructField("phone", StringType, true),
StructField("price", DoubleType, true),
StructField("origin_id", IntegerType, true),
. . .
StructField("transaction_status_id", IntegerType, true),
StructField("transaction_action_id", IntegerType, true),
StructField("returned_code", StringType, true),
StructField("creation_date", TimestampType, true),
StructField("rotate_number", IntegerType, true),
))
}
fragmento de código Scala
Processamento (Spark SQL API) v1
val query = streamReader
.withColumn("date", $"creation_date".cast("date"))
.withColumn("successful_charges", when($"transaction_status_id" === 2, 1))
.withColumn("no_credit", when($"transaction_status_id" === 0, 1).otherwise(0))
.withColumn("error", when($"transaction_status_id" === 3).otherwise(0))
.filter("carrier_id IN (1,2,4,5)")
.filter("transaction_status_id NOT IN (5, 6)")
.filter("transaction_action_id IN (0, 1)")
.withWatermark("creation_date", "3 hour")
.groupBy($"carrier_id", window($"creation_date", "5 minutes").as("window"))
.agg($"carrier_id",
avg($"response_time").as("avg_response_time"),
sum($"successful_charges").as("successful_charges"),
sum($"no_credit").as("no_credit"),
sum($"error").as("error"),
count($"carrier_id").as("total_attempts"))
select
case
when
filtering
aggregation
Processamento (Spark SQL API) v2
streamReader
.withWatermark("creation_date", "3 hour")
.createOrReplaceTempView("transaction_temp_table")
val streamReader = spark.readStream
.format("csv")
.schema(ReadSchemas.csvTransactionSchema)
.load("hdfs://YOUR_PATH/20*/*/*/*.gz")
Processamento (Spark SQL) v2
val query : DataFrame = spark.sql(
"""
SELECT carrier_id, TO_DATE(creation_date) as record_date, HOUR(creation_date) as hour_of_day,
WINDOW(creation_date, "5 minutes").start as start_date,
AVG(response_time) as avg_response_time ,
SUM(CASE
WHEN transaction_status_id = 2 THEN 1
ELSE 0
END) as successful_charges,
SUM(CASE
WHEN transaction_status_id = 0 THEN 1
ELSE 0
END) as no_credit,
count(carrier_id) as total_attempts
FROM transaction_raw
WHERE carrier_id IN (1,2,4,5)
AND transaction_action_id IN (0, 1)
AND transaction_status_id NOT IN (5, 6)
GROUP BY carrier_id, TO_DATE(creation_date), HOUR(creation_date),
WINDOW(creation_date, "5 minutes").start
""")
SELECT carrier_id, TO_DATE(creation_date) as record_date, HOUR(creation_date) as hour_of_day,
WINDOW(creation_date, "5 minutes").start as start_date,
AVG(response_time) as avg_response_time ,
SUM(CASE
WHEN transaction_status_id = 2 THEN 1
ELSE 0
END) as successful_charges,
SUM(CASE
WHEN transaction_status_id = 0 THEN 1
ELSE 0
END) as no_credit,
count(carrier_id) as total_attempts
FROM transaction_temp_table
WHERE carrier_id IN (1,2,4,5)
AND transaction_action_id IN (0, 1)
AND transaction_status_id NOT IN (5, 6)
GROUP BY carrier_id, TO_DATE(creation_date), HOUR(creation_date),
WINDOW(creation_date, "5 minutes").start
Fonte de Saída de Dados
val properties = ConfigFactory.load()
val username = properties.getString("postgres.username")
val password = properties.getString("postgres.password")
val resource = properties.getString("postgres.url")
val jdbcWriter = new JDBCSink(resource, username, password)
val foreachStream = query
.select($"carrier_id", $"date", $"hour_of_day", $"start_date", $"end_date")
.writeStream
.foreach(jdbcWriter)
.outputMode(OutputMode.Update())
.trigger(Trigger.ProcessingTime("2 minute"))
.option("checkpointLocation", "hdfs://YOUR_PATH/checkpoint-complete/")
.start
foreachStream.awaitTermination()
OUTPUT
Result table em consolidação
+--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+
|id|record_date|hour_of_day|start_date |end_date |avg_response_time |success_charges|no_credit|error|total_attempts|
+--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+
|1 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|618.8061297220243 |4 |2607 |195 |2806 |
|2 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|1456.4242838751206|13 |10912 |1503 |12428 |
|5 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|1161.7308960143841|9 |2796 |532 |3337 |
|4 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|2950.642105263158 |4 |1364 |54 |1425 |
+--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+
Resultados obtidos
Structured Streaming
t = 3-7 minutos
Lições Aprendidas
de
Schema
EV ÇÃO
def csvSchema = StructType {
StructType(Array(
StructField("id", StringType, true),
StructField("application_id", IntegerType, true),
StructField("carrier_id", IntegerType, true),
StructField("creation_date", TimestampType, true)
))}
Resiliência no processamento
com Streams
val input = spark.readStream
.option("mode", "DROPMALFORMED")
spark.sqlContext
.setConf("spark.sql.files.ignoreCorruptFiles","true")
Operações não Suportadas com Streams (DF/DS)
● Agregação de múltiplos Streams de dados
● Uso de LIMIT ou TAKE das primeiras N linhas
● Uso da instrução DISTINCT
● Operações de ordenação (parcialmente) em Output
Mode Complete
● Operações de Outter Joins também não são suportadas
MUITO OBRIGADO!
eitikimura eiti-kimura-movile eiti.kimura@wavy.global

Mais conteúdo relacionado

Semelhante a Apache Spark Structured Stream: um processador de dados em tempo real quase real

Exemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceExemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceFelipe
 
QCon 2015 - Combinando AngularJS com Java EE
QCon 2015 - Combinando AngularJS com Java EEQCon 2015 - Combinando AngularJS com Java EE
QCon 2015 - Combinando AngularJS com Java EERodrigo Cândido da Silva
 
PyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonPyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonBruno Rocha
 
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009Ramon Durães
 
Precisamos falar sobre MERN stack
Precisamos falar sobre MERN stackPrecisamos falar sobre MERN stack
Precisamos falar sobre MERN stackSidney Roberto
 
Bancos de dados No-SQL e afins
Bancos de dados No-SQL e afinsBancos de dados No-SQL e afins
Bancos de dados No-SQL e afinsdcarneir
 
Tecnologias para mineração de dados nas nuvens
Tecnologias para mineração de dados nas nuvensTecnologias para mineração de dados nas nuvens
Tecnologias para mineração de dados nas nuvensAlessandro Binhara
 
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EEJavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EERodrigo Cândido da Silva
 
Você não deveria escrever uma API para isso
Você não deveria escrever uma API para issoVocê não deveria escrever uma API para isso
Você não deveria escrever uma API para issoJunior Conte
 
Construindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskConstruindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskRodrigo R Passos
 
Construindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskConstruindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskRodrigo R Passos
 
Palestra DataFlow - II São Paulo Perl Workshop
Palestra DataFlow - II São Paulo Perl WorkshopPalestra DataFlow - II São Paulo Perl Workshop
Palestra DataFlow - II São Paulo Perl WorkshopAlexei Znamensky
 
Apache Spark Overview and Applications
Apache Spark Overview and ApplicationsApache Spark Overview and Applications
Apache Spark Overview and ApplicationsDiogo Munaro Vieira
 
Uso Do Arena Em Simulacao
Uso Do Arena Em SimulacaoUso Do Arena Em Simulacao
Uso Do Arena Em SimulacaoPrydigo
 

Semelhante a Apache Spark Structured Stream: um processador de dados em tempo real quase real (20)

Exemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduceExemplos de uso de apache spark usando aws elastic map reduce
Exemplos de uso de apache spark usando aws elastic map reduce
 
QCon 2015 - Combinando AngularJS com Java EE
QCon 2015 - Combinando AngularJS com Java EEQCon 2015 - Combinando AngularJS com Java EE
QCon 2015 - Combinando AngularJS com Java EE
 
PyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonPyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com Python
 
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009
Introdução ao ASP.NET 3.5 - Campus Party Brasil 2009
 
Precisamos falar sobre MERN stack
Precisamos falar sobre MERN stackPrecisamos falar sobre MERN stack
Precisamos falar sobre MERN stack
 
Bancos de dados No-SQL e afins
Bancos de dados No-SQL e afinsBancos de dados No-SQL e afins
Bancos de dados No-SQL e afins
 
Tecnologias para mineração de dados nas nuvens
Tecnologias para mineração de dados nas nuvensTecnologias para mineração de dados nas nuvens
Tecnologias para mineração de dados nas nuvens
 
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EEJavaOne LATAM 2016 - Combinando AngularJS com Java EE
JavaOne LATAM 2016 - Combinando AngularJS com Java EE
 
Você não deveria escrever uma API para isso
Você não deveria escrever uma API para issoVocê não deveria escrever uma API para isso
Você não deveria escrever uma API para isso
 
Wicket 2008
Wicket 2008Wicket 2008
Wicket 2008
 
Construindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskConstruindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com Asterisk
 
Construindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com AsteriskConstruindo URA e Sistemas de Call Center com Asterisk
Construindo URA e Sistemas de Call Center com Asterisk
 
C# 4.0
C# 4.0C# 4.0
C# 4.0
 
Palestra DataFlow - II São Paulo Perl Workshop
Palestra DataFlow - II São Paulo Perl WorkshopPalestra DataFlow - II São Paulo Perl Workshop
Palestra DataFlow - II São Paulo Perl Workshop
 
servlet-respostas
servlet-respostasservlet-respostas
servlet-respostas
 
Apache Spark Overview and Applications
Apache Spark Overview and ApplicationsApache Spark Overview and Applications
Apache Spark Overview and Applications
 
Servlets e JSP
Servlets e JSPServlets e JSP
Servlets e JSP
 
DDD > Experiências
DDD > ExperiênciasDDD > Experiências
DDD > Experiências
 
Uso Do Arena Em Simulacao
Uso Do Arena Em SimulacaoUso Do Arena Em Simulacao
Uso Do Arena Em Simulacao
 
MongoDB + PHP
MongoDB + PHPMongoDB + PHP
MongoDB + PHP
 

Mais de Eiti Kimura

[Redis conf18] The Versatility of Redis
[Redis conf18] The Versatility of Redis[Redis conf18] The Versatility of Redis
[Redis conf18] The Versatility of RedisEiti Kimura
 
[DEVFEST] Apache Spark Casos de Uso e Escalabilidade
[DEVFEST] Apache Spark  Casos de Uso e Escalabilidade[DEVFEST] Apache Spark  Casos de Uso e Escalabilidade
[DEVFEST] Apache Spark Casos de Uso e EscalabilidadeEiti Kimura
 
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto DesempenhoEiti Kimura
 
[TDC2016] Apache SparkMLlib: Machine Learning na Prática
[TDC2016] Apache SparkMLlib:  Machine Learning na Prática[TDC2016] Apache SparkMLlib:  Machine Learning na Prática
[TDC2016] Apache SparkMLlib: Machine Learning na PráticaEiti Kimura
 
[TDC2016] Apache Cassandra Estratégias de Modelagem de Dados
[TDC2016]  Apache Cassandra Estratégias de Modelagem de Dados[TDC2016]  Apache Cassandra Estratégias de Modelagem de Dados
[TDC2016] Apache Cassandra Estratégias de Modelagem de DadosEiti Kimura
 
QConSP16 - Apache Cassandra Evoluindo Sistemas Distribuídos
QConSP16 - Apache Cassandra Evoluindo Sistemas DistribuídosQConSP16 - Apache Cassandra Evoluindo Sistemas Distribuídos
QConSP16 - Apache Cassandra Evoluindo Sistemas DistribuídosEiti Kimura
 
SP Big Data Meetup - Conhecendo Apache Cassandra @Movile
SP Big Data Meetup - Conhecendo Apache Cassandra @MovileSP Big Data Meetup - Conhecendo Apache Cassandra @Movile
SP Big Data Meetup - Conhecendo Apache Cassandra @MovileEiti Kimura
 
Cassandra Summit 2015 - A Change of Seasons
Cassandra Summit 2015 - A Change of SeasonsCassandra Summit 2015 - A Change of Seasons
Cassandra Summit 2015 - A Change of SeasonsEiti Kimura
 
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto Desempenho
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto DesempenhoTDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto Desempenho
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto DesempenhoEiti Kimura
 
Conhecendo Apache Cassandra @Movile
Conhecendo Apache Cassandra  @MovileConhecendo Apache Cassandra  @Movile
Conhecendo Apache Cassandra @MovileEiti Kimura
 
Cassandra overview: Um Caso Prático
Cassandra overview:  Um Caso PráticoCassandra overview:  Um Caso Prático
Cassandra overview: Um Caso PráticoEiti Kimura
 
QConSP 2014 - Cassandra no Desenvolvimento de Aplicações para serviços Móveis
QConSP 2014 - Cassandra no Desenvolvimento  de Aplicações para  serviços MóveisQConSP 2014 - Cassandra no Desenvolvimento  de Aplicações para  serviços Móveis
QConSP 2014 - Cassandra no Desenvolvimento de Aplicações para serviços MóveisEiti Kimura
 

Mais de Eiti Kimura (12)

[Redis conf18] The Versatility of Redis
[Redis conf18] The Versatility of Redis[Redis conf18] The Versatility of Redis
[Redis conf18] The Versatility of Redis
 
[DEVFEST] Apache Spark Casos de Uso e Escalabilidade
[DEVFEST] Apache Spark  Casos de Uso e Escalabilidade[DEVFEST] Apache Spark  Casos de Uso e Escalabilidade
[DEVFEST] Apache Spark Casos de Uso e Escalabilidade
 
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
[DataFest-2017] Apache Cassandra Para Sistemas de Alto Desempenho
 
[TDC2016] Apache SparkMLlib: Machine Learning na Prática
[TDC2016] Apache SparkMLlib:  Machine Learning na Prática[TDC2016] Apache SparkMLlib:  Machine Learning na Prática
[TDC2016] Apache SparkMLlib: Machine Learning na Prática
 
[TDC2016] Apache Cassandra Estratégias de Modelagem de Dados
[TDC2016]  Apache Cassandra Estratégias de Modelagem de Dados[TDC2016]  Apache Cassandra Estratégias de Modelagem de Dados
[TDC2016] Apache Cassandra Estratégias de Modelagem de Dados
 
QConSP16 - Apache Cassandra Evoluindo Sistemas Distribuídos
QConSP16 - Apache Cassandra Evoluindo Sistemas DistribuídosQConSP16 - Apache Cassandra Evoluindo Sistemas Distribuídos
QConSP16 - Apache Cassandra Evoluindo Sistemas Distribuídos
 
SP Big Data Meetup - Conhecendo Apache Cassandra @Movile
SP Big Data Meetup - Conhecendo Apache Cassandra @MovileSP Big Data Meetup - Conhecendo Apache Cassandra @Movile
SP Big Data Meetup - Conhecendo Apache Cassandra @Movile
 
Cassandra Summit 2015 - A Change of Seasons
Cassandra Summit 2015 - A Change of SeasonsCassandra Summit 2015 - A Change of Seasons
Cassandra Summit 2015 - A Change of Seasons
 
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto Desempenho
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto DesempenhoTDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto Desempenho
TDC2015 - Apache Cassandra no Desenvolvimento de Sistemas de Alto Desempenho
 
Conhecendo Apache Cassandra @Movile
Conhecendo Apache Cassandra  @MovileConhecendo Apache Cassandra  @Movile
Conhecendo Apache Cassandra @Movile
 
Cassandra overview: Um Caso Prático
Cassandra overview:  Um Caso PráticoCassandra overview:  Um Caso Prático
Cassandra overview: Um Caso Prático
 
QConSP 2014 - Cassandra no Desenvolvimento de Aplicações para serviços Móveis
QConSP 2014 - Cassandra no Desenvolvimento  de Aplicações para  serviços MóveisQConSP 2014 - Cassandra no Desenvolvimento  de Aplicações para  serviços Móveis
QConSP 2014 - Cassandra no Desenvolvimento de Aplicações para serviços Móveis
 

Apache Spark Structured Stream: um processador de dados em tempo real quase real

  • 1. Apache Spark Structured Stream Um moedor de dados em tempo real quase real Eiti Kimura Datafest Out/2018 Apache Spark Structured Stream
  • 2. ● IT Coordinator and Software Architect at Movile ● Msc. in Electrical Engineering ● Apache Cassandra MVP (2014/2015 e 2015/2016) ● Apache Cassandra Contributor (2015) ● Cassandra Summit Speaker (2014 e 2015) ● Strata Hadoop World Singapore Speaker (2016) ● Spark Summit Speaker (2017) ● RedisConf Speaker (2018) Eiti Kimura eitikimura
  • 3. a Movile company building strong relations
  • 4. Sumário ● Introdução ao Apache Spark ● Nova API Structured Streaming ● Caso de uso de uma aplicação de processamento em "tempo real" ● Lições aprendidas
  • 6. Introdução ao Apache Spark Apache Spark™ is a fast and general engine for large-scale data processing.
  • 7. Em que o Apache Spark é usado? ● Processos de ETL ● Consultas Interativas (SQL) ● Análise de dados avançada ● Machine Learning/Deep Learning ● Streaming sobre grandes datasets
  • 11. Structured Stream API de alto nível para desenvolvimento de aplicações contínuas de processamento de stream de dados, integrando com storages de forma consistente e tolerante a falhas.
  • 12. Apache Spark Structured Stream • Nova API de alto nível • Junção de dados contínua com conteúdo estático • Integrações com diversas fontes de dados (File, Kafka) • Tolerante a falhas (checkpoints) • Tratamento de eventos desordenados (watermark)
  • 13. Processamento Batch com DataFrames input = spark.read .format("csv") .load("source-path") result = input .select("device", "signal") .where("signal > 15") result.write .format("parquet") .save("dest-path") Leitura de um arquivo CSV Aplicação de filtros e seleção Escrita em formato parquet
  • 14. Processamento Streaming com DataFrames input = spark.readStream .format("csv") .load("source-path") result = input .select("device", "signal") .where("signal > 15") result.writeStream .format("parquet") .start("dest-path") Leitura de um arquivo CSV Stream Aplicação de filtros e seleção Escrita em formato parquet Stream Substitui read por readStream Código não muda! Substitui write por writeStream e save por start
  • 16. Premissas de desenvolvimento Stream input data source (S3, HDFS, Kafka, Dir) processing batch (query, functions, expressions) output data (append, complete, update) triggers (when to update the results)
  • 17.
  • 18.
  • 19.
  • 20.
  • 21. Tipos de Entrada de Dados (Input Sources) ● File: arquivos em um diretório (parquet, json, csv) ● Kafka: obtém dados de e um tópico do Kafka (versão >= 0.10.0) ● Socket: lê as informações de uma conexão via Socket, usado para testes. INPUT
  • 22. Modos de Output, saída de dados ● Complete: todas as linhas resultantes do processamento são direcionadas para saída de dados ● Update: somente as linhas que sofreram alterações ao longo da última execução ● Append: somente as novas linhas geradas no processamento OUTPUT
  • 23. Tipos de Saída de Dados (Output Sinks) ● File: armazena a saída em um diretório (parquet, orc, json, csv) ● Kafka: armazena a saída e um ou mais tópicos do Kafka (Apache Spark 2.3) ● Foreach: executa um processamento de forma arbitrária nos registros de saída (personalizável) ● Memory/Console: registra as alterações e imprime no console (usado para debug)
  • 24. Tolerância a Falhas com Checkpoints Checkpointing: gravação de metadados (ex: offsets) em write ahead logs em disco (S3/HDFS) para recuperação em caso de falhas.
  • 25. Tratamento de dados desordenados (Watermarking)
  • 26. 'Moedor' de dados em tempo real quase real USE CASE
  • 27. Processo de ETL tradicional minutes / seconds Processo com Structured Streaming
  • 33.
  • 34. Amostra de Dados CSV (Gzipped) 838,2,5500000000,100015,"{""authCode"":""3215"",""transactionIdAuth"":""101170622042837 4938""}",SUBSCRIPTION_050,0.5,11,0,1,14,Subscription renew.,2017-07-18 13:22:59.518,,,19,PRE,false,Charge Fail. CTN[31984771092][PRE][GSM]: Without Credit.,,,,0,458,,engine2dc2,23,3,5,2017-07-18 13:22:59.544,,FE1952B0-571D-11E7-8A17-CA2EE9B22EAB,NT0359 838,2,5500000000,100008,"{""authCode"":""9496"",""transactionIdAuth"":""117170703192540 9718""}",SUBSCRIPTION_099,0.99,11,0,1,14,Subscription renew.,2017-07-18 13:22:58.893,,,19,PRE,false,Charge Fail. CTN[21976504467][PRE][GSM]: Without Credit.,,,,0,1074,,engine2dc2,24,3,5,2017-07-18 13:22:58.928,,3ADF36D0-6040-11E7-9619-A2D6E78E4511,NT0360 703,2,5500000000,100004,"{""authCode"":""6838"",""transactionIdAuth"":""118170706120694 8526""}",SUBSCRIPTION_299,2.99,11,0,1,14,Subscription renew.,2017-07-18 13:22:59.246,,,19,PRE,false,Charge Fail. CTN[84994640470][PRE][GSM]: Without Credit.,,,,0,748,,engine2dc2,24,3,5,2017-07-18 13:22:59.254, NT0299
  • 35. Fonte de Entrada de Dados val streamReader = spark.readStream .format("csv") .option("header", false) .option("latestFirst", "true") .option("maxFilesPerTrigger", "10") .option("charset", "UTF-8") .option("mode", "DROPMALFORMED") .schema(ReadSchemas.csvTransactionSchema) .load("hdfs://YOUR_PATH/20*/*/*/*.gz") val conf = new SparkConf().setAppName("Structured Streaming") val spark = SparkSession.builder() .config(conf).getOrCreate() fragmento de código Scala INPUT
  • 36. Estrutura na definição de um Schema StructField("origin_id", IntegerType, true) Nome do campo Tipo do campo pode ser nulo?
  • 37. Estrutura na definição de um Schema StructField("origin_id", IntegerType, true), StructType(Array( ... ))
  • 38. Definição de Schema de Leitura de Dados // the csv data schema def csvTransactionLogSchema = StructType { StructType(Array( StructField("id", StringType, true), StructField("application_id", IntegerType, true), StructField("carrier_id", IntegerType, true), StructField("phone", StringType, true), StructField("price", DoubleType, true), StructField("origin_id", IntegerType, true), . . . StructField("transaction_status_id", IntegerType, true), StructField("transaction_action_id", IntegerType, true), StructField("returned_code", StringType, true), StructField("creation_date", TimestampType, true), StructField("rotate_number", IntegerType, true), )) } fragmento de código Scala
  • 39. Processamento (Spark SQL API) v1 val query = streamReader .withColumn("date", $"creation_date".cast("date")) .withColumn("successful_charges", when($"transaction_status_id" === 2, 1)) .withColumn("no_credit", when($"transaction_status_id" === 0, 1).otherwise(0)) .withColumn("error", when($"transaction_status_id" === 3).otherwise(0)) .filter("carrier_id IN (1,2,4,5)") .filter("transaction_status_id NOT IN (5, 6)") .filter("transaction_action_id IN (0, 1)") .withWatermark("creation_date", "3 hour") .groupBy($"carrier_id", window($"creation_date", "5 minutes").as("window")) .agg($"carrier_id", avg($"response_time").as("avg_response_time"), sum($"successful_charges").as("successful_charges"), sum($"no_credit").as("no_credit"), sum($"error").as("error"), count($"carrier_id").as("total_attempts")) select case when filtering aggregation
  • 40. Processamento (Spark SQL API) v2 streamReader .withWatermark("creation_date", "3 hour") .createOrReplaceTempView("transaction_temp_table") val streamReader = spark.readStream .format("csv") .schema(ReadSchemas.csvTransactionSchema) .load("hdfs://YOUR_PATH/20*/*/*/*.gz")
  • 41. Processamento (Spark SQL) v2 val query : DataFrame = spark.sql( """ SELECT carrier_id, TO_DATE(creation_date) as record_date, HOUR(creation_date) as hour_of_day, WINDOW(creation_date, "5 minutes").start as start_date, AVG(response_time) as avg_response_time , SUM(CASE WHEN transaction_status_id = 2 THEN 1 ELSE 0 END) as successful_charges, SUM(CASE WHEN transaction_status_id = 0 THEN 1 ELSE 0 END) as no_credit, count(carrier_id) as total_attempts FROM transaction_raw WHERE carrier_id IN (1,2,4,5) AND transaction_action_id IN (0, 1) AND transaction_status_id NOT IN (5, 6) GROUP BY carrier_id, TO_DATE(creation_date), HOUR(creation_date), WINDOW(creation_date, "5 minutes").start """) SELECT carrier_id, TO_DATE(creation_date) as record_date, HOUR(creation_date) as hour_of_day, WINDOW(creation_date, "5 minutes").start as start_date, AVG(response_time) as avg_response_time , SUM(CASE WHEN transaction_status_id = 2 THEN 1 ELSE 0 END) as successful_charges, SUM(CASE WHEN transaction_status_id = 0 THEN 1 ELSE 0 END) as no_credit, count(carrier_id) as total_attempts FROM transaction_temp_table WHERE carrier_id IN (1,2,4,5) AND transaction_action_id IN (0, 1) AND transaction_status_id NOT IN (5, 6) GROUP BY carrier_id, TO_DATE(creation_date), HOUR(creation_date), WINDOW(creation_date, "5 minutes").start
  • 42. Fonte de Saída de Dados val properties = ConfigFactory.load() val username = properties.getString("postgres.username") val password = properties.getString("postgres.password") val resource = properties.getString("postgres.url") val jdbcWriter = new JDBCSink(resource, username, password) val foreachStream = query .select($"carrier_id", $"date", $"hour_of_day", $"start_date", $"end_date") .writeStream .foreach(jdbcWriter) .outputMode(OutputMode.Update()) .trigger(Trigger.ProcessingTime("2 minute")) .option("checkpointLocation", "hdfs://YOUR_PATH/checkpoint-complete/") .start foreachStream.awaitTermination() OUTPUT
  • 43. Result table em consolidação +--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+ |id|record_date|hour_of_day|start_date |end_date |avg_response_time |success_charges|no_credit|error|total_attempts| +--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+ |1 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|618.8061297220243 |4 |2607 |195 |2806 | |2 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|1456.4242838751206|13 |10912 |1503 |12428 | |5 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|1161.7308960143841|9 |2796 |532 |3337 | |4 |2017-07-18 |13 |2017-07-18 13:20:00|2017-07-18 13:25:00|2950.642105263158 |4 |1364 |54 |1425 | +--+-----------+-----------+-------------------+-------------------+------------------+---------------+---------+-----+--------------+
  • 46. de Schema EV ÇÃO def csvSchema = StructType { StructType(Array( StructField("id", StringType, true), StructField("application_id", IntegerType, true), StructField("carrier_id", IntegerType, true), StructField("creation_date", TimestampType, true) ))}
  • 47. Resiliência no processamento com Streams val input = spark.readStream .option("mode", "DROPMALFORMED") spark.sqlContext .setConf("spark.sql.files.ignoreCorruptFiles","true")
  • 48. Operações não Suportadas com Streams (DF/DS) ● Agregação de múltiplos Streams de dados ● Uso de LIMIT ou TAKE das primeiras N linhas ● Uso da instrução DISTINCT ● Operações de ordenação (parcialmente) em Output Mode Complete ● Operações de Outter Joins também não são suportadas