RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë

artikullin e kaluar. Ne kemi shqyrtuar klasterizimin RabbitMQ për të siguruar qëndrueshmërinë dhe disponueshmërinë e lartë. Tani do të thellohemi në Apache Kafka.

Këtu, njësi e replikimit është ndarja (partition). Çdo temë ka një ose më shumë ndarje. Në çdo ndarje ka një lider me ose pa ndjekës. Kur krijohet një temë, përcaktohet numri i ndarjeve dhe coefficienti i replikimit. Vlera e zakonshme është 3, që do të thotë tri replika: një lider dhe dy ndjekës.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 1. Katër ndarjet janë shpërndarë midis tre brokerëve

Të gjitha kërkesat për lexim dhe shkruajmë i drejtohen liderit. Ndjekësit dërgojnë rregullisht liderit kërkesa për të marrë mesazhet më të fundit. Përdoruesit nuk i drejtohen ndjekësve; këta ekzistojnë vetëm për përbashkësi dhe qëndrueshmëri.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë

Dështimi i ndarjes

Kur një broker bie, shpesh ndodhin dështime të liderëve të disa ndarjeve. Në secilën prej tyre, një ndjekës nga një nyje tjetër bëhet lider. Në të vërtetë, kjo nuk ndodh gjithmonë, pasi ndikon edhe faktori i sinkronizimit: a ka ndjekës të sinkronizuar, dhe nëse jo, a lejohet kalimi në një replikë të nesinkronizuar. Por për momentin, mos e kompliko.

Një broker 3 del nga rrjeti — dhe për ndarjen 2, një lider i ri zgjidhet në brokerin 2.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 2. Brokeri 3 është i vdekur, dhe ndjekësi i tij në brokerin 2 zgjidhet lider i ri për ndarjen 2

Pastaj bie brokeri 1 dhe ndarja 1 gjithashtu humbet liderin e saj, roli i të cilit kalon në brokerin 2.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 3. Ka mbetur vetëm një broker. Të gjitha liderët janë në një broker me zero mbivendosje

Kur brokeri 1 kthehet në rrjet, ai shton katër ndjekës, duke siguruar një farë mbivendosjeje për çdo ndarje. Por të gjitha liderët akoma qëndrojnë në brokerin 2.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 4. Liderët mbeten në brokerin 2

Kur brokeri 3 ngrihet, ne kthehemi në tre replika në ndarje. Por të gjitha liderët akoma janë në brokerin 2.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 5. Vendosja e paekuilibruar e liderëve pas ristrukturimit të brokerëve 1 dhe 3

Kafka ka një mjet për një ristrukturim më të mirë të liderëve sesa RabbitMQ. Atje duhej të përdorej një plugin ose skript i jashtëm, i cili ndryshonte politikat për migrimin e nyjës kryesore duke ulur mbivendosjen gjatë migrimit. Për më tepër, për kolonat më të mëdha, duhej të pranohej papërshkrueshmëria gjatë sinkronizimit.

Kafka ka konceptin e "replikave të preferuara" për rolin e liderit. Kur krijohen ndarjet e temës, Kafka përpiqet të shpërndajë liderët baraz në nyje dhe i shënon këta liderët e parë si të preferuar. Me kalimin e kohës, për shkak të rifillimeve të serverëve, dështimeve dhe ndërprerjeve të lidhjeve, liderët mund të përfundojnë në nyje të tjera, siç ndodhi në rastin ekstrem të përmendur më sipër.

Për të rregulluar këtë, Kafka ofron dy opsione:

  • Opcioni auto.leader.rebalance.enable=true lejon që nyja kontrolluese të rinominojë automatikisht liderët mbrapsht në replikat e preferuara dhe kështu të rikthejë shpërndarjen e barabartë.
  • Administratori mund të ekzekutojë skriptin kafka-preferred-replica-election.sh për të rinovuar manualisht.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 6. Replikat pas ristrukturimit

Kjo ishte një version i thjeshtuar i dështimit, por realiteti është më i ndërlikuar, edhe pse nuk ka asgjë të komplikuar këtu. E gjithë kjo lidhet me replikat e sinkronizuara (In-Sync Replicas, ISR).

Replikat e sinkronizuara (ISR)

ISR është një grup replikash të ndarjes, i cili konsiderohet "i sinkronizuar" (in-sync). Ka një lider dhe ndjekësit mund të mos jenë të pranishëm. Një ndjekës konsiderohet i sinkronizuar nëse ka bërë kopje të sakta të të gjitha mesazheve të liderit para se të skadojë interesi replica.lag.time.max.ms.

Një ndjekës largohet nga grupi ISR nëse ai:

  • nuk ka kërkuar përzgjedhjen për brenda intervalit replica.lag.time.max.ms (konsiderohet i vdekur)
  • nuk arriti të përditësohet në interval replica.lag.time.max.ms (konsiderohet i ngadalshëm)

Ndjekësit bëjnë kërkesa përzgjedhjeje brenda intervalit replica.fetch.wait.max.ms, i cili përshekull është 500 ms.

Për të shpjeguar qartësisht qëllimin e ISR, duhet të shqyrtojmë konfirmimet nga prodhuesi dhe disa skenarë dështimi. Prodhuesit mund të zgjedhin se kur brokeri dërgon konfirmim:

  • acks=0, nuk dërgohet konfirmim
  • acks=1, konfirmimi dërgohet pasi lideri ka regjistruar mesazhin në logun e tij lokal
  • acks=all, konfirmimi dërgohet pasi të gjitha replikat në ISR regjistrojnë mesazhin në logët e tyre lokale

Në terminologjinë e Kafka-s, nëse ISR ka ruajtur mesazhin, ndodh "komitimi" i tij. Acks=all është opsioni më i sigurt, por ka një vonesë të shtuar. Le të shqyrtojmë dy shembuj dështimi dhe si opsionet e ndryshme ‘acks’ ndërveprojnë me konceptin ISR.

Acks=1 dhe ISR

Në këtë shembull, ne do të shohim se nëse lideri nuk pret të ruajë çdo mesazh nga të gjithë ndjekësit, atëherë në rast të dështimit të liderit, mund të ndodhi humbja e të dhënave. Kalimi te ndjekësi jo të sinkronizuar mund të lejohet ose ndalohet nga konfigurimi. unclean.leader.election.enable.

Në këtë shembull, prodhuesi ka vendosur vlerën acks=1. Nënshkrimi është shpërndarë në të tre brokerët. Brokeri 3 është duke pritur, ai është sinkronizuar me liderin tetë sekonda më parë dhe tani është prapa me 7456 mesazhe. Brokeri 1 është prapa vetëm një sekondë. Prodhuesi ynë dërgon një mesazh dhe merr shpejt një konfirmim, pa ngarkesë për ndjekësit e ngadalshëm ose të vdekur, të cilët lideri nuk i pret.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 7. ISR me tre replica

Brokeri 2 dështoi, dhe prodhuesi merr një gabim lidhjeje. Pas kalimit të liderit te brokeri 1, ne humbim 123 mesazhe. Ndjekësi në brokerin 1 ishte në ISR, por nuk ishte sinkronizuar plotësisht me liderin kur ai ra.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 8. Mesazhet humbasin kur ndodhi dështimi

Në konfiguracionin bootstrap.servers prodhuesi rendit disa brokerë dhe ai mund të pyesë një broker tjetër se kush e ka marrë rolin e liderit të nënshkrimit. Pastaj ai vendos një lidhje me brokerin 1 dhe vazhdon të dërgojë mesazhe.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 9. Dërgimi i mesazheve rinis pas një pauze të shkurtër

Brokeri 3 është prapa edhe më shumë. Ai bën kërkesa për të tërhequr mesazhe, por nuk mund të sinkronizohet. Kjo mund të jetë për shkak të një lidhjeje rrjeti të ngadalshme midis brokerëve, një problem ruajtjeje, etj. Ai është larguar nga ISR. Tani ISR përbëhet nga një replike — lideri! Prodhuesi vazhdon të dërgojë mesazhe dhe merr konfirmime.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 10. Ndjekësi në brokerin 3 largohet nga ISR

Brokeri 1 bie, dhe roli i liderit kalon te brokeri 3 me humbje 15286 mesazhesh! Prodhuesi merr një mesazh gabimi lidhjeje. Kalimi te lideri jashtë ISR ishte i mundur vetëm për shkak të konfigurimit unclean.leader.election.enable=true. Nëse është vendosur në false, atëherë kalimi nuk do të ndodhte, dhe të gjitha kërkesat për lexim dhe shkruaj do të refuzoheshin. Në këtë rast, ne presim rikthimin e brokerit 1 me të dhënat e tij të paprekura në repliken që do të marrë sërish rolin e liderit.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 11. Brokeri 1 bie. Gjatë dështimit humbet një numër të madh mesazhesh

Prodhuesi vendos lidhje me brokerin e fundit dhe sheh se ai tani është lider i nënshkrimit. Ai fillon të dërgojë mesazhe në brokerin 3.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 12. Pas një pauze të shkurtër, dërgimi i mesazheve rinis në nënshkrimin 0

Kemi parë se përveç ndalimeve të shkurtra për të vendosur lidhje të reja dhe për të gjetur një lider të ri, prodhuesi vazhdimisht dërgonte mesazhe. Një konfigurim i tillë siguron disponueshmëri përmes konsistencës (sigurisë së të dhënave). Kafka humbi mijëra mesazhe, por vazhdoi të pranojë regjistrime të reja.

Acks=all dhe ISR

Le të përsërisim këtë skenar një herë tjetër, por me acks=all. Vonesa e brokerit 3 mesatarisht katër sekonda. Prodhuesi dërgon një mesazh me acks=all, dhe tani nuk merr një përgjigje të shpejtë. Lideri pret derisa mesazhi të ruhet nga të gjithë replikat në ISR.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 13. ISR me tre replica. Një punon ngadalë, duke shkaktuar vonesa në shkruarje

Pas katër sekondash vonesë shtesë, brokeri 2 dërgon një konfirmim. Të gjitha replikat tani janë plotësisht të përditësuara.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 14. Të gjitha replikat ruajnë mesazhet dhe dërgohet konfirmimi

Brokeri 3 tani është prapa edhe më shumë dhe largohet nga ISR. Vonesa zvogëlohet ndjeshëm, pasi nuk ka mbetur replikë të ngadalshme në ISR. Brokeri 2 tani pret vetëm brokerin 1, i cili ka një vonesë mesatare prej 500 ms.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 15. Replica në brokerin 3 largohet nga ISR

Pastaj bie brokeri 2, dhe lideri kalon te brokeri 1 pa humbje mesazhesh.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 16. Brokeri 2 bie

Prodhuesi gjen një lider të ri dhe fillon t’i dërgojë atij mesazhe. Vonesa vazhdon të zvogëlohet, sepse tani ISR përbëhet vetëm nga një replike! Prandaj, opsioni acks=all nuk shton mbivendosje.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 17. Replica në brokerin 1 merr rolin e liderit pa humbje mesazhesh

Pastaj bie brokeri 1, dhe roli i liderit kalon te brokeri 3 me humbje 14238 mesazhesh!

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 18. Brokeri 1 vdes, dhe kalimi i liderit me konfigurimin e papastërtisë çon në humbje të mëdha të të dhënave

Ne mund të mos vendosim opsionin unclean.leader.election.enable në vlerë e vërtetë. Mënyra e paracaktuar është false. Konfigurimi acks=all me unclean.leader.election.enable=true siguron disponueshmëri me disa siguri shtesë për të dhënat. Por, siç e shihni, ne ende mund të humbim mesazhe.

Por çfarë nëse duam të rrisim sigurinë e të dhënave? Mund të vendosim unclean.leader.election.enable = false, por kjo nuk do të na mbrojë domosdoshmërisht nga humbja e të dhënave. Nëse lideri ra rëndë dhe e mori me vete të dhënat, atëherë mesazhet përsëri humbasin, plus humbet disponueshmëria, derisa administratori të rikthejë situatën.

Më mirë të garantoni redundancën e të gjitha mesazheve, në të kundërt do të hiqni dorë nga regjistrimi. Kështu, nga pikëpamja e brokerit, humbja e të dhënave është e mundur vetëm në rast të dy ose më shumë dështimeve të njëkohshme.

Acks=all, min.insync.replicas dhe ISR

Me konfigurimin e temës min.insync.replicas ne rrisim nivelin e sigurisë së të dhënave. Le të kalojmë sërish në pjesën e fundit të skenarit të kaluar, por këtë herë me min.insync.replicas=2.

Pra, brokeri 2 ka liderin e replikuar, ndërsa ndjekësi në brokerin 3 është hequr nga ISR.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 19. ISR nga dy replika

Brokeri 2 bie, dhe udhëheqja kalon në brokerin 1 pa humbje mesazhesh. Por tani ISR përbëhet vetëm nga një replikë. Kjo nuk i përmbush numrin minimal për regjistrim, dhe prandaj brokeri përgjigjet me një gabim në përpjekjen për regjistrim. NotEnoughReplicas.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 20. Numri i ISR është një më i ulët se sa e përcaktuar në min.insync.replicas

Kjo konfigurim i sakrifikon disponueshmërinë për konsistencë. Para se të konfirmoni mesazhin, ne garanti që ajo regjistrohet në të paktën dy replika. Kjo i jep prodhuesit shumë më shumë siguri. Këtu humbja e mesazheve është e mundur vetëm në rast të dështimit të dy replika në një periudhë të shkurtër, derisa mesazhi të miratohet te një ndjekës tjetër, që është e pamundur. Por nëse je shumë paranojak, mund të vendosësh një faktor replikimi 5, dhe min.insync.replicas në 3. Kështu këtu duhet të bien tre brokerë njëkohësisht për të humbur regjistrimin! Sigurisht, për një besueshmëri të tillë do të paguani me vonesë të shtuar.

Kur disponueshmëria është e nevojshme për sigurinë e të dhënave

As in në rastin e RabbitMQ, ndonjëherë disponueshmëria është e nevojshme për sigurinë e të dhënave. Ju duhet të mendoni për këtë:

  • A mund të kthejë vetëm publiku një gabim, dhe shërbimi i lartë ose përdoruesi ta provoni përsëri më vonë?
  • A mund të ruajë botuesi mesazhin lokalisht ose në bazën e të dhënave për ta provuar më vonë?

Nëse përgjigjja është negative, atëherë optimizimi i disponueshmërisë rrit sigurinë e të dhënave. Do të humbni më pak të dhëna nëse zgjidhni disponueshmëri mbi refuzimin e regjistrimit. Pra, gjithçka varet nga gjetja e një balancimi, dhe zgjidhja varet nga situata specifike.

Kuptimi i ISR

Grupi i ISR lejon të zgjidhni balancimin optimal midis sigurisë së të dhënave dhe vonesës. Për shembull, sigurojnë disponueshmëri në kushte të dështimit të shumicës së replika, duke minimalizuar ndikimin e replika të vdekura ose të ngadalta në aspektin e vonesës.

Ne vetë zgjedhim vlerën replica.lag.time.max.ms sipas nevojave tona. Në thelb, ky parametër tregon se sa vonesë jemi të gatshëm të pranojmë në acks=all. Vlera e paracaktuar është dhjetë sekonda. Nëse për ju kjo është shumë e gjatë, mund ta reduktoni. Kështu, do të rritet frekuenca e ndryshimeve në ISR, pasi ndjekësit do të hiqen dhe shtohen më shpesh.

Në RabbitMQ ka thjesht një grup pasqyrash që duhet të replikohen. Pasqyrat e ngadalta sjellin vonesë shtesë, dhe për përgjigjet e pasqyrave të vdekura mund të pritet deri në skadimin e kohës së paketave që kontrollojnë disponueshmërinë e çdo nodi (net tick). ISR është një mënyrë interesante për të shmangur këto probleme me rritjen e vonesës. Por rrezikojmë të humbasim redundancën, pasi ISR mund të zvogëlohet vetëm deri te lideri. Për të shmangur këtë rrezik, përdorni konfigurimin min.insync.replicas.

Garancia e lidhjes së klientëve

Në cilësimet bootstrap.servers prodhuesit dhe konsumatorit mund të specifikojnë disa brokerë për t'u lidhur me klientët. Ideja është që në rast të ndarjes së një nodi, të mbeten disa rezervë me të cilat klienti mund të hapë një lidhje. Kjo nuk është domosdoshmërisht liderët e ndarjeve, por thjesht një bazë për ngarkim fillestar. Klienti mund t'i pyesë ata se në cilin nod është vendosur lideri i ndarjes për lexim/shkrim.

Në RabbitMQ klientët mund të lidhen me çdo nod, dhe routing i brendshëm dërgon kërkesën aty ku duhet. Kjo do të thotë se mund të vendosni një balancues ngarkese para RabbitMQ. Kafka kërkon që klientët të lidhen me nodin ku ndodhet lideri i ndarjes përkatëse. Në një situatë të tillë, nuk është e mundur të vendosni një balancues ngarkese. Lista bootstrap.servers është kritike që klientët të mund t'i drejtohen nodëve të nevojshëm dhe t'i gjejnë ato pas dështimit.

Arkitektura e konsensusit të Kafka

Derisa ne nuk kemi shqyrtuar ende se si klasteri e merr vesh për rënien e brokerit dhe si zgjidhet një lider i ri. Për të kuptuar se si Kafka funksionon me ndarjet në rrjet, është e nevojshme të kuptoni fillimisht arkitekturën e konsensusit.

Çdo klaster i Kafka shërbehet së bashku me një klaster Zookeeper — kjo është një shërbim i konsensusit të shpërndarë që lejon sistemin të arrijë konsensus mbi një gjendje të caktuar me prioritet për konsistencën mbi disponueshmërinë. Për miratimin e operacioneve të leximit dhe shkrimit kërkohet dakordësia e shumicës së nodëve të Zookeeper.

Zookeeper ruan gjendjen e klasterit:

  • Lista e temave, seksioneve, konfigurimi, replikat aktuale të liderit, replikat e preferuara.
  • Anëtarët e klasterit. Çdo broker pingon në klasterin Zookeeper. Nëse ai nuk merr ping për një periudhë të caktuar kohe, Zookeeper e regjistron brokerin si të paaksesueshëm.
  • Zgjedhja e nyjeve kryesore dhe rezervë për kontrolluesin.

Nyja e kontrolluesit — një nga brokerët Kafka, i cili është përgjegjës për zgjedhjen e liderëve të replikave. Zookeeper i dërgon kontrolluesit njoftime mbi anëtarësimin në klaster dhe ndryshimet në temë, dhe kontrolluesi duhet të veprojë në përputhje me këto ndryshime.

Për shembull, le të marrim një temë të re me dhjetë seksione dhe faktor riplikimi 3. Kontrolluesi duhet të zgjedhë liderin e çdo seksioni, duke u përpjekur të shpërndajë optimalisht liderët midis brokerëve.

Për çdo seksion kontrolluesi:

  • përditëson informacionin në Zookeeper mbi ISR dhe liderin;
  • dërgon komandën LeaderAndISRCommand për çdo broker që vendos replikën e këtij seksioni, duke i informuar brokerët mbi ISR dhe liderin.

Kur bie një broker me liderin, Zookeeper i dërgon një njoftim kontrolluesit, dhe ai zgjedh një lider të ri. Përsëri, kontrolluesi së pari përditëson Zookeeper, dhe pastaj dërgon komandën për çdo broker, duke i njoftuar ata për ndryshimin e liderit.

Çdo lider është përgjegjës për grupin ISR. Konfigurimi replica.lag.time.max.ms përcakton se kush do të hyjë aty. Kur ndryshon ISR, lideri e kalon informacionin e ri në Zookeeper.

Zookeeper është gjithmonë në dijeni të çdo ndryshimi, që në rast dështimi, udhëheqja të kalojë pa probleme te një lider i ri.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 21. Konsensusi Kafka

Protokolli i riplikimit

Të kuptuarit e detajeve të riplikimit ndihmon në kuptimin më të mirë të skenarëve të mundshëm të humbjes së të dhënave.

Kërkesat për tërheqje, Log End Offset (LEO) dhe Highwater Mark (HW)

Ne kemi shqyrtuar se ndjekësit dërgojnë herë pas here kërkesa për tërheqje (fetch) liderit. Intervali i paracaktuar është 500 ms. Kjo është e ndryshme nga RabbitMQ, ku riplikimi niset jo nga pasqyra e radhës, por nga masteri. Masteri dërgon ndryshimet te pasqyra.

Lideri dhe të gjithë ndjekësit ruajnë Offset-in e fundit të logut (Log End Offset, LEO) dhe etiketën Highwater (HW). Etiketa LEO ruan offset-in e mesazhit të fundit në replikën lokale, ndersa HW është offset i komitimit të fundit. Mbani mend se për statusin "komit" mesazhi duhet të ruhet në të gjitha replikat ISR. Kjo do të thotë se LEO zakonisht është pak përpara HW.

Kur lideri merr një mesazh, ai e ruan atë lokal. Ndjekësi bën një kërkesë për tërheqje, duke dorëzuar LEO-në e tij. Pastaj lideri dërgon një paketë mesazhesh, duke filluar nga ky LEO, si dhe e transmeton HW-në aktuale. Kur lideri merr informacionin se të gjitha replikat kanë ruajtur mesazhin me offset-in e caktuar, ai e lëviz etiketën HW. Vetëm lideri mund të lëvizë HW-në, dhe kështu të gjithë ndjekësit mësojnë vlerën aktuale në përgjigje të kërkesës së tyre. Kjo do të thotë se ndjekësit mund të jenë pas liderit, si në mesazhe ashtu edhe në njohjen e HW-së. Konsumatorët marrin mesazhe vetëm deri në HW-në aktuale.

Kujdes, "i ruajtur" (persisted) do të thotë i shkruar në memorje, jo në disk. Për performancë, Kafka bën sinkronizimin në disk me një interval të caktuar. Kjo ndodhet gjithashtu në RabbitMQ, por do të dërgojë një konfirmim për publikuesin vetëm pasi masteri dhe të gjitha pasqyrat të kenë regjistruar mesazhin në disk. Zhvilluesit e Kafka, për arsye të performancës, kanë vendosur të dërgojnë ack, sa herë që mesazhi është regjistruar në memorje. Kafka beson se tepërtia kompenson rrezikun e ruajtjes afatshkurtër të mesazheve të konfirmuara vetëm në memorje.

Dështimi i liderit

Kur bie lideri, Zookeeper e njofton kontrolluesin, dhe ai zgjedh një replikë të re lideri. Lideri i ri vendos një etiketë të re HW në përputhje me LEO-në e tij. Pastaj ndjekësit marrin informacionin për liderin e ri. Në varësi të versionit të Kafka, ndjekësi do të zgjedhë një nga dy skenarët:

  1. Do të shkurtojë logun lokal në një HW të njohur dhe do t'i dërgojë liderit një kërkesë për mesazhe pas kësaj etikete.
  2. Do të dërgojë një kërkesë për liderin për të mësuar HW-në në momentin e zgjedhjes së tij si lider, dhe pastaj do të shkurtëzojë logun deri në këtë offset. Pastaj do të fillojë të dërgojë kërkesa të rregullta për tërheqje, duke filluar nga ky offset.

Ndjekësit mund të kenë nevojë të shkurtëzojnë logun për arsyet e mëposhtme:

  • Kur ndodh një dështim lideri, ndihmësi i parë nga grupi ISR, i regjistruar në Zookeeper, fiton zgjedhjet dhe bëhet lider. Të gjithë ndihmësit në ISR, megjithëse konsiderohen "të sinkronizuar", mund edhe të mos kenë marrë kopje të të gjitha mesazheve nga lideri i mëparshëm. Është mjaft e mundur që ndihmësi i zgjedhur të mos ketë kopjen më të përditësuar. Kafka garanton që nuk ka shkëputje midis kopjeve. Kështu, për të shmangur shkëputjen, çdo ndihmës duhet të shkurtojë logun e tij deri në vlerën HW të liderit të ri në momentin e zgjedhjes së tij. Kjo është një arsye tjetër pse konfigurimi acks=all është kaq i rëndësishëm për koherencën.
  • Mesazhet regjistrohen periodikisht në disk. Nëse të gjithë nodet e klasterit dështojnë njëkohësisht, atëherë në disqe do të ruhen kopje me offset të ndryshëm. Është mjaft e mundur që kur brokerët të rikthehen në rrjet, lideri i ri që do të zgjidhet të jetë pas ndihmësve të tij, sepse është ruajtur në disk më herët se ata.

Rikthimi në klaster

Kur rikthehesh në klaster, ndihmësit veprojnë ashtu siç veprojnë në rast dështimi lideri: kontrollojnë kopjen e liderit dhe shkurtojnë logun e tyre deri në HW (në momentin e zgjedhjes). Për krahasim, RabbitMQ i vlerëson nodet e rikthyer si krejtësisht të reja. Në të dy rastet, brokeri hedh çdo gjendje ekzistuese. Nëse përdoret sinkronizimi automatik, atëherë lideri duhet të riprodhojë krejt përmbajtjen aktuale në pasqyrën e re me një metodë "dhe le të presë bota e tërë". Gjatë kësaj operacioni, lideri nuk pranon asnjë operacion leximi ose shkruaje. Ky qasje krijon probleme në radhët e mëdha.

Kafka është një log i shpërndarë, dhe në përgjithësi ruan më shumë mesazhe se një radhë RabbitMQ, ku të dhënat fshihen nga radhë pas leximit të tyre. Radhët aktive duhet të mbeten relativisht të vogla. Por Kafka është një log me politikën e saj të ruajtjes, e cila mund të vendosë një afat deri në ditë ose javë. Qasja me bllokimin e radhës dhe sinkronizimin e plotë është krejtësisht e papranueshme për një log të shpërndarë. Në vend të kësaj, ndihmësit e Kafka thjesht shkurtojnë logun e tyre deri në HW të liderit (në momentin e zgjedhjes) në rastin kur kopja e tyre e tejkalon liderin. Në një rast më të mundshëm, kur ndihmësi është pas, ai thjesht fillon të bëjë kërkesa për të tërhequr, duke filluar nga LEO aktual.

Ndihmësit e rinj ose ata që rikthehen fillojnë jashtë ISR dhe nuk marrin pjesë në komitetet. Ata thjesht punojnë ngjitur me grupin, duke marrë mesazhe sa më shpejt që mundeni, derisa të përfundojnë me liderin dhe të hyjnë në ISR. Nuk ka bllokim dhe nuk ka nevojë të hodhni të dhëna.

Shkeputja e lidhshmërisë

Kafka ka më shumë componente se RabbitMQ, kështu që këtu ka një set më të komplikuar të sjelljeve kur lidhshmëria e klasterit prishët. Por Kafka fillimisht është projektuar për klasterë, kështu që zgjidhjet janë shumë mirë të menduara.

Më poshtë janë disa skenarë të shkeljes së lidhshmërisë:

  • Skenari 1. Ndihmësi nuk e sheh liderin, por akoma e sheh Zookeeper.
  • Skenari 2. Lideri nuk sheh asnjë ndihmës, por akoma e sheh Zookeeper.
  • Skenari 3. Ndihmësi e sheh liderin, por nuk e sheh Zookeeper.
  • Skenari 4. Lideri i sheh ndihmësit, por nuk e sheh Zookeeper.
  • Skenari 5. Ndihmësi është plotësisht i ndarë nga nodet e tjera të Kafka dhe nga Zookeeper.
  • Skenari 6. Lideri është plotësisht i ndarë nga nodet e tjera të Kafka dhe nga Zookeeper.
  • Skenari 7. Nodi kontrollues i Kafka nuk e sheh ndonjë nod tjetër të Kafka.
  • Skenari 8. Kontrolluesi i Kafka nuk e sheh Zookeeper.

Për çdo skenar është parashikuar një sjellje e saj.

Skenari 1. Ndihmësi nuk e sheh liderin, por akoma e sheh Zookeeper

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 22. Skenari 1. ISR nga tre kopje

Shkëputja e lidhshmërisë ndan brokerin 3 nga brokerët 1 dhe 2, por jo nga Zookeeper. Brokeri 3 nuk mund më të bëjë kërkesa për të tërhequr. Pas kalimit të kohës replica.lag.time.max.ms ai hiqet nga ISR dhe nuk merr pjesë në komitetet e mesazheve. Sapo lidhshmëria rikthehet, ai do të rinovojë kërkesat për të tërhequr dhe do t'i bashkohet ISR, kur të kapë liderin. Zookeeper do të vazhdojë të marrë ping dhe të mendojë se brokeri është i gjallë dhe i shëndoshë.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 23. Skenari 1. Brokeri hiqet nga ISR, nëse nuk merr një kërkesë për të tërhequr brenda intervalit replica.lag.time.max.ms

Nuk ka asnjë ndarje logjike (split-brain) ose pezullim nodi si në RabbitMQ. Në vend të kësaj, reduktohet mbivendosja.

Skenari 2. Lideri nuk e sheh asnjë ndihmës, por akoma e sheh Zookeeper.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 24. Skenari 2. Lideri dhe dy ndihmës

Shkëputja e lidhjes rrjetike ndan liderin nga ndjekësit, por brokeri ende e sheh Zookeeper. Si në skenarin e parë, ISR ngushtohet, por kësaj here vetëm deri te lideri, pasi të gjithë ndjekësit ndalojnë së dërguari kërkesat për tërheqje. Sërish, nuk ka ndarje logjike. Në vend të kësaj, ndodhi humbja e tepricës për mesazhet e reja, derisa lidhja të rikuperohet. Zookeeper vazhdon të marrë ping dhe konsideron se brokeri është i gjallë dhe në formë.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 25. Skenari 2. ISR ngushtohet vetëm deri te lideri

Skenari 3. Ndjekësi e sheh liderin, por nuk e sheh Zookeeper

Ndjekësi ndahen nga Zookeeper, por jo nga brokeri me liderin. Si rezultat, ndjekësi vazhdon të dërgojë kërkesa për tërheqje dhe të jetë anëtar i ISR. Zookeeper nuk merr më ping dhe regjistron rënien e brokerit, por pasi është vetëm një ndjekës, nuk ka asnjë pasojë pas rikuperimit.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 26. Skenari 3. Ndjekësi vazhdon të dërgojë kërkesa për tërheqje te lideri

Skenari 4. Lideri sheh ndjekësit, por nuk e sheh Zookeeper

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 27. Skenari 4. Lideri dhe dy ndjekës

Lideri është i ndarë nga Zookeeper, por jo nga brokerat me ndjekës.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 28. Skenari 4. Lideri është i izoluar nga Zookeeper

Pas një kohe, Zookeeper do të regjistrojë rënien e brokerit dhe do ta njoftojë kontrolluesin. Ai do të zgjedhë një lider të ri nga ndjekësit. Megjithatë, lideri origjinal do të vazhdojë të mendojë se është lider dhe do të vazhdojë të pranojë regjistrime me acks=1. Ndjekësit nuk i dërgojnë më atij kërkesa për tërheqje, kështu ai do t'i konsiderojë ata të vdekur dhe do të përpiqet ta ngushtojë ISR deri te vetja. Por, pasi nuk ka lidhje me Zookeeper, nuk do të mundet ta bëjë këtë dhe në atë moment do të heqë dorë nga pranimi i mëtejshëm të regjistrimeve.

Mesazhet acks=all nuk do të marrin konfirmime, sepse në fillim ISR përfshin të gjitha replikat, dhe para se të arrijnë te ato, mesazhet nuk kalojnë. Kur lideri fillestar të përpiqet t'i heqë ato nga ISR, nuk do të mund ta bëjë këtë dhe do të ndalojë gjithashtu pranimin e ndonjë mesazhi.

Konsumatorët shpejt vërejnë ndërrimin e liderit dhe fillojnë të dërgojnë regjistrime në serverin e ri. Pas rikuperimit të rrjetit, lideri origjinal sheh se nuk është më lider dhe e pranon logun e tij në vlerën HW që kishte lideri i ri në momentin e dështimit, për të shmangur çarjen e logjeve. Pastaj fillon t'u dërgojë kërkesa për tërheqje liderit të ri. Do të humbasin të gjitha regjistrimet e liderit origjinal, të pa replikuara te lideri i ri. Do të thotë se mesazhet e pa konfirmuara nga lideri fillestar do të humbasin në ato disa sekonda, kur dy liderë ishin aktivë.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 29. Skenari 4. Lideri në brokerin 1 bëhet ndjekës pas rikuperimit të rrjetit

Skenari 5. Ndjekësi është plotësisht i ndarë nga të tjerët nodet Kafka dhe nga Zookeeper

Ndjekësi është plotësisht i izoluar nga të tjerët nodet Kafka dhe nga Zookeeper. Ai thjesht hiqet nga ISR, derisa të rikuperohet rrjeti, dhe pastaj e ndjek të tjerët.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 30. Skenari 5. Ndjekësi i izoluar hiqet nga ISR

Skenari 6. Lideri është plotësisht i ndarë nga të tjerët nodet Kafka dhe nga Zookeeper

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 31. Skenari 6. Lideri dhe dy ndjekës

Lideri është plotësisht i izoluar nga ndjekësit e tij, kontrolluesi dhe Zookeeper. Për një periudhë të shkurtër, ai do të vazhdojë të pranojë regjistrime me acks=1.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 32. Skenari 6. Izolimi i liderit nga nodet e tjera Kafka dhe Zookeeper

Duke mos marrë kërkesa pas replica.lag.time.max.ms, ai do të përpiqet ta ngushtojë ISR deri te vetja, por nuk do të mundet ta bëjë këtë, pasi nuk ka lidhje me Zookeeper, kështu ai do të ndalojë pranimin e regjistrimeve.

Në ndërkohë, Zookeeper do ta shënojë brokerin e izoluar si të vdekur, dhe kontrolluesi do të zgjedhë një lider të ri.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 33. Skenari 6. Dy liderë

Lideri origjinal mund të pranojë regjistrime për disa sekonda, por pastaj ndalon pranimin e ndonjë mesazhi. Konsumatorët përditësohen çdo 60 sekonda me metadatat e fundit. Ata do të informohen për ndërrimin e liderit dhe do të fillojnë të dërgojnë regjistrime te lideri i ri.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 34. Skenari 6. Prodhuesit kalojnë te lideri i ri

Do të humbasin të gjitha regjistrimet e konfirmuara, të bëra nga lideri origjinal që nga humbja e lidhjes. Pasi rrjeti të rikuperohet, lideri origjinal përmes Zookeeper do të zbulojë se nuk është më lider. Atëherë do të presë logun e tij deri në HW të liderit të ri në momentin e zgjedhjes dhe do të fillojë të dërgojë kërkesa si ndjekës.

RabbitMQ kundër Kafka: qëndrueshmëria dhe disponueshmëria e lartë
Fig. 35. Skenari 6. Lideri origjinal bëhet ndjekës pas rikuperimit të lidhjes së rrjetit

Në këtë situatë, për një periudhë të shkurtër mund të ketë një ndarje logjike, por vetëm nëse acks=1 dhe min.insync.replicas Po gjithashtu 1. Ndarja logjike përfundon automatikisht ose pas rikthimit të rrjetit, kur lideri origjinal e kupton se nuk është më lider, ose kur të gjithë klientët kuptojnë se lideri ka ndryshuar dhe fillojnë të shkruajnë te lideri i ri — në varësi të asaj se çfarë ndodh më parë. Në çdo rast do të ndodhi humbja e disa mesazheve, por vetëm me acks=1.

Ekziston një variant tjetër i këtij skenari, kur menjëherë para ndarjes së rrjetit, ndjekësit kanë mbetur pas, dhe lideri e ka ngushtuar ISR në vetëm veten. Pastaj ai izolohet për shkak të humbjes së lidhshmërisë. Zgjedhet një lider i ri, por lideri fillestar vazhdon të pranojë regjistrime, madje acks=all, sepse në ISR përveç tij nuk ka askush tjetër. Këto regjistrime do të humbasin pas rikthimit të rrjetit. Mënyra e vetme për të shmangur një variant të tillë është min.insync.replicas = 2.

Skenari 7. Një nyje e kontrolluesit Kafka nuk e sheh një nyje tjetër Kafka

Në përgjithësi, pas humbjes së lidhjes me një nyje Kafka, kontroluesi nuk do të mund t'i dërgojë atij asnjë informacion në lidhje me ndryshimin e liderit. Në rastin më të keq, kjo do të çojë në një ndarje logjike të shkurtër, si në skenarin 6. Shpesh, brokeri thjesht nuk do të jetë një kandidat për liderësi në rastin e dështimit të fundit.

Skenari 8. Kontrolluesi Kafka nuk e sheh Zookeeper

Kontrolluesi i humbur nuk do të marrë ping nga Zookeeper dhe do të zgjedhë një nyje të re Kafka si kontrollues. Kontrolluesi origjinal mund të vazhdojë të veprojë si i tillë, por ai nuk merr njoftime nga Zookeeper, prandaj nuk do të ketë asnjë detyrë për të përfunduar. Sap o rrjeti të rikthehet, ai do të kuptojë se nuk është më kontrollues, por është bërë një nyje e zakonshme Kafka.

Përfundimet nga skenarët

Ne shohim se humbja e lidhshmërisë së ndjekësve nuk çon në humbjen e mesazheve, por thjesht redukton përkohësisht tepricën, derisa rrjeti të rikthehet. Kjo, sigurisht, mund të çojë në humbje të të dhënave, nëse një ose disa nyje humbin.

Nëse për shkak të humbjes së lidhshmërisë lideri është ndarë nga Zookeeper, kjo mund të çojë në humbje mesazhesh me acks=1. Mungesa e lidhjes me Zookeeper shkakton një ndarje logjike të shkurtër me dy liderë. Ky problem zgjidhet nga parametrat acks=all.

Parametri min.insync.replicas për dy ose më shumë replika ofron garanci të shtesë që skenarët e tillë afatshkurtër nuk do të çojnë në humbjen e mesazheve, si në skenarin 6.

Përmbledhje mbi humbjen e mesazheve

Le të rendisim të gjitha mënyrat se si mund të humbni të dhëna në Kafka:

  • Çdo dështim i liderit, nëse mesazhet janë konfirmuar duke përdorur acks=1
  • Çdo kalim i papastër (unclean) në liderësi, do të thotë te ndjekësi jashtë ISR, madje edhe me acks=all
  • Izolimi i liderit nga Zookeeper, nëse mesazhet janë konfirmuar duke përdorur acks=1
  • Izolimi i plotë i liderit, i cili tashmë e ka ngushtuar grupin ISR në veten e tij. Të gjitha mesazhet do të humbasin, madje acks=all. Kjo është e vërtetë vetëm në rast se min.insync.replicas=1.
  • Dështime të menjëhershme të të gjitha nyjeve të një seksioni. Duke qenë se mesazhet konfirmohen nga memoria, disa mund të mos jenë regjistruar ende në disk. Pas rinisjes së serverëve, disa mesazhe mund të mungojnë.

Kalimet e papastra në liderësi mund të shmangen, ose duke i ndaluar ato, ose duke siguruar tepricë prej të paktën dy. Konfigurimi më i fortë është një kombinim acks=all dhe min.insync.replicas më shumë se 1.

Krahasimi i drejtpërdrejtë i qëndrueshmërisë së RabbitMQ dhe Kafka

Për të siguruar qëndrueshmërinë dhe disponueshmërinë e lartë, të dy platformat zbatojnë një sistem replikimi primar dhe sekondar. Megjithatë, RabbitMQ ka një ahile të vet. Gjatë ri-ngjitjes pas një dështimi, nyjet hedhin të dhënat e tyre, dhe sinkronizimi bllokohet. Ky dyfishim rrezikon qëndrueshmërinë e rreshtave të mëdha në RabbitMQ. Ju do të duhet të pajtoheni ose me reduktimin e tepricës, ose me bllokime të zgjatura. Reduktimi i tepricës rrit rrezikun e humbjeve masive të të dhënave. Por nëse rreshtat janë të vegjël, për qëllime të tepricës me periudha të shkurtra të pakohësisë (për disa sekonda) mund të arrihet përmes përpjekjeve për lidhje.

Në Kafka nuk ka një problem të tillë. Ajo hedh të dhënat vetëm nga pika e shkëputjes mes liderit dhe ndjekësit. Të gjitha të dhënat e zakonshme ruhen. Për më tepër, replikimi nuk bllokon sistemin. Lideri vazhdon të pranojë regjistrime, ndërsa ndjekësi i ri e përfshin, kështu që për dev.ops, bashkimi ose ri-bashkimi me klasterin bëhet një detyrë triviale. Sigurisht, ende mbeten probleme, si kapaciteti i rrjetit gjatë replikimit. Nëse disa ndjekës shtohen në të njëjtën kohë, mund të hasni kufirin e kapacitetit.

RabbitMQ ofron besueshmëri më të lartë se Kafka kur ndodhin dështime të shumtë serverësh në klaster. Siç e përmendem, RabbitMQ dërgon një konfirmim ndaj botuesit vetëm pasi mesazhi të regjistrohet në disk te mjeshtri dhe të gjitha pasqyrat. Por kjo shton një vonesë të shtuar për dy arsye:

  • fsync çdo disa qindra milisekonda
  • Dështimi i pasqyrës mund të vihet re vetëm pas përfundimit të jetës së pakove, të cilat kontrollojnë disponibilitetin e secilit nyje (net tick). Nëse pasqyra ngec apo dështon, kjo shton vonesën.

Kafka beson se, nëse mesazhi ruhet në disa nyje, mund të konfirmohen mesazhet sapo ato futen në kujtesë. Për këtë shkak, ekziston rreziku i humbjes së mesazheve të çdo lloji (edhe acks=all, min.insync.replikat=2) në rast të dështimit të menjëhershëm.

Në përgjithësi, Kafka tregon performancë më të lartë dhe është projektuar fillimisht për klastere. Numri i ndjekësve mund të rritet deri në 11, nëse është e nevojshme për besueshmëri. Faktorët e replikimit 5 dhe numri minimal i replikave në gjendje të sinkronizuar min.insync.replicas=3 do ta bëjnë humbjen e mesazheve një ngjarje shumë të rrallë. Nëse infrastruktura juaj është në gjendje të ofrojë një faktor replikimi dhe një nivel të tepërt, atëherë mund të zgjidhni këtë mundësi.

Klasterizimi i RabbitMQ është i mirë për radhët e vogla. Por, edhe radhët e vogla mund të rriten shpejt me trafikun e madh. Sapo radhët bëhen të mëdha, do të duhet të bëni një zgjedhje të ashpër midis disponueshmërisë dhe besueshmërisë. Klasterizimi i RabbitMQ është më i përshtatshëm për situata më të pazakonta, ku përfitimet e fleksibilitetit të RabbitMQ e tejkalojnë çdo disavantazh të klasterizimit të tij.

Një nga antidotet ndaj dobësisë së RabbitMQ në lidhje me radhët e mëdha është t'i ndash ato në shumë më të vogla. Nëse nuk kërkohet renditje e plotë e gjithë radhës, por vetëm e mesazheve përkatëse (p.sh. mesazhet e një klienti të caktuar), ose asgjë të renditur fare, atëherë kjo mundësi është e pranueshme: shihni projektin tim Rebalanser për ndarjen e radhës (projekti është ende në fazë të hershme).

Në fund, mos harroni për një sërë problemesh në mekanizmat e klasterizimit dhe replikimit si te RabbitMQ ashtu edhe te Kafka. Me kalimin e kohës sistemet janë bërë më të pjekura dhe të qëndrueshme, por asnjë mesazh nuk do të jetë ndonjëherë 100% i mbrojtur nga humbja! Për më tepër, në qendrat e të dhënave ndodhin katastrofa masive!

Nëse kam lënë diçka jashtë, kam bërë një gabim, ose nuk jeni dakord me ndonjë nga tezën, mos ngurroni të shkruani një koment apo të më kontaktoni.

Më pyesin shpesh: “Çfarë të zgjedh, Kafka apo RabbitMQ?”, “Cili është sistemi më i mirë?”. E vërteta është se, kjo varet vërtet nga situata juaj, eksperienca aktuale etj. Nuk guxoj të shpreh mendimin tim, pasi do të ishte një thjeshtim shumë i madh të rekomandoj një platformë të vetme për të gjitha përdorimet e mundshme dhe kufizimet. Kam shkruar këtë cikël artikujsh, që ju mund të formoni mendimin tuaj.

Dua të them se të dy sistemet janë liderë në këtë fushë. Ndoshta jam pak i paragjykuar, pasi përvojat e mia në projekte më bëjnë më të prirur të vlerësoj gjëra si renditja e garantuar e mesazheve dhe besueshmëria.

Shoh teknologji të tjera që u mungon kjo besueshmëri dhe renditje e garantuar, pastaj shoh RabbitMQ dhe Kafka — dhe kuptoj vlerën e jashtëzakonshme të këtyre dy sistemeve.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster