Apache Kafka og datastreaming med Spark Streaming

Hej, Habr! I dag skal vi bygge et system, der ved hjælp af Spark Streaming vil behandle beskedstrømme fra Apache Kafka og gemme resultaterne i en cloud-database, AWS RDS.

Lad os forestille os, at en kreditinstitution stiller os opgaven at behandle indkommende transaktioner "on the fly" i alle deres filialer. Dette kan gøres med det formål at beregne den åbne valuta-position for kassen, grænser eller det økonomiske resultat af handler osv.

Hvordan man realiserer denne brugssag uden at anvende magi og trylleformularer - læs videre! Lad os komme i gang!

Apache Kafka og datastreaming med Spark Streaming
(Kilde til billede)

Introduktion

Uden tvivl giver behandlingen af et stort datamængde i realtid omfattende muligheder for brug i moderne systemer. En af de mest populære kombinationer til dette er tandem Apache Kafka og Spark Streaming, hvor Kafka skaber en strøm af indkommende beskeder, mens Spark Streaming behandler disse pakker indenfor et bestemt tidsinterval.

For at øge applikationens fejltolerance vil vi bruge kontrolpunkter - checkpoints. Ved hjælp af denne mekanisme, når Spark Streaming-modulet skal genoprette tabte data, vil det kun være nødvendigt at vende tilbage til det seneste kontrolpunkt og genoptage beregningerne derfra.

Arkitekturen for det udviklede system

Apache Kafka og datastreaming med Spark Streaming

Brugte komponenter:

  • Apache Kafka — det er et distribueret beskedudvekslingssystem med publicering og abonnement. Det er egnet både til autonom og online forbrug af beskeder. For at forhindre datatab gemmes beskeder fra Kafka på disk og replikeres indenfor klyngen. Kafka-systemet er bygget oven på synkroniseringstjenesten ZooKeeper;
  • Apache Spark Streaming — komponenten Spark til behandling af streamede data. Spark Streaming-modulet er bygget med en "micro-batch" arkitektur, hvor streamen af data fortolkes som en kontinuerlig sekvens af små datapakker. Spark Streaming modtager data fra forskellige kilder og samler dem i små pakker. Nye pakker oprettes med regelmæssige tidsintervaller. I begyndelsen af hvert tidsinterval oprettes en ny pakke, og alle data, der er modtaget i løbet af dette interval, inkluderes i pakken. Ved slutningen af intervallet stopper stigningen af pakke. Størrelsen af intervallet bestemmes af en parameter kaldet batch interval;
  • Apache Spark SQL — kombinerer relationel behandling med funktionel programmering i Spark. Med strukturerede data menes der data, der har et skema, det vil sige et ensartet sæt felter for alle poster. Spark SQL understøtter input fra mange kilder til strukturerede data og takket være tilgængeligheden af skema-information kan det effektivt udtrække kun de nødvendige felter fra posterne samt levere DataFrame API'er;
  • AWS RDS — det er en relativt billig cloud-relational database, en webservice der forenkler opsætningen, driften og skaleringen, administreres direkte af Amazon.

Installation og opstart af Kafka-server

Før brug af Kafka skal man sikre, at Java er tilgængelig, da JVM anvendes:

sudo apt-get update 
sudo apt-get install default-jre
java -version

Lad os oprette en ny bruger til at arbejde med Kafka:

sudo useradd kafka -m
sudo passwd kafka
sudo adduser kafka sudo

Derefter downloader vi distributionen fra Apache Kafka's officielle hjemmeside:

wget -P /YOUR_PATH "http://apache-mirror.rbc.ru/pub/apache/kafka/2.2.0/kafka_2.12-2.2.0.tgz"

Udpak den downloadede arkiv:

tar -xvzf /YOUR_PATH/kafka_2.12-2.2.0.tgz
ln -s /YOUR_PATH/kafka_2.12-2.2.0 kafka

Det næste skridt er valgfrit. Faktisk tillader standardindstillingerne ikke fuld anvendelse af alle muligheder i Apache Kafka. For eksempel at slette emner, kategorier, grupper, som meddelelser kan offentliggøres til. For at ændre dette redigerer vi konfigurationsfilen:

vim ~/kafka/config/server.properties

Tilføj følgende til slutningen af filen:

delete.topic.enable = true

Inden du starter Kafka-serveren, skal ZooKeeper-serveren startes. Vi bruger et hjælpeprogram, der leveres med Kafka-distributionen:

Cd ~/kafka
bin/zookeeper-server-start.sh config/zookeeper.properties

Når ZooKeeper er startet korrekt, starter vi Kafka-serveren i et separat terminalvindue:

bin/kafka-server-start.sh config/server.properties

Lad os oprette et nyt emne kaldet Transaction:

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic transaction

Lad os sikre os, at emnet er oprettet med det rette antal partitioner og replikering:

bin/kafka-topics.sh --describe --zookeeper localhost:2181

Apache Kafka og datastreaming med Spark Streaming

Vi udelader testøjeblikke for producenten og forbrugeren til det nyligt oprettede emne. Mere detaljeret om, hvordan man kan teste sending og modtagelse af beskeder, står i den officielle dokumentation — Send nogle beskeder. Men vi går videre til at skrive producenten i Python ved hjælp af KafkaProducer API.

Skrive en producent

Producenten vil generere tilfældige data — 100 beskeder hvert sekund. Med tilfældige data mener vi et ordforråd bestående af tre felter:

  • Filial — navnet på salgsstedet for kreditinstitutionen;
  • Currency — valutaen for transaktionen;
  • Amount — beløbet for transaktionen. Beløbet vil være et positivt tal, hvis det er et køb af valuta fra banken, og negativt hvis det er et salg.

Koden til producenten ser således ud:

from numpy.random import choice, randint

def get_random_value():
    new_dict = {}

    branch_list = ['Kazan', 'SPB', 'Novosibirsk', 'Surgut']
    currency_list = ['RUB', 'USD', 'EUR', 'GBP']

    new_dict['branch'] = choice(branch_list)
    new_dict['currency'] = choice(currency_list)
    new_dict['amount'] = randint(-100, 100)

    return new_dict

Derefter, ved hjælp af metoden send, sender vi en besked til serveren i det ønskede emne, i JSON-format:

from kafka import KafkaProducer    

producer = KafkaProducer(bootstrap_servers=['localhost:9092'],
                             value_serializer=lambda x:dumps(x).encode('utf-8'),
                             compression_type='gzip')
my_topic = 'transaction'
data = get_random_value()

try:
    future = producer.send(topic = my_topic, value = data)
    record_metadata = future.get(timeout=10)
    
    print('--> Beskeden er sendt til et emne: 
            {}, partition: {}, offset: {}' 
            .format(record_metadata.topic,
                record_metadata.partition,
                record_metadata.offset ))   
                             
except Exception as e:
    print('--> Det ser ud til, at der er opstået en fejl: {}'.format(e))

finally:
    producer.flush()

Når scriptet køres, får vi følgende beskeder i terminalen:

Apache Kafka og datastreaming med Spark Streaming

Det betyder, at alt fungerer, som vi ønskede — producenten genererer og sender beskeder til det ønskede emne.
Næste skridt bliver at installere Spark og behandle denne strøm af beskeder.

Installation af Apache Spark

Apache Spark — er en alsidig og højtydende cluster computing platform.

I forhold til ydeevne overgår Spark populære implementeringer af MapReduce-modellen, samtidig med at der tilbydes support til et bredere udvalg af beregningstyper, herunder interaktive forespørgsler og streamingbehandling. Hastigheden spiller en vigtig rolle i behandlingen af store datamængder, da det netop er hastigheden, der muliggør interaktiv drift uden at bruge minutter eller timer på at vente. En af Spark's vigtigste fordele, der muliggør så høj hastighed, er evnen til at udføre beregninger i hukommelsen.

Denne ramme er skrevet i Scala, så det er nødvendigt først at installere det:

sudo apt-get install scala

Download distributionen af Spark fra det officielle websted:

wget "http://mirror.linux-ia64.org/apache/spark/spark-2.4.2/spark-2.4.2-bin-hadoop2.7.tgz"

Udpak arkivet:

sudo tar xvf spark-2.4.2/spark-2.4.2-bin-hadoop2.7.tgz -C /usr/local/spark

Tilføj stien til Spark i bash-filen:

vim ~/ .bashrc

Tilføj følgende linjer gennem editoren:

SPARK_HOME=/usr/local/spark
export PATH=$SPARK_HOME/bin:$PATH

Kør kommandoen nedenfor efter at have foretaget ændringerne i bashrc:

source ~/ .bashrc

Udrulning af AWS PostgreSQL

Det er tilbage at udrulle databasen, hvor vi vil indlæse de behandlede oplysninger fra strømme. For dette vil vi bruge tjenesten AWS RDS.

Gå til AWS konsollen —> AWS RDS —> Databases —> Opret database:
Apache Kafka og datastreaming med Spark Streaming

Vælg PostgreSQL og klik på knappen Næste:
Apache Kafka og datastreaming med Spark Streaming

Da dette eksempel kun behandles til uddannelsesmæssige formål, vil vi bruge en gratis server "på minimumsniveau" (Free Tier):
Apache Kafka og datastreaming med Spark Streaming

Derefter markerer vi afkrydsningsfeltet i blokken Free Tier, og efter dette vil vi automatisk få tilbudt en instans af typen t2.micro — selvom den er lidt svag, så er den gratis og helt passende til vores opgave:
Apache Kafka og datastreaming med Spark Streaming

Dernæst er der meget vigtige oplysninger: navnet på DB-instansen, navnet på master-brugeren og dens adgangskode. Vi kalder instansen: myHabrTest, master-bruger: habr, adgangskoden: habr12345 og klikker på knappen Næste:
Apache Kafka og datastreaming med Spark Streaming

På den næste side findes indstillingerne, der bestemmer tilgængeligheden af vores DB-server udefra (Public accessibility) og tilgængeligheden af porte:

Apache Kafka og datastreaming med Spark Streaming

Lad os oprette en ny indstilling for VPC security group, der tillader udefra adgang til vores DB-server via port 5432 (PostgreSQL).
Lad os åbne et nyt browservindue til AWS-konsollen i afsnittet VPC Dashboard —> Security Groups —> Opret security group:
Apache Kafka og datastreaming med Spark Streaming

Vi angiver et navn til sikkerhedsgruppen — PostgreSQL, en beskrivelse, angiver hvilken VPC denne gruppe skal være knyttet til, og klikker på knappen Opret:
Apache Kafka og datastreaming med Spark Streaming

Vi udfylder for den nyoprettede gruppe Indgående regler for port 5432, som vist på billedet nedenfor. Man behøver ikke at indtaste porten manuelt, men kan vælge PostgreSQL fra rullelisten Type.

Strengt taget betyder værdien ::/0 tilgængeligheden af indgående trafik til serveren fra hele verden, hvilket kan anses for at være lidt misvisende, men for eksemplets skyld vil vi tillade os at bruge denne tilgang:
Apache Kafka og datastreaming med Spark Streaming

Vi vender tilbage til browserens side, hvor vi har åbnet «Konfigurer avancerede indstillinger» og vælger i afsnittet VPC-sikkerhedsgrupper —> Vælg eksisterende VPC-sikkerhedsgrupper —> PostgreSQL:
Apache Kafka og datastreaming med Spark Streaming

Dernæst i afsnittet Databaseindstillinger —> Database navn —> angiver vi navnet — habrDB.

De øvrige parametre, bortset fra måske deaktivering af sikkerhedskopiering (backup retention period — 0 dage), overvågning og Performance Insights, kan vi lade stå som standard. Vi klikker på knappen Opret database:
Apache Kafka og datastreaming med Spark Streaming

Stream behandler

Det afsluttende trin vil være udviklingen af en Spark-job, der hver anden sekund behandler nye data, der kommer fra Kafka, og indsætter resultatet i databasen.

Som nævnt tidligere er kontrolpunkter (checkpoints) den primære mekanisme i Spark Streaming, som skal konfigureres for at sikre fejltolerance. Vi vil bruge kontrolpunkter, og i tilfælde af, at proceduren fejler, vil Spark Streaming-modulet til genopretning af tabte data kun skulle vende tilbage til det seneste kontrolpunkt og genoptage beregningerne derfra.

Kontrolpunktet kan aktiveres ved at angive en mappe i et fejltolerant, pålideligt filsystem (f.eks. HDFS, S3 osv.), hvor kontrolpunktsoplysningerne vil blive gemt. Dette gøres f.eks. ved:

streamingContext.checkpoint(checkpointDirectory)

I vores eksempel vil vi bruge følgende tilgang, nemlig hvis checkpointDirectory eksisterer, vil konteksten blive genskabt fra kontrolpunktsdataene. Hvis mappen ikke eksisterer (dvs. det udføres for første gang), kaldes funktionen functionToCreateContext for at oprette en ny kontekst og konfigurere DStreams:

from pyspark.streaming import StreamingContext

context = StreamingContext.getOrCreate(checkpointDirectory, functionToCreateContext)

Vi opretter et DirectStream-objekt med henblik på at oprette forbindelse til emnet «transaction» ved hjælp af metoden createDirectStream fra KafkaUtils-biblioteket:

fra pyspark.streaming.kafka import KafkaUtils
    
sc = SparkContext(conf=conf)
ssc = StreamingContext(sc, 2)

broker_list = 'localhost:9092'
topic = 'transaktion'

directKafkaStream = KafkaUtils.createDirectStream(ssc,
                                [topic],
                                {"metadata.broker.list": broker_list})

Vi parser indkommende data i JSON-format:

rowRdd = rdd.map(lambda w: Row(branch=w['branch'],
                                       currency=w['currency'],
                                       amount=w['amount']))
                                       
testDataFrame = spark.createDataFrame(rowRdd)
testDataFrame.createOrReplaceTempView("treasury_stream")

Ved hjælp af Spark SQL udfører vi en enkel gruppering og viser resultatet i konsollen:

select 
    from_unixtime(unix_timestamp()) as curr_time,
    t.branch                        as branch_name,
    t.currency                      as currency_code,
    sum(amount)                     as batch_value
from treasury_stream t
group by
    t.branch,
    t.currency

Hent teksten fra forespørgslen og kør den via Spark SQL:

sql_query = get_sql_query()
testResultDataFrame = spark.sql(sql_query)
testResultDataFrame.show(n=5)

Og så gemmer vi de aggregerede data i en tabel i AWS RDS. For at gemme aggregationsresultaterne i databasen vil vi bruge write-metoden på DataFrame-objektet:

testResultDataFrame.write 
    .format("jdbc") 
    .mode("append") 
    .option("driver", 'org.postgresql.Driver') 
    .option("url","jdbc:postgresql://myhabrtest.ciny8bykwxeg.us-east-1.rds.amazonaws.com:5432/habrDB") 
    .option("dbtable", "transaction_flow") 
    .option("user", "habr") 
    .option("password", "habr12345") 
    .save()

Nogle ord om opsætning af forbindelsen til AWS RDS. Brugernavn og adgangskode til den blev oprettet i trin "Udrulning af AWS PostgreSQL". Som URL til databasen skal vi bruge den Endpoint, der vises under Connectivity & security:

Apache Kafka og datastreaming med Spark Streaming

For korrekt integration af Spark og Kafka skal opgaven køres via spark-submit med brug af artefakten spark-streaming-kafka-0-8_2.11. Derudover anvender vi også artefakten til interaktion med PostgreSQL-database, som vi vil overføre via —packages.

For at gøre scriptet mere fleksibelt, vil vi også tage navnet på beskedserveren og det emne, vi ønsker at modtage data fra, som indtastningsparametre.

Så er det tid til at starte og teste systemets funktionalitet:

spark-submit 
--packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.0.2,
org.postgresql:postgresql:9.4.1207 
spark_job.py localhost:9092 transaktion

Det lykkedes! Som vist på billedet nedenfor — under anvendelse af applikationen vises de nye aggregationsresultater hvert 2. sekund, fordi vi har sat pakkeintervallet til 2 sekunder, da vi oprettede StreamingContext-objektet:

Apache Kafka og datastreaming med Spark Streaming

Derudover laver vi en simpel forespørgsel til databasen for at kontrollere, om der er poster i tabellen transaction_flow:

Apache Kafka og datastreaming med Spark Streaming

Konklusion

I denne artikel blev der præsenteret et eksempel på strømningsbehandling af information ved hjælp af Spark Streaming i samarbejde med Apache Kafka og PostgreSQL. Med den stigende mængde data fra forskellige kilder er det svært at overvurdere den praktiske værdi af Spark Streaming til at skabe streamingapplikationer og applikationer, der fungerer i realtid.

Den fulde kildekode kan findes i mit repository på GitHub.

Jeg ser frem til at diskutere denne artikel, og jeg ser frem til jeres kommentarer samt håber på konstruktiv kritik fra alle interesserede læsere.

Jeg ønsker dig held og lykke!

Ps. Oprindeligt var det planlagt at bruge en lokal database PostgreSQL, men i betragtning af min kærlighed til AWS besluttede jeg at flytte databasen til skyen. I den næste artikel om dette emne vil jeg vise, hvordan man implementerer hele det ovenfor beskrevne system i AWS ved hjælp af AWS Kinesis og AWS EMR. Hold øje med nyhederne!

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster