Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Hei Habr!

Vi minner om at etter boken om Kafka vi har publisert et like interessant verk om biblioteket Kafka Streams API.

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

For nå lærer samfunnet bare grensene for dette kraftige verktøyet. Så det ble nylig publisert en artikkel, som vi gjerne vil introdusere deg for oversettelsen av. Fra sin egen erfaring forteller forfatteren hvordan man gjør Kafka Streams til en distribuert datalagring. Liker å lese!

Apache bibliotek Kafka bekker brukes over hele verden i bedrifter for distribuert strømbehandling på toppen av Apache Kafka. Et av de undervurderte aspektene ved dette rammeverket er at det lar deg lagre lokalt produsert basert på trådbehandling.

I denne artikkelen vil jeg fortelle deg hvordan selskapet vårt klarte å bruke denne muligheten lønnsomt når de utviklet et produkt for skyapplikasjonssikkerhet. Ved å bruke Kafka Streams opprettet vi delte statlige mikrotjenester, som hver fungerer som en feiltolerant og svært tilgjengelig kilde til pålitelig informasjon om tilstanden til objekter i systemet. For oss er dette et fremskritt både når det gjelder pålitelighet og brukervennlighet.

Hvis du er interessert i en alternativ tilnærming som lar deg bruke en enkelt sentral database for å støtte den formelle tilstanden til objektene dine, les den, det vil være interessant...

Hvorfor vi trodde det var på tide å endre måten vi jobber med delt tilstand

Vi trengte å opprettholde tilstanden til ulike objekter basert på agentrapporter (for eksempel: var nettstedet under angrep)? Før vi migrerte til Kafka Streams, stolte vi ofte på en enkelt sentral database (+ tjeneste API) for statsadministrasjon. Denne tilnærmingen har sine ulemper: dato intensive situasjoner opprettholde konsistens og synkronisering blir en reell utfordring. Databasen kan bli en flaskehals eller havne i løpstilstand og lider av uforutsigbarhet.

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 1: Et typisk delt tilstandsscenario sett før overgangen til
Kafka og Kafka Streams: agenter kommuniserer sine synspunkter via API, oppdatert tilstand beregnes gjennom en sentral database

Møt Kafka Streams, noe som gjør det enkelt å lage delte statlige mikrotjenester

For omtrent et år siden bestemte vi oss for å ta en grundig titt på våre delte tilstandsscenarier for å løse disse problemene. Vi bestemte oss umiddelbart for å prøve Kafka Streams – vi vet hvor skalerbar, svært tilgjengelig og feiltolerant den er, og hvor rik dens strømmefunksjonalitet er (transformasjoner, inkludert tilstandsfulle). Akkurat det vi trengte, for ikke å snakke om hvor modent og pålitelig meldingssystemet har blitt i Kafka.

Hver av de stateful mikrotjenestene vi opprettet ble bygget på toppen av en Kafka Streams-forekomst med en ganske enkel topologi. Den besto av 1) en kilde 2) en prosessor med et vedvarende nøkkelverdilager 3) en vask:

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 2: Standardtopologien til strømmeforekomstene våre for stateful mikrotjenester. Merk at det også er et depot her som inneholder planleggingsmetadata.

I denne nye tilnærmingen komponerer agenter meldinger som mates inn i kildeemnet, og forbrukere – for eksempel en e-postvarslingstjeneste – mottar den beregnede delte tilstanden gjennom vasken (utdataemne).

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 3: Nytt eksempel på oppgaveflyt for et scenario med delte mikrotjenester: 1) agenten genererer en melding som kommer til Kafka-kildeemnet; 2) en mikrotjeneste med delt tilstand (ved hjelp av Kafka Streams) behandler den og skriver den beregnede tilstanden til det endelige Kafka-emnet; hvoretter 3) forbrukerne aksepterer den nye staten

Hei, denne innebygde nøkkelverdibutikken er faktisk veldig nyttig!

Som nevnt ovenfor inneholder vår delte tilstandstopologi et nøkkelverdilager. Vi fant flere alternativer for å bruke den, og to av dem er beskrevet nedenfor.

Alternativ 1: Bruk et nøkkelverdilager for beregninger

Vårt første nøkkelverdilager inneholdt hjelpedataene vi trengte for beregninger. For eksempel ble delstaten i noen tilfeller bestemt av prinsippet om "flertallsstemmer". Depotet kan inneholde alle de siste agentrapportene om statusen til et objekt. Så, når vi mottok en ny rapport fra en eller annen agent, kunne vi lagre den, hente rapporter fra alle andre agenter om tilstanden til det samme objektet fra lagring og gjenta beregningen.
Figur 4 nedenfor viser hvordan vi eksponerte nøkkel/verdilageret for prosessorens behandlingsmetode slik at den nye meldingen deretter kunne behandles.

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Illustrasjon 4: Vi åpner tilgang til nøkkelverdilageret for prosessorens behandlingsmetode (etter dette må hvert skript som fungerer med delt tilstand implementere metoden doProcess)

Alternativ #2: Opprette en CRUD API på toppen av Kafka Streams

Etter å ha etablert vår grunnleggende oppgaveflyt, begynte vi å prøve å skrive en RESTful CRUD API for våre delte statlige mikrotjenester. Vi ønsket å kunne hente tilstanden til noen eller alle objekter, samt angi eller fjerne tilstanden til et objekt (nyttig for backend-støtte).

For å støtte alle Get State APIer, når vi trengte å beregne tilstanden på nytt under behandlingen, lagret vi den i et innebygd nøkkelverdilager i lang tid. I dette tilfellet blir det ganske enkelt å implementere et slikt API ved å bruke en enkelt forekomst av Kafka Streams, som vist i listen nedenfor:

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 5: Bruk av det innebygde nøkkelverdilageret for å få den forhåndsberegnede tilstanden til et objekt

Å oppdatere tilstanden til et objekt via API er også enkelt å implementere. I utgangspunktet er alt du trenger å gjøre å lage en Kafka-produsent og bruke den til å lage en plate som inneholder den nye tilstanden. Dette sikrer at alle meldinger som genereres gjennom API vil bli behandlet på samme måte som de som mottas fra andre produsenter (f.eks. agenter).

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 6: Du kan angi tilstanden til et objekt ved hjelp av Kafka-produsenten

Liten komplikasjon: Kafka har mange partisjoner

Deretter ønsket vi å fordele behandlingsbelastningen og forbedre tilgjengeligheten ved å tilby en klynge av mikrotjenester med delt tilstand per scenario. Oppsettet var en lek: Når vi konfigurerte alle forekomster til å kjøre under samme applikasjons-ID (og de samme bootstrap-serverne), ble nesten alt annet gjort automatisk. Vi spesifiserte også at hvert kildeemne ville bestå av flere partisjoner, slik at hver forekomst kunne tilordnes et undersett av slike partisjoner.

Jeg vil også nevne at det er vanlig praksis å lage en sikkerhetskopi av den statlige butikken, slik at for eksempel, i tilfelle gjenoppretting etter en feil, overføre denne kopien til en annen instans. For hver statlig butikk i Kafka Streams opprettes et replikert emne med en endringslogg (som sporer lokale oppdateringer). Dermed backer Kafka hele tiden opp statsbutikken. Derfor, i tilfelle en svikt i en eller annen Kafka Streams-forekomst, kan statsbutikken raskt gjenopprettes på en annen forekomst, hvor de tilsvarende partisjonene vil gå. Våre tester har vist at dette er gjort i løpet av sekunder, selv om det er millioner av poster i butikken.

Å flytte fra en enkelt mikrotjeneste med delt tilstand til en klynge av mikrotjenester, blir det mindre trivielt å implementere Get State API. I den nye situasjonen inneholder statens lager for hver mikrotjeneste bare en del av det overordnede bildet (de objektene hvis nøkler ble tilordnet til en bestemt partisjon). Vi måtte bestemme hvilken forekomst som inneholdt tilstanden til objektet vi trengte, og vi gjorde dette basert på trådens metadata, som vist nedenfor:

Ikke bare prosessering: Hvordan vi laget en distribuert database fra Kafka Streams, og hva kom ut av det

Figur 7: Ved å bruke strømmetadata bestemmer vi fra hvilken instans vi skal spørre om tilstanden til ønsket objekt; en lignende tilnærming ble brukt med GET ALL API

Hovedfunn

Statlige butikker i Kafka Streams kan fungere som en de facto distribuert database,

  • stadig replikert i Kafka
  • Et CRUD API kan enkelt bygges på toppen av et slikt system
  • Å håndtere flere partisjoner er litt mer komplisert
  • Det er også mulig å legge til en eller flere tilstandslagre til streamingtopologien for å lagre hjelpedata. Dette alternativet kan brukes til:
  • Langtidslagring av data som trengs for beregninger under strømbehandling
  • Langtidslagring av data som kan være nyttig neste gang strømmeforekomsten klargjøres
  • mye mer...

Disse og andre fordeler gjør Kafka Streams godt egnet for å opprettholde global tilstand i et distribuert system som vårt. Kafka Streams har vist seg å være svært pålitelig i produksjon (vi har nesten ikke mistet meldinger siden vi ble distribuert det), og vi er sikre på at dets evner ikke vil stoppe der!

Kilde: www.habr.com

Legg til en kommentar