RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed

В sidste artikel vi så på RabbitMQ-klynger for fejltolerance og høj tilgængelighed. Lad os nu grave dybt i Apache Kafka.

Her er replikationsenheden partitionen. Hvert emne har et eller flere afsnit. Hver sektion har en leder med eller uden følgere. Når du opretter et emne, angiver du antallet af partitioner og replikeringskoefficienten. Den sædvanlige værdi er 3, hvilket betyder tre replikaer: en leder og to følgere.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 1. Fire sektioner er fordelt på tre mæglere

Alle læse- og skriveanmodninger går til lederen. Følgere sender med jævne mellemrum anmodninger til lederen om at modtage de seneste beskeder. Forbrugere henvender sig aldrig til følgere; sidstnævnte eksisterer kun for redundans og fejltolerance.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed

Partitionsfejl

Når en mægler fejler, fejler lederne af flere sektioner ofte. I hver af dem bliver en følger fra en anden knude leder. Det er faktisk ikke altid tilfældet, da synkroniseringsfaktoren også har indflydelse på: om der er synkroniserede følgere, og hvis ikke, om det så er tilladt at skifte til en usynkroniseret replika. Men lad os ikke komplicere tingene lige nu.

Mægler 3 forlader netværket, og der vælges en ny leder for sektion 2 hos mægler 2.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 2. Mægler 3 dør og hans følger på mægler 2 vælges som ny leder af parti 2

Så forlader mægler 1 og sektion 1 mister også sin leder, hvis rolle overgår til mægler 2.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 3. Der er en mægler tilbage. Alle ledere er på én mægler med nul redundans

Når mægler 1 kommer online igen, tilføjer den fire følgere, hvilket giver en vis redundans til hver partition. Men alle lederne forblev stadig på mægler 2.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 4. Ledere forbliver på mægler 2

Når broker 3 dukker op, er vi tilbage til tre replikaer pr. partition. Men alle lederne er stadig på mægler 2.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 5. Ubalanceret placering af ledere efter restaurering af mægler 1 og 3

Kafka har et værktøj til bedre lederrebalancering end RabbitMQ. Der skulle du bruge et tredjeparts plugin eller script, der ændrede politikkerne for migrering af masterknudepunktet ved at reducere redundans under migrering. Derudover måtte vi for store køer acceptere utilgængelighed under synkronisering.

Kafka har begrebet "foretrukne replikaer" til lederrollen. Når emneopdelinger oprettes, forsøger Kafka at fordele ledere jævnt på tværs af noder og markerer de første ledere som foretrukne. Over tid, på grund af servergenstart, fejl og forbindelsesnedbrud, kan ledere ende på andre noder, som i det ekstreme tilfælde beskrevet ovenfor.

For at rette op på dette tilbyder Kafka to muligheder:

  • valgmulighed auto.leader.rebalance.enable=true gør det muligt for controller-noden automatisk at omplacere ledere tilbage til foretrukne replikaer og derved genoprette ensartet fordeling.
  • Administratoren kan køre scriptet kafka-preferred-replica-election.sh til manuel omplacering.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 6. Replikaer efter rebalancering

Dette var en forenklet version af fiaskoen, men virkeligheden er mere kompleks, selvom der ikke er noget for kompliceret her. Det hele kommer ned til synkroniserede replikaer (In-Sync Replicas, ISR).

Synkroniserede replikaer (ISR)

En ISR er et sæt replikaer af en partition, der betragtes som "synkroniseret" (synkroniseret). Der er en leder, men der er måske ikke tilhængere. En følger betragtes som synkroniseret, hvis den har lavet nøjagtige kopier af alle lederens beskeder inden intervallet udløber replika.forsinkelsestid.maks.ms.

En følger fjernes fra ISR-sættet, hvis den:

  • fremsatte ikke en anmodning om at vælge for intervallet replika.forsinkelsestid.maks.ms (formodes død)
  • nåede ikke at opdatere i intervallet replika.forsinkelsestid.maks.ms (betragtes som langsom)

Følgere foretager prøveudtagningsanmodninger i intervallet replica.fetch.wait.max.ms, som er standard til 500ms.

For klart at forklare formålet med ISR er vi nødt til at se på bekræftelser fra producenten og nogle fejlscenarier. Producenterne kan vælge, hvornår mægleren sender bekræftelse:

  • acks=0, bekræftelse sendes ikke
  • acks=1, bekræftelse sendes efter at lederen har skrevet besked til sin lokale log
  • acks=all, bekræftelse sendes efter at alle replikaer i ISR ​​har skrevet beskeden til de lokale logfiler

I Kafka-terminologi, hvis ISR har gemt en besked, er den "committed". Acks=all er den sikreste mulighed, men tilføjer også yderligere forsinkelse. Lad os se på to eksempler på fiasko, og hvordan de forskellige 'acks'-muligheder interagerer med ISR-konceptet.

Acks=1 og ISR

I dette eksempel vil vi se, at hvis lederen ikke venter på, at hver besked fra alle følgere bliver gemt, så er datatab muligt, hvis lederen fejler. Navigering til en usynkroniseret følger kan aktiveres eller deaktiveres ved indstilling uren.leder.valg.aktivere.

I dette eksempel har producenten værdien acks=1. Afsnittet er fordelt på alle tre mæglere. Broker 3 er bagud, den synkroniserede med lederen for otte sekunder siden og er nu 7456 beskeder bagud. Mægler 1 var kun et sekund efter. Vores producer sender en besked og modtager hurtigt et ack tilbage, uden overhead af langsomme eller døde følgere, som lederen ikke venter på.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 7. ISR med tre replikaer

Broker 2 fejler, og producenten modtager en forbindelsesfejl. Efter ledelsen er overgået til mægler 1, mister vi 123 beskeder. Følgeren på broker 1 var en del af ISR, men var ikke fuldt synkroniseret med lederen, da den faldt.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 8. Beskeder går tabt, når den går ned

I konfiguration bootstrap.servere Producenten har flere mæglere opført og kan spørge en anden mægler, som er ny sektionsleder. Den etablerer derefter en forbindelse til mægler 1 og fortsætter med at sende beskeder.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 9. Afsendelse af beskeder genoptages efter en kort pause

Broker 3 er endnu længere bagud. Den foretager hentningsanmodninger, men kan ikke synkronisere. Dette kan skyldes langsom netværksforbindelse mellem mæglere, lagringsproblem osv. Det fjernes fra ISR. Nu består ISR af én replika - lederen! Producenten fortsætter med at sende beskeder og modtage bekræftelser.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 10. Følger på mægler 3 fjernes fra ISR

Mægler 1 går ned, og lederrollen går til mægler 3 med tab af 15286 beskeder! Producenten modtager en forbindelsesfejlmeddelelse. Overgangen til en leder uden for ISR var kun mulig på grund af indstillingen unclean.leader.election.enable=sand. Hvis det er installeret i falsk, så ville overgangen ikke finde sted, og alle læse- og skriveanmodninger ville blive afvist. I dette tilfælde venter vi på, at mægler 1 vender tilbage med sine intakte data i replikaen, som igen vil overtage ledelsen.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 11. Mægler 1 falder. Når der opstår en fejl, går et stort antal meddelelser tabt

Producenten etablerer forbindelse med den sidste mægler og ser, at han nu er leder af sektionen. Han begynder at sende beskeder til mægler 3.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 12. Efter en kort pause sendes beskeder igen til afsnit 0

Vi så, at bortset fra korte afbrydelser for at etablere nye forbindelser og søge efter en ny leder, sendte producenten konstant beskeder. Denne konfiguration sikrer tilgængelighed på bekostning af konsistens (datasikkerhed). Kafka mistede tusindvis af beskeder, men fortsatte med at acceptere nye skriverier.

Acks=alle og ISR

Lad os gentage dette scenarie igen, men med acks=alle. Broker 3 har en gennemsnitlig latenstid på fire sekunder. Producenten sender en besked med acks=alle, og modtager nu ikke et hurtigt svar. Lederen venter på, at beskeden bliver gemt af alle replikaer i ISR.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 13. ISR med tre kopier. Den ene er langsom, hvilket resulterer i optagelsesforsinkelser

Efter fire sekunders yderligere forsinkelse sender mægler 2 et kvittering. Alle replikaer er nu fuldt opdateret.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 14. Alle replikaer gemmer beskeder og sender ack

Broker 3 falder nu længere bagud og fjernes fra ISR. Latency reduceres betydeligt, fordi der ikke er nogen langsomme replikaer tilbage i ISR. Mægler 2 venter nu kun på mægler 1, og han har en gennemsnitlig forsinkelse på 500 ms.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 15. Replikaen på mægler 3 fjernes fra ISR

Så falder mægler 2, og ledelsen overgår til mægler 1 uden tab af beskeder.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 16. Mægler 2 falder

Producenten finder en ny leder og begynder at sende beskeder til ham. Latensen er yderligere reduceret, fordi ISR ​​nu består af én replika! Derfor muligheden acks=alle tilføjer ikke redundans.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 17. Replika på broker 1 tager føringen uden at miste beskeder

Så går mægler 1 ned, og føringen går til mægler 3 med et tab på 14238 beskeder!

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 18. Broker 1 dør og lederskabsovergang med urene omgivelser resulterer i omfattende datatab

Vi kunne ikke installere muligheden uren.leder.valg.aktivere i betydning sand. Som standard er det ens falsk. Indstillinger acks=alle с unclean.leader.election.enable=sand giver tilgængelighed med en vis ekstra datasikkerhed. Men som du kan se, kan vi stadig miste beskeder.

Men hvad nu hvis vi vil øge datasikkerheden? Du kan sætte unclean.leader.election.enable = falsk, men dette vil ikke nødvendigvis beskytte os mod tab af data. Hvis lederen faldt hårdt og tog dataene med sig, så er beskeder stadig tabt, plus tilgængelighed går tabt, indtil administratoren genopretter situationen.

Det er bedre at sikre, at alle beskeder er overflødige, og ellers kassere optagelsen. Så er datatab, i hvert fald fra mæglerens synspunkt, kun muligt i tilfælde af to eller flere samtidige fejl.

Acks=all, min.insync.replicas og ISR

Med emne konfiguration min.insync.replikaer Vi øger niveauet af datasikkerhed. Lad os gennemgå den sidste del af det forrige scenarie igen, men denne gang med min.insync.replicas=2.

Så mægler 2 har en replika-leder, og følgeren på mægler 3 fjernes fra ISR.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 19. ISR fra to kopier

Mægler 2 falder, og ledelsen overgår til mægler 1 uden tab af beskeder. Men nu består ISR kun af én replika. Dette opfylder ikke minimumsantallet for at modtage poster, og derfor reagerer mægleren på skriveforsøget med en fejl Ikke nok replikaer.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 20. Antallet af ISR'er er én lavere end angivet i min.insync.replicas

Denne konfiguration ofrer tilgængelighed for konsistens. Før vi bekræfter en besked, sikrer vi, at den er skrevet til mindst to replikaer. Dette giver producenten meget mere selvtillid. Her er beskedtab kun muligt, hvis to replikaer fejler samtidigt i et kort interval, indtil beskeden replikeres til en ekstra følger, hvilket er usandsynligt. Men hvis du er super paranoid, kan du indstille replikationsfaktoren til 5, og min.insync.replikaer med 3. Her skal tre mæglere falde på samme tid for at miste rekorden! Selvfølgelig betaler du for denne pålidelighed i yderligere latenstid.

Når tilgængelighed er nødvendig for datasikkerhed

Som i etui med RabbitMQ, nogle gange er tilgængelighed nødvendig for datasikkerhed. Her er hvad du skal tænke over:

  • Kan udgiveren blot returnere en fejl og få upstream-tjenesten eller brugeren til at prøve igen senere?
  • Kan udgiveren gemme meddelelsen lokalt eller i en database for at prøve igen senere?

Hvis svaret er nej, forbedrer optimering af tilgængeligheden datasikkerheden. Du mister mindre data, hvis du vælger tilgængelighed i stedet for ikke at optage. Det hele handler således om at finde en balance, og beslutningen afhænger af den konkrete situation.

Betydningen af ​​ISR

ISR-pakken giver dig mulighed for at vælge den optimale balance mellem datasikkerhed og latenstid. For eksempel skal du sikre tilgængelighed i tilfælde af fejl i de fleste replikaer, minimere virkningen af ​​døde eller langsomme replikaer med hensyn til latenstid.

Vi vælger selv meningen replika.forsinkelsestid.maks.ms efter dine behov. I det væsentlige betyder denne parameter, hvor meget forsinkelse vi er villige til at acceptere hvornår acks=alle. Standardværdien er ti sekunder. Hvis dette er for langt for dig, kan du reducere det. Så vil hyppigheden af ​​ændringer i ISR ​​stige, da følgere vil blive fjernet og tilføjet oftere.

RabbitMQ er simpelthen et sæt spejle, der skal replikeres. Langsomme spejle introducerer yderligere latenstid, og døde spejle kan vente, indtil de pakker, der kontrollerer tilgængeligheden af ​​hver node (nettick), reagerer. ISR er en interessant måde at undgå disse latensproblemer på. Men vi risikerer at miste redundans, da ISR kun kan skrumpe ind til lederen. Brug indstillingen for at undgå denne risiko min.insync.replikaer.

Kundeforbindelsesgaranti

I indstillinger bootstrap.servere producent og forbruger kan angive flere mæglere til at forbinde kunder. Tanken er, at når en node går ned, er der flere reservedele tilbage, som klienten kan åbne en forbindelse med. Disse er ikke nødvendigvis sektionsledere, men blot et springbræt til indledende læsning. Klienten kan spørge dem, hvilken node der er vært for læse/skrive partitionslederen.

I RabbitMQ kan klienter oprette forbindelse til enhver node, og intern routing sender anmodningen derhen, hvor den skal hen. Det betyder, at du kan installere en load balancer foran RabbitMQ. Kafka kræver, at klienter opretter forbindelse til den node, der er vært for den tilsvarende partitionsleder. I en sådan situation kan du ikke installere en load balancer. Liste bootstrap.servere Det er afgørende, at klienter kan få adgang til og finde de korrekte noder efter en fejl.

Kafka konsensusarkitektur

Indtil nu har vi ikke overvejet, hvordan klyngen lærer om mæglerens fald, og hvordan en ny leder vælges. For at forstå, hvordan Kafka arbejder med netværkspartitioner, skal du først forstå konsensusarkitekturen.

Hver Kafka-klynge er implementeret sammen med en Zookeeper-klynge, som er en distribueret konsensustjeneste, der gør det muligt for systemet at nå konsensus om en given tilstand, idet der prioriteres konsistens frem for tilgængelighed. Der kræves samtykke fra et flertal af Zookeeper-noder for at godkende læse- og skriveoperationer.

Zookeeper gemmer klyngens tilstand:

  • Liste over emner, sektioner, konfiguration, aktuelle lederreplikaer, foretrukne replikaer.
  • Klyngemedlemmer. Hver mægler pinger Zookeeper-klyngen. Hvis den ikke modtager et ping inden for et bestemt tidsrum, registrerer Zookeeper mægleren som utilgængelig.
  • Valg af hoved- og reserveknudepunkter til controlleren.

Controllernoden er en af ​​Kafka-mæglerne, der er ansvarlig for at vælge replika-ledere. Zookeeper sender meddelelser til controlleren om klyngemedlemskab og emneændringer, og controlleren skal handle på disse ændringer.

Lad os for eksempel tage et nyt emne med ti partitioner og en replikeringsfaktor på 3. Controlleren skal vælge en leder for hver partition, og forsøge at fordele lederne optimalt blandt mæglerne.

For hver sektionscontroller:

  • opdaterer oplysninger i Zookeeper om ISR og leder;
  • Sender en LeaderAndISRCommand til hver mægler, der er vært for en replika af denne partition, og informerer mæglerne om ISR'en og lederen.

Når en mægler med en leder falder, sender Zookeeper en meddelelse til controlleren, og den vælger en ny leder. Igen opdaterer controlleren først Zookeeper og sender derefter en kommando til hver mægler, der underretter dem om ledelsesændringen.

Hver leder er ansvarlig for at rekruttere ISR'er. Indstillinger replika.forsinkelsestid.maks.ms bestemmer, hvem der kommer ind der. Når ISR ændres, sender lederen ny information til Zookeeper.

Zookeeper bliver altid informeret om eventuelle ændringer, så ledelsen i tilfælde af fejl overgår problemfrit til en ny leder.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 21. Kafka-konsensus

Replikationsprotokol

At forstå detaljerne i replikering hjælper dig med bedre at forstå potentielle datatabsscenarier.

Sampling forespørgsler, Log End Offset (LEO) og Highwater Mark (HW)

Vi overvejede, at følgere med jævne mellemrum sender anmodninger om hentning til lederen. Standardintervallet er 500ms. Dette adskiller sig fra RabbitMQ ved, at replikering i RabbitMQ ikke initieres af køspejlet, men af ​​masteren. Mesteren skubber ændringer til spejlene.

Lederen og alle følgere gemmer Log End Offset (LEO) og Highwater (HW)-mærket. LEO-mærket gemmer forskydningen af ​​den sidste besked i den lokale replika, og HW'en holder forskydningen af ​​den sidste commit. Husk, at for forpligtelsesstatus skal meddelelsen fortsættes på tværs af alle ISR-replikaer. Det betyder, at LEO normalt er lidt foran HW.

Når lederen modtager en besked, gemmer den den lokalt. Følgeren laver en hentningsanmodning ved at sende sin LEO. Lederen sender derefter en batch af meddelelser startende fra denne LEO og transmitterer også den aktuelle HW. Når lederen modtager information om, at alle replikaer har gemt beskeden ved den givne offset, flytter den HW-mærket. Kun lederen kan flytte HW, og så vil alle følgere kende den aktuelle værdi i svarene på deres anmodning. Det betyder, at følgere kan halte bagefter lederen i både budskab og HW viden. Forbrugere modtager kun beskeder op til den aktuelle HW.

Bemærk, at "vedvarende" betyder skrevet til hukommelsen, ikke til disken. For ydeevne synkroniserer Kafka til disk med et bestemt interval. RabbitMQ har også et sådant interval, men det vil først sende en bekræftelse til udgiveren, når masteren og alle spejle har skrevet beskeden til disken. Kafka-udviklerne besluttede af præstationsmæssige årsager at sende en ack, så snart beskeden er skrevet i hukommelsen. Kafka satser på, at redundans opvejer risikoen for kortvarig lagring af bekræftede beskeder kun i hukommelsen.

Leder fiasko

Når en leder falder, underretter Zookeeper controlleren, og den vælger en ny leder-replika. Den nye leder sætter et nyt HW-mærke i henhold til sin LEO. Følgere modtager derefter information om den nye leder. Afhængigt af versionen af ​​Kafka vil følgeren vælge et af to scenarier:

  1. Den vil afkorte den lokale log til en kendt HW og sende en anmodning til den nye leder om beskeder efter dette mærke.
  2. Vil sende en anmodning til lederen om at finde ud af HW på det tidspunkt, han blev valgt til leder, og derefter afkorte loggen til denne offset. Den vil derefter begynde at foretage periodiske hentningsanmodninger, der starter med denne offset.

En følger kan være nødt til at afkorte loggen af ​​følgende årsager:

  • Når en leder fejler, vinder den første følger i ISR-sættet, der er registreret hos Zookeeper valget og bliver leder. Alle følgere på ISR, selvom de betragtes som "synkroniserede", har muligvis ikke modtaget kopier af alle beskeder fra den tidligere leder. Det er helt muligt, at den fremhævede følger ikke har den mest opdaterede kopi. Kafka sikrer, at der ikke er nogen divergens mellem replikaer. For at undgå uoverensstemmelser skal hver følger afkorte sin log til HW-værdien for den nye leder på tidspunktet for hans valg. Dette er en anden grund til at indstille acks=alle så vigtigt for konsistensen.
  • Meddelelser skrives med jævne mellemrum til disk. Hvis alle klynge noder fejler på samme tid, vil replikaer med forskellige forskydninger blive gemt på diskene. Det er muligt, at når mæglere kommer online igen, vil den nye leder, der bliver valgt, stå bag sine følgere, fordi han blev gemt på disk før de andre.

Gensyn med klyngen

Når replikaerne slutter sig til klyngen igen, gør de det samme, som når en leder fejler: de tjekker lederens replika og afkorter deres log til dens HW (på valgtidspunktet). Til sammenligning behandler RabbitMQ på samme måde genforenede noder som helt nye. I begge tilfælde kasserer mægleren enhver eksisterende tilstand. Hvis automatisk synkronisering bruges, så skal masteren replikere absolut alt nuværende indhold til det nye spejl i en "lad hele verden vente"-metoden. Masteren accepterer ikke nogen læse- eller skrivehandlinger under denne operation. Denne tilgang skaber problemer i store køer.

Kafka er en distribueret log, og generelt gemmer den flere beskeder end en RabbitMQ-kø, hvor data fjernes fra køen, efter at de er læst. Aktive køer bør forblive relativt små. Men Kafka er en log med sin egen opbevaringspolitik, som kan indstille en periode på dage eller uger. Tilgangen til køblokering og fuld synkronisering er absolut uacceptabel for en distribueret log. I stedet for afkorter Kafka-tilhængere simpelthen deres log til lederens HW (på tidspunktet for hans valg), hvis deres kopi er foran lederen. I det mere sandsynlige tilfælde, når følgeren er bagud, begynder den simpelthen at lave henteanmodninger, der starter med sin nuværende LEO.

Nye eller gentilsluttede følgere starter uden for ISR og deltager ikke i commits. De arbejder simpelthen sammen med gruppen og modtager beskeder så hurtigt som de kan, indtil de indhenter lederen og går ind i ISR. Der er ingen låsning og ingen grund til at smide alle dine data væk.

Tab af forbindelse

Kafka har flere komponenter end RabbitMQ, så den har et mere komplekst sæt af adfærd, når klyngen bliver afbrudt. Men Kafka er oprindeligt designet til klynger, så løsningerne er meget gennemtænkte.

Nedenfor er flere scenarier for forbindelsesfejl:

  • Scenario 1: Følgeren ser ikke lederen, men ser stadig dyrepasseren.
  • Scenarie 2: Lederen ser ingen følgere, men ser stadig Zookeeper.
  • Scenarie 3: Tilhængeren ser lederen, men ser ikke dyrepasseren.
  • Scenarie 4: Lederen ser følgerne, men ser ikke dyrepasseren.
  • Scenarie 5: Følgeren er fuldstændig adskilt fra både andre Kafka-noder og Zookeeper.
  • Scenario 6: Lederen er fuldstændig adskilt fra både andre Kafka-noder og Zookeeper.
  • Scenario 7: Kafka-controllernoden kan ikke se en anden Kafka-knude.
  • Scenarie 8: Kafka-controlleren kan ikke se Zookeeper.

Hvert scenarie har sin egen adfærd.

Scenarie 1: Følgeren ser ikke lederen, men ser stadig Zookeeper

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 22. Scenario 1: ISR af tre replikaer

Forbindelsesfejlen adskiller mægler 3 fra mægler 1 og 2, men ikke fra Zookeeper. Broker 3 kan ikke længere sende hentningsanmodninger. Efter at tiden er gået replika.forsinkelsestid.maks.ms den fjernes fra ISR'en og deltager ikke i meddelelsescommits. Når forbindelsen er genoprettet, genoptager den henteanmodninger og slutter sig til ISR'en, når den indhenter lederen. Zookeeper vil fortsat modtage ping og antage, at mægleren lever og har det godt.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 23. Scenarie 1: Mægleren fjernes fra ISR'en, hvis der ikke modtages en henteanmodning fra den inden for replica.lag.time.max.ms intervallet

Der er ingen split-brain eller node suspension som i RabbitMQ. I stedet reduceres redundansen.

Scenarie 2: Lederen ser ingen følgere, men ser stadig Zookeeper

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 24. Scenarie 2. Leder og to følgere

Et sammenbrud i netværksforbindelsen adskiller lederen fra følgerne, men mægleren kan stadig se Zookeeper. Som i det første scenarie skrumper ISR, men denne gang kun til lederen, da alle følgere holder op med at sende hentningsanmodninger. Igen er der ingen logisk opdeling. I stedet er der et tab af redundans for nye beskeder, indtil forbindelsen er genoprettet. Zookeeper modtager fortsat ping og mener, at mægleren lever i bedste velgående.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 25. Scenario 2. ISR er kun skrumpet til lederen

Scenarie 3. Følgeren ser lederen, men ser ikke dyrepasseren

Følgeren er adskilt fra Zookeeper, men ikke fra mægleren med lederen. Som et resultat fortsætter følgeren med at foretage hentningsanmodninger og være medlem af ISR. Zookeeper modtager ikke længere ping og registrerer et mæglernedbrud, men da det kun er en følger, er der ingen konsekvenser efter genopretning.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 26. Scenarie 3: Følgeren fortsætter med at sende henteanmodninger til lederen

Scenarie 4. Leder ser følgere, men ser ikke Zookeeper

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 27. Scenarie 4. Leder og to følgere

Lederen er adskilt fra Zookeeper, men ikke fra mæglerne med følgere.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 28. Scenario 4: Leder isoleret fra Zookeeper

Efter nogen tid vil Zookeeper registrere en mæglerfejl og underrette controlleren om det. Han vil vælge en ny leder blandt sine følgere. Den oprindelige leder vil dog fortsætte med at tro, at det er lederen og vil fortsætte med at tage imod tilmeldinger fra acks=1. Tilhængere sender ham ikke længere henteanmodninger, så han vil betragte dem som døde og forsøge at krympe ISR til sig selv. Men da den ikke har en forbindelse til Zookeeper, vil den ikke være i stand til at gøre dette, og på det tidspunkt vil den nægte at acceptere yderligere tilmeldinger.

meddelelser acks=alle vil ikke modtage en bekræftelse, fordi ISR ​​først tænder for alle replikaer, og beskeder når dem ikke. Når den oprindelige leder forsøger at fjerne dem fra ISR, vil den ikke være i stand til at gøre det og vil stoppe med at acceptere nogen beskeder overhovedet.

Kunder bemærker snart ændringen i leder og begynder at sende poster til den nye server. Når netværket er gendannet, ser den oprindelige leder, at den ikke længere er en leder og afkorter sin log til den HW-værdi, som den nye leder havde på tidspunktet for fejl i at undgå log divergens. Det vil derefter begynde at sende hentningsanmodninger til den nye leder. Alle poster fra den oprindelige leder, som ikke er replikeret til den nye leder, går tabt. Det vil sige, beskeder, der ikke blev anerkendt af den oprindelige leder i de få sekunder, hvor to ledere arbejdede, vil gå tabt.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 29. Scenarie 4. Lederen på mægler 1 bliver en følger efter netværket er gendannet

Scenarie 5: Følgeren er fuldstændig adskilt fra både andre Kafka-noder og Zookeeper

Tilhængeren er fuldstændig isoleret fra både andre Kafka-noder og Zookeeper. Han fjerner sig simpelthen fra ISR, indtil netværket er genoprettet, og indhenter derefter de andre.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 30. Scenario 5: Isoleret følger fjernes fra ISR

Scenario 6: Lederen er fuldstændig adskilt fra både andre Kafka-noder og Zookeeper

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 31. Scenarie 6. Leder og to følgere

Lederen er fuldstændig isoleret fra sine følgere, controlleren og dyrepasseren. I en kort periode vil den fortsætte med at modtage tilmeldinger fra acks=1.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 32. Scenario 6: Isolering af lederen fra andre Kafka og Zookeeper noder

Har ikke modtaget anmodninger efter udløb replika.forsinkelsestid.maks.ms, vil den forsøge at krympe ISR til sig selv, men vil ikke være i stand til at gøre det, fordi der ikke er nogen kommunikation med Zookeeper, så vil den stoppe med at acceptere skriverier.

I mellemtiden vil Zookeeper markere den isolerede mægler som død, og controlleren vil vælge en ny leder.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 33. Scenario 6. To ledere

Den oprindelige leder accepterer muligvis indtastninger i nogle få sekunder, men holder derefter op med at acceptere eventuelle beskeder. Klienter opdateres hvert 60. sekund med de seneste metadata. De vil blive informeret om lederskiftet og vil begynde at sende indlæg til den nye leder.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 34. Scenario 6: Producenter skifter til en ny leder

Alle bekræftede indtastninger foretaget af den oprindelige leder siden tab af forbindelse vil gå tabt. Når netværket er genoprettet, vil den oprindelige leder opdage gennem Zookeeper, at den ikke længere er lederen. Derefter vil den afkorte sin log til den nye leders HW på valgtidspunktet og begynde at sende anmodninger som følger.

RabbitMQ vs Kafka: Fejltolerance og høj tilgængelighed
Ris. 35. Scenarie 6: Den oprindelige leder bliver en følger efter netværksforbindelsen er gendannet

I denne situation kan logisk adskillelse forekomme i en kort periode, men kun hvis acks=1 и min.insync.replikaer også 1. Logisk adskillelse slutter automatisk, enten efter at netværket er genoprettet, når den oprindelige leder indser, at han ikke længere er lederen, eller når alle klienter indser, at lederen har ændret sig og begynder at skrive til den nye leder - alt efter hvad der sker først. Under alle omstændigheder vil nogle beskeder gå tabt, men kun med acks=1.

Der er en anden variant af dette scenarie, hvor følgerne, lige før netværket splittes, faldt bagud, og lederen komprimerede ISR til kun sig selv. Det bliver derefter isoleret på grund af tab af forbindelse. En ny leder vælges, men den oprindelige leder fortsætter med at tage imod tilmeldinger, selv acks=alle, fordi der ikke er andre i ISR ​​end ham. Disse registreringer vil gå tabt, når netværket er gendannet. Den eneste måde at undgå denne mulighed er min.insync.replicas = 2.

Scenario 7: Kafka Controller Node kan ikke se en anden Kafka Node

Generelt, når forbindelsen til en Kafka-knude er tabt, vil controlleren ikke være i stand til at sende nogen lederændringsinformation til den. I værste fald vil dette føre til en kortsigtet logisk adskillelse, som i scenarie 6. Oftere end ikke vil mægleren simpelthen ikke blive en lederkandidat, hvis sidstnævnte fejler.

Scenarie 8: Kafka-controlleren kan ikke se Zookeeper

Zookeeper vil ikke modtage et ping fra den faldne controller og vil vælge en ny Kafka node som controller. Den originale controller kan fortsætte med at præsentere sig selv som sådan, men den modtager ikke notifikationer fra Zookeeper, så den vil ikke have nogen opgaver at udføre. Når netværket er gendannet, vil han indse, at han ikke længere er en controller, men er blevet en almindelig Kafka-knude.

Konklusioner fra scenarierne

Vi ser, at tabet af follower-forbindelse ikke resulterer i tab af beskeder, men blot midlertidigt reducerer redundans, indtil netværket er gendannet. Dette kan selvfølgelig føre til tab af data, hvis en eller flere noder går tabt.

Hvis lederen bliver adskilt fra Zookeeper på grund af tab af forbindelse, kan dette resultere i, at meddelelser går tabt fra acks=1. Manglende kommunikation med Zookeeper forårsager en kort logisk splittelse med de to ledere. Dette problem løses af parameteren acks=alle.

Parameter min.insync.replikaer ind i to eller flere replikaer giver yderligere sikkerhed for, at sådanne kortsigtede scenarier ikke vil resultere i tabte meddelelser som i scenarie 6.

Oversigt over mistede meddelelser

Lad os liste alle de måder, du kan miste data på i Kafka:

  • Enhver lederfejl, hvis beskeder blev bekræftet vha acks=1
  • Enhver uren overgang af lederskab, det vil sige til en tilhænger uden for ISR, selv med acks=alle
  • Isolering af lederen fra Zookeeper, hvis beskeder blev bekræftet vha acks=1
  • Fuldstændig isolation af lederen, der allerede har skrumpet ISR-gruppen ned til sig selv. Alle beskeder vil gå tabt, endda acks=alle. Dette er kun sandt, hvis min.insync.replicas=1.
  • Samtidige fejl i alle partitionsknuder. Fordi beskeder bekræftes fra hukommelsen, er nogle muligvis endnu ikke skrevet til disken. Efter genstart af serverne kan der mangle nogle meddelelser.

Urene lederskabsovergange kan undgås ved enten at forbyde dem eller sikre mindst to afskedigelser. Den mest holdbare konfiguration er en kombination acks=alle и min.insync.replikaer over 1.

Direkte sammenligning af pålideligheden af ​​RabbitMQ og Kafka

For at sikre pålidelighed og høj tilgængelighed implementerer begge platforme et primært og sekundært replikeringssystem. RabbitMQ har dog en akilleshæl. Når der genoprettes forbindelse efter en fejl, kasserer noder deres data, og synkroniseringen blokeres. Denne dobbelte pudsighed sætter spørgsmålstegn ved levetiden af ​​store køer i RabbitMQ. Du bliver nødt til at acceptere enten reduceret redundans eller lange blokeringstider. Reduktion af redundans øger risikoen for massivt datatab. Men hvis køerne er små, kan korte perioder med utilgængelighed (et par sekunder) af hensyn til redundansen håndteres ved brug af gentagne forbindelsesforsøg.

Kafka har ikke dette problem. Det kasserer kun data fra divergenspunktet mellem lederen og følgeren. Alle delte data gemmes. Derudover blokerer replikering ikke systemet. Lederen fortsætter med at acceptere stillinger, mens den nye følger indhenter, så for devops bliver det en triviel opgave at tilslutte sig eller gentiltræde klyngen. Selvfølgelig er der stadig problemer såsom netværksbåndbredde under replikering. Hvis du tilføjer flere følgere på samme tid, kan du støde på en båndbreddebegrænsning.

RabbitMQ er Kafka overlegen i pålidelighed, når flere servere i en klynge fejler på samme tid. Som vi allerede har sagt, sender RabbitMQ først en bekræftelse til udgiveren, efter at meddelelsen er skrevet til disken af ​​masteren og alle spejle. Men dette tilføjer yderligere latenstid af to grunde:

  • fsync hvert par hundrede millisekunder
  • Fejlen i spejlet kan først bemærkes, efter at levetiden for de pakker, der kontrollerer tilgængeligheden af ​​hver node (nettick), er udløbet. Hvis spejlet sænker farten eller falder, tilføjer dette en forsinkelse.

Kafkas satsning er, at hvis en besked er gemt på tværs af flere noder, kan den bekræfte beskeder, så snart de rammer hukommelsen. På grund af dette er der risiko for at miste meddelelser af enhver type (selv acks=alle, min.insync.replicas=2) i tilfælde af samtidig svigt.

Samlet set udviser Kafka bedre softwareydelse og er designet fra bunden til klynger. Antallet af følgere kan øges til 11, hvis det er nødvendigt for pålideligheden. Replikeringsfaktor 5 og minimum antal replikaer i synkronisering min.insync.replicas=3 vil gøre tab af besked til en meget sjælden begivenhed. Hvis din infrastruktur kan understøtte dette replikeringsforhold og redundansniveau, så kan du vælge denne mulighed.

RabbitMQ clustering er god til små køer. Men selv små køer kan vokse hurtigt, når der er tæt trafik. Når først køerne bliver store, bliver du nødt til at træffe svære valg mellem tilgængelighed og pålidelighed. RabbitMQ clustering er bedst egnet til ikke-typiske situationer, hvor fordelene ved RabbitMQs fleksibilitet opvejer eventuelle ulemper ved dets clustering.

En modgift mod RabbitMQs sårbarhed over for store køer er at dele dem op i mange mindre køer. Hvis du ikke kræver fuldstændig bestilling af hele køen, men kun de relevante beskeder (for eksempel beskeder fra en specifik klient), eller slet ikke bestiller noget, så er denne mulighed acceptabel: se på mit projekt Rebalancer at opdele køen (projektet er stadig på et tidligt stadie).

Glem endelig ikke en række fejl i klynge- og replikeringsmekanismerne for både RabbitMQ og Kafka. Med tiden er systemerne blevet mere modne og stabile, men ingen besked vil nogensinde være 100 % sikker mod tab! Derudover sker der storstilede ulykker i datacentre!

Hvis jeg er gået glip af noget, lavet en fejl, eller du er uenig i nogen af ​​punkterne, er du velkommen til at skrive en kommentar eller kontakte mig.

Jeg bliver ofte spurgt: "Hvad skal jeg vælge, Kafka eller RabbitMQ?", "Hvilken platform er bedre?". Sandheden er, at det virkelig afhænger af din situation, aktuelle erfaringer osv. Jeg er tøvende med at give min mening til kende, fordi det ville være for meget af en overforenkling at anbefale én platform til alle use cases og mulige begrænsninger. Jeg skrev denne serie af artikler, så du kan danne dig din egen mening.

Jeg vil sige, at begge systemer er førende på dette område. Jeg er måske lidt forudindtaget, fordi jeg ud fra min erfaring med projekter har en tendens til at værdsætte ting som garanteret meddelelsesrækkefølge og pålidelighed.

Jeg ser andre teknologier, der mangler denne pålidelighed og garanteret bestilling, så ser jeg på RabbitMQ og Kafka og indser den utrolige værdi af begge disse systemer.

Kilde: www.habr.com

Tilføj en kommentar