Apache Kafka och strömning av data med Spark Streaming

Hej, Habr! Idag ska vi bygga ett system som med hjÀlp av Spark Streaming behandlar meddelandeflöden frÄn Apache Kafka och skriver resultaten till en molndatabas, AWS RDS.

LÄt oss anta att en kreditorganisation stÀller oss inför uppgiften att behandla inkommande transaktioner "i realtid" för alla sina filialer. Detta kan göras för att snabbt berÀkna den öppna valutapositionen för kassan, grÀnser eller det finansiella resultatet för affÀrer, etc.

Hur man implementerar detta fall utan att anvĂ€nda magi och trollformler — lĂ€s vidare! LĂ„t oss köra!

Apache Kafka och strömning av data med Spark Streaming
(KĂ€lla till bilden)

Introduktion

SjÀlvklart erbjuder behandling av stora datamÀngder i realtid stora möjligheter för anvÀndning i moderna system. En av de mest populÀra kombinationerna för detta Àr tandem Apache Kafka och Spark Streaming, dÀr Kafka skapar en ström av inkommande meddelandepaket och Spark Streaming behandlar dessa paket under ett givet tidsintervall.

För att öka systemets tillförlitlighet kommer vi att anvÀnda checkpoints. Med denna mekanism behöver Spark Streaming-modulen, nÀr den behöver ÄterstÀlla förlorade data, bara ÄtervÀnda till den senaste kontrollpunkten och Äteruppta berÀkningarna dÀrifrÄn.

Arkitekturen för det utvecklade systemet

Apache Kafka och strömning av data med Spark Streaming

AnvÀnda komponenter:

  • Apache Kafka — Ă€r ett distribuerat meddelandebytesystem med publicering och prenumeration. Det Ă€r lĂ€mpligt för bĂ„de offline och online konsumption av meddelanden. För att förhindra dataloss sparas meddelanden frĂ„n Kafka pĂ„ disk och replikeras inom klustret. Kafka-systemet Ă€r byggt ovanpĂ„ ZooKeeper-tjĂ€nsten;
  • Apache Spark Streaming — komponenten Spark för bearbetning av strömmande data. Modulen Spark Streaming Ă€r byggd med hjĂ€lp av mikrobatch-arkitektur, dĂ€r en datastream tolkas som en kontinuerlig sekvens av smĂ„ datapaket. Spark Streaming tar emot data frĂ„n olika kĂ€llor och samlar dem i smĂ„ paket. Nya paket skapas med regelbundna tidsintervall. I början av varje tidsintervall skapas ett nytt paket, och all data som kommer in under detta intervall inkluderas i paketet. I slutet av intervallet upphör paketets tillvĂ€xt. Storleken pĂ„ intervallet bestĂ€ms av en parameter som kallas batchintervall;
  • Apache Spark SQL — förenar relationell bearbetning med funktionell programmering i Spark. Strukturerade data definieras som data som har ett schema, det vill sĂ€ga en enhetlig uppsĂ€ttning fĂ€lt för alla poster. Spark SQL stödjer indata frĂ„n mĂ„nga kĂ€llor med strukturerade data och, tack vare att schemainformation finns, kan det effektivt extrahera endast de nödvĂ€ndiga fĂ€lten i posterna samt tillhandahĂ„lla API-grĂ€nssnitt för DataFrame;
  • AWS RDS — en relativt billig molnrelaterad relationsdatabas, en webbtjĂ€nst som förenklar installation, drift och skalering, hanteras direkt av Amazon.

Installation och körning av Kafka-servern

Innan Kafka kan anvÀndas direkt, mÄste du sÀkerstÀlla att Java finns installerat, eftersom JVM anvÀnds för att köra det:

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

Skapa en ny anvÀndare för att arbeta med Kafka:

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

Ladda ner distributionspaketet frÄn Apache Kafkas officiella webbplats:

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

Packa upp den nedladdade arkivet:

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

NÀsta steg Àr valfritt. FrÄgan Àr att standardinstÀllningarna tillÄter inte att man fullt ut utnyttjar alla funktioner i Apache Kafka. Till exempel att ta bort en Àmne, kategori eller grupp som meddelanden kan publiceras pÄ. För att Àndra detta, redigera konfigurationsfilen:

vim ~/kafka/config/server.properties

LÀgg till följande i slutet av filen:

delete.topic.enable = true

Innan vi startar Kafka-servern, mÄste vi starta ZooKeeper-servern. Vi kommer att anvÀnda ett hjÀlpskript som följer med Kafka-distributionen:

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

NÀr ZooKeeper har startat framgÄngsrikt, starta Kafka-servern i ett separat terminalfönster:

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

LÄt oss skapa ett nytt Àmne med namnet Transaction:

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

Vi kontrollerar att Àmnet har skapats med rÀtt antal partitioner och replikering:

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

Apache Kafka och strömning av data med Spark Streaming

Vi hoppar över testmomentet för producer och konsument för det nyligen skapade Ă€mnet. Mer detaljerat om hur man kan testa att skicka och ta emot meddelanden stĂ„r i den officiella dokumentationen — Skicka nĂ„gra meddelanden. Men vi gĂ„r vidare till att skriva en producer pĂ„ Python med KafkaProducer API.

Skriv en producer

Producenten kommer att generera slumpmĂ€ssiga data – 100 meddelanden varje sekund. Med slumpmĂ€ssiga data menar vi en ordbok som bestĂ„r av tre fĂ€lt:

  • Filial – namnet pĂ„ försĂ€ljningsstĂ€llet för kreditorganisationen;
  • Valuta – valutakursen för transaktionen;
  • Belopp – beloppet för transaktionen. Beloppet kommer att vara ett positivt tal om det handlar om köp av valuta av banken, och negativt om det handlar om försĂ€ljning.

Koden för producenten ser ut som följande:

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

DÀrefter, med hjÀlp av metoden send, skickar vi meddelandet till servern, till det Àmne vi vill ha, 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('--> Meddelandet har skickats till ett Àmne: 
            {}, partition: {}, offset: {}' 
            .format(record_metadata.topic,
                record_metadata.partition,
                record_metadata.offset ))
                             
except Exception as e:
    print('--> Det verkar ha uppstÄtt ett fel: {}'.format(e))

finally:
    producer.flush()

NÀr skriptet körs fÄr vi följande meddelanden i terminalen:

Apache Kafka och strömning av data med Spark Streaming

Det betyder att allt fungerar som vi ville – producenten genererar och skickar meddelanden till det Ă€mne vi vill ha.
NÀsta steg blir att installera Spark och bearbeta denna ström av meddelanden.

Installation av Apache Spark

Apache Spark — Ă€r en mĂ„ngsidig och högpresterande klusterberĂ€kningsplattform.

NÀr det gÀller prestanda övertrÀffar Spark populÀra implementationer av MapReduce, samtidigt som det erbjuder stöd för en bredare uppsÀttning berÀkningstyper, inklusive interaktiva frÄgor och strömmande behandling. Hastighet spelar en viktig roll vid hantering av stora datamÀngder, eftersom hastigheten möjliggör interaktivt arbete utan att behöva vÀnta minuter eller timmar. En av de viktigaste fördelarna med Spark, som möjliggör denna höga hastighet, Àr dess förmÄga att utföra berÀkningar i minnet.

Denna ramverk Àr skriven i Scala, sÄ vi mÄste installera det först:

sudo apt-get install scala

Ladda ner Spark-distributionen frÄn den officiella webbplatsen:

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

Packa upp arkivet:

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

LÀgg till sökvÀgen till Spark i bash-filen:

vim ~/ .bashrc

LÀgg till följande rader via redigeraren:

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

Kör kommandot nedan efter att ha gjort Àndringar i bashrc:

source ~/ .bashrc

Distribution av AWS PostgreSQL

Det ÄterstÄr att distribuera databasen dÀr vi ska ladda upp den bearbetade informationen frÄn strömmarna. För detta kommer vi att anvÀnda tjÀnsten AWS RDS.

Logga in pĂ„ konsolen AWS —> AWS RDS —> Databaser —> Skapa databas:
Apache Kafka och strömning av data med Spark Streaming

VÀlj PostgreSQL och klicka pÄ knappen NÀsta:
Apache Kafka och strömning av data med Spark Streaming

Eftersom detta exempel endast behandlas för utbildningsÀndamÄl kommer vi att anvÀnda en gratis server "med minimala resurser" (Free Tier):
Apache Kafka och strömning av data med Spark Streaming

DĂ€refter markerar vi kryssrutan i blocket Free Tier, och efter det fĂ„r vi automatiskt ett instans av typen t2.micro – om Ă€n svagt, men gratis och helt tillrĂ€ckligt för vĂ„r uppgift:
Apache Kafka och strömning av data med Spark Streaming

Följande Àr mycket viktiga saker: namnet pÄ DB-instansen, namn pÄ huvud-anvÀndaren och hans lösenord. Vi döper instansen till: myHabrTest, huvud-anvÀndare: habr, lösenord: habr12345 och klickar pÄ knappen NÀsta:
Apache Kafka och strömning av data med Spark Streaming

PÄ nÀsta sida finns parametrarna som ansvarar för tillgÀngligheten av vÄr DB-server utifrÄn (Public accessibility) och tillgÀngligheten av portar:

Apache Kafka och strömning av data med Spark Streaming

LÄt oss skapa en ny instÀllning för VPC-sÀkerhetsgruppen, som tillÄter extern Ätkomst till vÄr DB-server via port 5432 (PostgreSQL).
LĂ„t oss gĂ„ till AWS-konsolen i ett separat webblĂ€sarfönster till VPC Dashboard —> SĂ€kerhetsgrupper —> Skapa sĂ€kerhetsgrupp:
Apache Kafka och strömning av data med Spark Streaming

Ange ett namn för Security group – PostgreSQL, en beskrivning, ange vilken VPC denna grupp ska associeras med och klicka pĂ„ knappen Skapa:
Apache Kafka och strömning av data med Spark Streaming

Fyll i den nyss skapade gruppens Inbound rules för port 5432, som visas pÄ bilden nedan. Porten behöver inte anges manuellt, utan kan vÀljas frÄn rullgardinsmenyn Typ som PostgreSQL.

Rent tekniskt betyder vÀrdet ::/0 att servern har tillgÄng till inkommande trafik frÄn hela vÀrlden, vilket kan anses vara lite missvisande, men för att förtydliga exemplet tillÄter vi oss att anvÀnda denna metod:
Apache Kafka och strömning av data med Spark Streaming

ÅtervĂ€nd till webblĂ€sarsidan dĂ€r vi har öppnat "Configure advanced settings" och vĂ€lj i avsnittet VPC security groups –> VĂ€lj befintliga VPC security groups –> PostgreSQL:
Apache Kafka och strömning av data med Spark Streaming

DĂ€refter, i avsnittet Databasalternativ –> Databasnamn –> ange namnet – habrDB.

Övriga parametrar, med undantag för eventuell avstĂ€ngning av backup (backup retention period – 0 days), övervakning och Performance Insights, kan lĂ€mnas som standard. Klicka pĂ„ knappen Skapa databas:
Apache Kafka och strömning av data med Spark Streaming

Strömhanterare

Det sista steget kommer att vara utvecklingen av en Spark-jobb, som varannan sekund kommer att bearbeta nya data som kommer frÄn Kafka och lagra resultatet i databasen.

Som nÀmnt ovan Àr checkpoints den grundlÀggande mekanismen i SparkStreaming, som mÄste stÀllas in för att sÀkerstÀlla fel tolerans. Vi kommer att anvÀnda checkpoints och, om processen kraschar, krÀvs det bara att ÄtervÀnda till den senaste checkpointen för att Äteruppta berÀkningarna.

Checkpointen kan aktiveras genom att stÀlla in en katalog i ett fel toleranta, pÄlitligt filsystem (t.ex. HDFS, S3 osv.), dÀr checkpointinformation sparas. Detta görs exempelvis med:

streamingContext.checkpoint(checkpointDirectory)

I vÄrt exempel kommer vi att anvÀnda följande tillvÀgagÄngssÀtt, nÀmligen, om checkpointDirectory finns, kommer kontexten att Äterskapas frÄn checkpointdata. Om katalogen inte finns (det vill sÀga körs första gÄngen), sÄ anropas funktionen functionToCreateContext för att skapa en ny kontext och stÀlla in DStreams:

from pyspark.streaming import StreamingContext

context = StreamingContext.getOrCreate(checkpointDirectory, functionToCreateContext)

Skapa ett objekt DirectStream för att ansluta till Àmnet "transaction" med hjÀlp av metoden createDirectStream frÄn KafkaUtils:

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

broker_list = 'localhost:9092'
topic = 'transaction'

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

Parsing av inkommande 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")

Vi anvÀnder Spark SQL för att göra en enkel gruppering och skriver ut resultatet i konsolen:

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

Vi fÄr texten av frÄgan och kör den genom Spark SQL:

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

Och sedan sparar vi de aggregerade data i en tabell i AWS RDS. För att spara aggregatresultaten i databastabellen anvÀnder vi metoden write för 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()

NÄgra ord om hur du konfigurerar anslutningen till AWS RDS. AnvÀndaren och lösenordet skapades i steg "Distribution av AWS PostgreSQL". För databasens serveradress bör du anvÀnda Endpoint som visas i avsnittet Connectivity & security:

Apache Kafka och strömning av data med Spark Streaming

För en korrekt koppling mellan Spark och Kafka bör jobben köras genom spark-submit med hjĂ€lp av artefaktet spark-streaming-kafka-0-8_2.11. Dessutom kommer vi Ă€ven att tillĂ€mpa artefakten för att interagera med PostgreSQL-databasen, som vi kommer att överföra via —packages.

För flexibiliteten i skriptet ska vi ocksÄ föra ut namnet pÄ meddelandeservern och Àmnet som ingÄngsparametrar frÄn vilket vi vill hÀmta data.

SÄ nu Àr det dags att köra och kontrollera 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 transaction

Det fungerade! Som du kan se pĂ„ bilden nedan — under applikationens drift visas nya aggregater var 2:a sekund, eftersom vi satte batchintervallet till 2 sekunder nĂ€r vi skapade StreamingContext-objektet:

Apache Kafka och strömning av data med Spark Streaming

DÀrefter gör vi en enkel frÄga till databasen för att kontrollera om det finns poster i tabellen transaction_flow:

Apache Kafka och strömning av data med Spark Streaming

Slutsats

I denna artikel granskades ett exempel pÄ strömmande informationsbehandling med hjÀlp av Spark Streaming i samarbete med Apache Kafka och PostgreSQL. Med den ökande mÀngden data frÄn olika kÀllor Àr det svÄrt att överskatta det praktiska vÀrdet av Spark Streaming för att skapa strömmande applikationer och applikationer som fungerar i realtid.

Den fullstÀndiga koden kan du hitta i mitt arkiv pÄ GitHub.

Jag ser fram emot att diskutera denna artikel, jag vÀntar pÄ dina kommentarer och hoppas Àven pÄ konstruktiv kritik frÄn alla intresserade lÀsare.

Jag önskar dig framgÄng!

Ps. Det var först planerat att anvÀnda en lokal PostgreSQL-databas, men med tanke pÄ min kÀrlek till AWS beslutade jag mig för att flytta databasen till molnet. I nÀsta artikel om detta Àmne kommer jag att visa hur man helt implementerar det ovan beskrivna systemet i AWS med hjÀlp av AWS Kinesis och AWS EMR. HÄll utkik efter nyheter!

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster