Hvordan Kafka ble virkelighet

Hvordan Kafka ble virkelighet

Hei Habr!

Jeg jobber pÄ Tinkoff-teamet, som utvikler sitt eget varslingssenter. Jeg utvikler for det meste i Java ved hjelp av Spring boot og lÞser ulike tekniske problemer som oppstÄr i et prosjekt.

De fleste av vÄre mikrotjenester kommuniserer med hverandre asynkront gjennom en meldingsmegler. Tidligere brukte vi IBM MQ som megler, som ikke lenger kunne takle belastningen, men samtidig hadde hÞye leveringsgarantier.

Som erstatning ble vi tilbudt Apache Kafka, som har hÞyt skaleringspotensial, men som dessverre krever en nesten individuell tilnÊrming til konfigurasjon for ulike scenarier. I tillegg tillot ikke leveringsmekanismen minst én gang som fungerer i Kafka som standard Ä opprettholde det nÞdvendige nivÄet av konsistens ut av esken. Deretter vil jeg dele vÄr erfaring med Kafka-konfigurasjon, spesielt vil jeg fortelle deg hvordan du konfigurerer og lever med nÞyaktig en gang levering.

Garantert levering og mer

Innstillingene diskutert nedenfor vil bidra til Ă„ forhindre en rekke problemer med standard tilkoblingsinnstillinger. Men fĂžrst vil jeg ta hensyn til en parameter som vil lette en mulig feilsĂžking.

Dette vil hjelpe klient-ID for produsent og forbruker. Ved fÞrste Þyekast kan du bruke applikasjonsnavnet som verdi, og i de fleste tilfeller vil dette fungere. Selv om situasjonen nÄr en applikasjon bruker flere forbrukere og du gir dem samme client.id, resulterer i fÞlgende advarsel:

org.apache.kafka.common.utils.AppInfoParser — Error registering AppInfo mbean javax.management.InstanceAlreadyExistsException: kafka.consumer:type=app-info,id=kafka.test-0

Hvis du vil bruke JMX i en applikasjon med Kafka, kan dette vÊre et problem. I dette tilfellet er det best Ä bruke en kombinasjon av applikasjonsnavnet og for eksempel emnenavnet som client.id-verdi. Resultatet av konfigurasjonen vÄr kan sees i kommandoutgangen kafka-forbrukergrupper fra verktÞy fra Confluent:

Hvordan Kafka ble virkelighet

La oss nÄ se pÄ scenariet for garantert meldingslevering. Kafka Producer har en parameter akks, som lar deg konfigurere etter hvor mange bekreftelser klyngelederen trenger for Ä vurdere meldingen som vellykket skrevet. Denne parameteren kan ha fÞlgende verdier:

  • 0 — anerkjenne vil ikke bli vurdert.
  • 1 er standardparameteren, bare 1 replika kreves for Ă„ bekrefte.
  • −1 — bekreftelse fra alle synkroniserte replikaer kreves (klyngeoppsett min.insync.replicas).

Fra de oppfÞrte verdiene er det klart at acks lik -1 gir den sterkeste garantien for at meldingen ikke gÄr tapt.

Som vi alle vet, er distribuerte systemer upÄlitelige. For Ä beskytte mot forbigÄende feil, tilbyr Kafka Producer alternativet prÞver pÄ nytt, som lar deg angi antall forsÞk pÄ Ä sende pÄ nytt innen leveringstidsavbrudd.ms. Siden gjenforsÞk-parameteren har en standardverdi pÄ Integer.MAX_VALUE (2147483647), kan antall gjenforsÞk pÄ meldinger justeres ved Ä endre levering.timeout.ms.

Vi gÄr mot nÞyaktig en gang levering

De oppfĂžrte innstillingene lar produsenten vĂ„r levere meldinger med hĂžy garanti. La oss nĂ„ snakke om hvordan vi sikrer at bare Ă©n kopi av en melding er skrevet til et Kafka-emne? I det enkleste tilfellet, for Ă„ gjĂžre dette, mĂ„ du sette parameteren pĂ„ Producer aktivere.idempotens til sant. Idempotens garanterer at kun Ă©n melding skrives til en bestemt partisjon av ett emne. Forutsetningen for Ă„ muliggjĂžre idempotens er verdiene acks = alle, prĂžv pĂ„ nytt > 0, maks.in.flight.requests.per.connection ≀ 5. Hvis disse parameterne ikke er spesifisert av utvikleren, vil verdiene ovenfor automatisk settes.

NĂ„r idempotens er konfigurert, er det nĂždvendig Ă„ sikre at de samme meldingene havner i de samme partisjonene hver gang. Dette kan gjĂžres ved Ă„ sette partitioner.class-nĂžkkelen og parameteren til Producer. La oss starte med nĂžkkelen. Det mĂ„ vĂŠre likt for hver innlevering. Dette kan enkelt oppnĂ„s ved Ă„ bruke hvilken som helst av forretnings-ID-ene fra det opprinnelige innlegget. Parameteren partitioner.class har en standardverdi − DefaultPartitioner. Med denne partisjoneringsstrategien fungerer vi som standard slik:

  • Hvis partisjonen er eksplisitt spesifisert nĂ„r du sender meldingen, bruker vi den.
  • Hvis partisjonen ikke er spesifisert, men nĂžkkelen er spesifisert, velg partisjonen ved hjelp av hashen til nĂžkkelen.
  • Hvis partisjonen og nĂžkkelen ikke er spesifisert, velg partisjonene Ă©n etter Ă©n (round-robin).

OgsÄ bruk av en nÞkkel og idempotent sending med en parameter max.in.flight.requests.per.connection = 1 gir deg strÞmlinjeformet meldingsbehandling pÄ Consumer. Det er ogsÄ verdt Ä huske at hvis tilgangskontroll er konfigurert pÄ klyngen din, vil du trenge rettigheter til Ä idempotent skrive til et emne.

Hvis du plutselig mangler evnene til idempotent sending med nÞkkel eller logikken pÄ produsentsiden krever Ä opprettholde datakonsistens mellom forskjellige partisjoner, vil transaksjoner komme til unnsetning. I tillegg, ved Ä bruke en kjedetransaksjon, kan du betinget synkronisere en post i Kafka, for eksempel med en post i databasen. For Ä muliggjÞre transaksjonssending til produsenten, mÄ den vÊre idempotent og i tillegg innstilt transaksjons-id. Hvis Kafka-klyngen din har tilgangskontroll konfigurert, vil en transaksjonspost, som en idempotent post, trenge skrivetillatelser, som kan gis med maske ved Ä bruke verdien lagret i transactional.id.

Formelt sett kan en hvilken som helst streng, for eksempel applikasjonsnavnet, brukes som en transaksjonsidentifikator. Men hvis du starter flere forekomster av samme applikasjon med samme transactional.id, vil den fĂžrste lanserte forekomsten bli stoppet med en feil, siden Kafka vil betrakte det som en zombieprosess.

org.apache.kafka.common.errors.ProducerFencedException: Producer attempted an operation with an old epoch. Either there is a newer producer with the same transactionalId, or the producer's transaction has been expired by the broker.

For Ă„ lĂžse dette problemet legger vi til et suffiks til applikasjonsnavnet i form av vertsnavnet, som vi henter fra miljĂžvariabler.

Produsenten er konfigurert, men transaksjoner pÄ Kafka kontrollerer bare omfanget av meldingen. Uavhengig av transaksjonsstatus, gÄr meldingen umiddelbart til emnet, men har flere systemattributter.

For Ä forhindre at slike meldinger blir lest av forbrukeren pÄ forhÄnd, mÄ den angi parameteren isolasjonsnivÄ til read_committed verdi. En slik forbruker vil vÊre i stand til Ä lese ikke-transaksjonelle meldinger som fÞr, og transaksjonsmeldinger kun etter en commit.
Hvis du har angitt alle innstillingene som er oppfĂžrt tidligere, har du konfigurert nĂžyaktig en gang levering. Gratulerer!

Men det er en nyanse til. Transactional.id, som vi konfigurerte ovenfor, er faktisk transaksjonsprefikset. PÄ transaksjonsbehandleren legges det til et sekvensnummer. Den mottatte identifikatoren utstedes til transaksjons-id.utlÞp.ms, som er konfigurert pÄ en Kafka-klynge og har en standardverdi pÄ "7 dager". Hvis applikasjonen i lÞpet av denne tiden ikke har mottatt noen meldinger, vil du motta den neste transaksjonssendingen nÄr du prÞver InvalidPidMappingException. Transaksjonskoordinator vil da utstede et nytt sekvensnummer for neste transaksjon. Meldingen kan imidlertid gÄ tapt hvis InvalidPidMappingException ikke hÄndteres pÄ riktig mÄte.

I stedet for totals

Som du kan se, er det ikke nok Ä bare sende meldinger til Kafka. Du mÄ velge en kombinasjon av parametere og vÊre forberedt pÄ Ä gjÞre raske endringer. I denne artikkelen prÞvde jeg Ä vise i detalj oppsettet for nÞyaktig levering én gang og beskrev flere problemer med client.id og transactional.id-konfigurasjonene som vi mÞtte. Nedenfor er et sammendrag av produsent- og forbrukerinnstillingene.

Producer:

  1. acks = alle
  2. prÞver pÄ nytt > 0
  3. enable.idempotence = sant
  4. max.in.flight.requests.per.connection ≀ 5 (1 for ryddig sending)
  5. transactional.id = ${application-name}-${vertsnavn}

Forbruker:

  1. isolation.level = read_committed

For Ä minimere feil i fremtidige applikasjoner, laget vi vÄr egen omslag over fjÊrkonfigurasjonen, der verdiene for noen av de listede parameterne allerede er satt.

Her er et par materialer for selvstudier:

Kilde: www.habr.com

KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KjĂžp pĂ„litelig webhotell med DDoS-beskyttelse, VPS VDS-servere | ProHoster