RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност

В последната статия разгледахме клъстерирането на RabbitMQ за толерантност към грешки и висока достъпност. Сега нека се задълбочим в Apache Kafka.

Тук единицата за репликация е дялът. Всяка тема има един или повече раздели. Всеки раздел има лидер със или без последователи. Когато създавате тема, вие определяте броя на дяловете и коефициента на репликация. Обичайната стойност е 3, което означава три реплики: един лидер и двама последователи.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 1. Четири секции са разпределени между трима брокери

Всички заявки за четене и писане отиват при лидера. Последователите периодично изпращат заявки до лидера, за да получат най-новите съобщения. Потребителите никога не се обръщат към последователи; последните съществуват само за излишък и толерантност към грешки.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност

Повреда на дяла

Когато един брокер се провали, лидерите на няколко секции често се провалят. Във всеки от тях последовател от друг възел става лидер. Всъщност това не винаги е така, тъй като факторът на синхронизация също влияе: дали има синхронизирани последователи и ако не, тогава дали е разрешено преминаването към несинхронизирана реплика. Но да не усложняваме нещата засега.

Брокер 3 напуска мрежата и се избира нов лидер за секция 2 при брокер 2.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 2. Брокер 3 умира и неговият последовател на брокер 2 е избран за нов лидер на дял 2

Тогава брокер 1 напуска и секция 1 също губи лидера си, чиято роля преминава към брокер 2.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 3. Остана един брокер. Всички лидери са на един брокер с нулево излишък

Когато брокер 1 се върне онлайн, той добавя четирима последователи, осигурявайки известно излишък на всеки дял. Но всички лидери все още остават на брокер 2.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 4. Лидерите остават на брокер 2

Когато се появи брокер 3, се връщаме към три реплики на дял. Но всички лидери все още са на брокер 2.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 5. Небалансирано разположение на лидерите след възстановяването на брокери 1 и 3

Kafka има инструмент за по-добро ребалансиране на лидери от RabbitMQ. Там трябваше да използвате плъгин или скрипт на трета страна, който промени правилата за мигриране на главния възел чрез намаляване на излишъка по време на мигрирането. В допълнение, за големи опашки трябваше да приемем недостъпност по време на синхронизация.

Кафка има концепцията за „предпочитаните реплики“ за водещата роля. Когато се създават дялове на теми, Kafka се опитва да разпредели лидерите равномерно между възлите и маркира тези първи лидери като предпочитани. С течение на времето, поради рестартиране на сървъра, повреди и прекъсване на връзката, лидерите може да се окажат на други възли, както в крайния случай, описан по-горе.

За да коригира това, Kafka предлага две опции:

  • Вариант auto.leader.rebalance.enable=true позволява на възела на контролера автоматично да преназначава лидерите обратно към предпочитаните реплики и по този начин да възстанови равномерното разпределение.
  • Администраторът може да стартира скрипта kafka-preferred-replica-election.sh за ръчно преназначаване.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 6. Реплики след ребалансиране

Това беше опростена версия на провала, но реалността е по-сложна, въпреки че тук няма нищо прекалено сложно. Всичко се свежда до синхронизирани реплики (In-Sync Replicas, ISR).

Синхронизирани реплики (ISR)

ISR е набор от реплики на дял, който се счита за „синхронизиран“ (в синхрон). Има лидер, но може да няма последователи. Последователят се счита за синхронизиран, ако е направил точни копия на всички съобщения на лидера преди изтичането на интервала replica.lag.time.max.ms.

Последовател се премахва от набора ISR, ако:

  • не направи заявка за избор за интервала replica.lag.time.max.ms (предполага се за мъртъв)
  • не успя да се актуализира през интервала replica.lag.time.max.ms (счита се за бавен)

Последователите правят заявки за вземане на проби в интервала replica.fetch.wait.max.ms, което по подразбиране е 500ms.

За да обясним ясно целта на ISR, трябва да разгледаме потвържденията от производителя и някои сценарии за неуспех. Производителите могат да избират кога брокерът изпраща потвърждение:

  • acks=0, потвърждението не се изпраща
  • acks=1, потвърждението се изпраща, след като лидерът е написал съобщение в своя локален журнал
  • acks=all, потвърждението се изпраща, след като всички реплики в ISR са записали съобщението в локалните регистрационни файлове

В терминологията на Kafka, ако ISR е запазил съобщение, то е „отдадено“. Acks=all е най-безопасният вариант, но също така добавя допълнително забавяне. Нека да разгледаме два примера за неуспех и как различните опции за „acks“ взаимодействат с концепцията за ISR.

Acks=1 и ISR

В този пример ще видим, че ако лидерът не изчака всяко съобщение от всички последователи да бъде запазено, тогава е възможна загуба на данни, ако лидерът се провали. Навигирането до несинхронизиран последовател може да бъде активирано или деактивирано чрез настройка нечист.лидер.избори.разрешаване.

В този пример производителят има стойност acks=1. Разделът е разпределен между трите брокера. Брокер 3 изостава, той се синхронизира с лидера преди осем секунди и сега изостава с 7456 съобщения. Брокер 1 изостана само с една секунда. Нашият продуцент изпраща съобщение и бързо получава обратна потвърждение, без допълнителни разходи за бавни или мъртви последователи, които лидерът не чака.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 7. ISR с три реплики

Брокер 2 се проваля и производителят получава грешка при свързване. След като лидерството премине към брокер 1, ние губим 123 съобщения. Последователят на брокер 1 беше част от ISR, но не беше напълно синхронизиран с лидера, когато падна.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 8. Съобщенията се губят, когато се срине

В конфигурация bootstrap.сървъри Производителят има няколко изброени брокера и може да попита друг брокер кой е новият лидер на раздела. След това установява връзка с брокер 1 и продължава да изпраща съобщения.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 9. Изпращането на съобщения се възобновява след кратко прекъсване

Брокер 3 е още по-назад. Прави заявки за извличане, но не може да синхронизира. Това може да се дължи на бавна мрежова връзка между брокери, проблем със съхранението и т.н. Премахва се от ISR. Сега ISR се състои от една реплика - лидерът! Производителят продължава да изпраща съобщения и да получава потвърждения.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 10. Последователят на брокер 3 е отстранен от ISR

Брокер 1 пада и лидерската роля отива на брокер 3 със загуба на 15286 съобщения! Производителят получава съобщение за грешка при свързване. Преходът към лидер извън ISR беше възможен само поради настройката unclean.leader.election.enable=true. Ако е инсталиран в фалшив, тогава преходът няма да се случи и всички заявки за четене и запис ще бъдат отхвърлени. В този случай чакаме брокер 1 да се върне с непокътнати данни в репликата, която отново ще поеме ръководството.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 11. Брокер 1 пада. Когато възникне повреда, голям брой съобщения се губят

Продуцентът установява връзка с последния брокер и вижда, че той вече е лидер на секцията. Той започва да изпраща съобщения до брокер 3.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 12. След кратка пауза съобщенията се изпращат отново към секция 0

Видяхме, че освен кратки прекъсвания за създаване на нови връзки и търсене на нов лидер, производителят непрекъснато изпраща съобщения. Тази конфигурация гарантира наличност за сметка на последователност (сигурност на данните). Кафка загуби хиляди съобщения, но продължи да приема нови писания.

Acks=всички и ISR

Нека повторим този сценарий отново, но с acks=всички. Брокер 3 има средна латентност от четири секунди. Производителят изпраща съобщение с acks=всички, а сега не получава бърз отговор. Лидерът изчаква съобщението да бъде запазено от всички реплики в ISR.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 13. ISR с три реплики. Единият е бавен, което води до забавяне на записа

След четири секунди допълнително забавяне, брокер 2 изпраща ack. Всички реплики вече са напълно актуализирани.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 14. Всички реплики запазват съобщения и изпращат ack

Брокер 3 сега изостава още повече и е премахнат от ISR. Забавянето е значително намалено, тъй като в ISR не са останали бавни реплики. Брокер 2 сега чака само брокер 1 и той има среден лаг от 500 ms.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 15. Репликата на брокер 3 се премахва от ISR

Тогава брокер 2 пада и лидерството преминава към брокер 1 без загуба на съобщения.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 16. Брокер 2 пада

Производителят намира нов лидер и започва да му изпраща съобщения. Забавянето е допълнително намалено, защото ISR сега се състои от една реплика! Следователно опцията acks=всички не добавя излишък.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 17. Реплика на брокер 1 поема водеща роля, без да губи съобщения

След това брокер 1 се срива и преднината отива при брокер 3 със загуба на 14238 съобщения!

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 18. Брокер 1 умира и преходът на ръководството с нечиста настройка води до голяма загуба на данни

Не можахме да инсталираме опцията нечист.лидер.избори.разрешаване в смисъл вярно. По подразбиране е равно на фалшив. Настройки acks=всички с unclean.leader.election.enable=true осигурява достъпност с известна добавена сигурност на данните. Но както виждате, все още можем да загубим съобщения.

Но какво, ако искаме да повишим сигурността на данните? Можете да поставите unclean.leader.election.enable = невярно, но това не е задължително да ни предпази от загуба на данни. Ако лидерът падне силно и вземе данните със себе си, тогава съобщенията все още се губят, плюс наличността се губи, докато администраторът не възстанови ситуацията.

По-добре е да се уверите, че всички съобщения са излишни и в противен случай изхвърлете записа. Тогава, поне от гледна точка на брокера, загубата на данни е възможна само в случай на две или повече едновременни повреди.

Acks=всички, min.insync.replicas и ISR

С конфигурация на темата min.insync.реплики Повишаваме нивото на сигурност на данните. Нека отново да преминем през последната част от предишния сценарий, но този път с min.insync.replicas=2.

Така че брокер 2 има водещ реплика и последователят на брокер 3 се премахва от ISR.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 19. ISR от две реплики

Брокер 2 пада и лидерството преминава към брокер 1 без загуба на съобщения. Но сега ISR се състои само от една реплика. Това не отговаря на минималния брой за получаване на записи и следователно брокерът отговаря на опита за запис с грешка NotEnoughReplicas.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 20. Броят на ISR е с един по-малък от посочения в min.insync.replicas

Тази конфигурация жертва наличността за последователност. Преди да потвърдим съобщение, ние гарантираме, че то е написано в поне две реплики. Това дава на производителя много повече увереност. Тук загубата на съобщение е възможна само ако две реплики се провалят едновременно в кратък интервал, докато съобщението не бъде репликирано към допълнителен последовател, което е малко вероятно. Но ако сте супер параноик, можете да зададете коефициента на репликация на 5 и min.insync.реплики с 3. Тук трима брокера трябва да паднат едновременно, за да загубят рекорда! Разбира се, вие плащате за тази надеждност в допълнително забавяне.

Когато достъпността е необходима за сигурността на данните

Както в случай с RabbitMQ, понякога достъпността е необходима за сигурността на данните. Ето за какво трябва да помислите:

  • Може ли издателят просто да върне грешка и да накара услугата нагоре или потребителя да опита отново по-късно?
  • Може ли издателят да запази съобщението локално или в базата данни, за да опита отново по-късно?

Ако отговорът е не, тогава оптимизирането на наличността подобрява сигурността на данните. Ще загубите по-малко данни, ако изберете наличност вместо да не записвате. Така всичко се свежда до намиране на баланс, а решението зависи от конкретната ситуация.

Значението на ISR

Пакетът ISR ви позволява да изберете оптималния баланс между сигурност на данните и латентност. Например, осигурете наличност в случай на повреда на повечето реплики, минимизирайки въздействието на мъртви или бавни реплики по отношение на латентността.

Ние сами избираме значението replica.lag.time.max.ms според вашите нужди. По същество този параметър означава колко забавяне сме готови да приемем, когато acks=всички. Стойността по подразбиране е десет секунди. Ако това е твърде дълго за вас, можете да го намалите. Тогава честотата на промените в ISR ще се увеличи, тъй като последователите ще бъдат премахвани и добавяни по-често.

RabbitMQ е просто набор от огледала, които трябва да бъдат копирани. Бавните огледала въвеждат допълнителна латентност и мъртвите огледала могат да изчакат, докато пакетите, които проверяват наличността на всеки възел (net tick), отговорят. ISR е интересен начин за избягване на тези проблеми със закъснението. Но рискуваме да загубим излишък, тъй като ISR може да се свие само до лидера. За да избегнете този риск, използвайте настройката min.insync.реплики.

Гаранция за връзка с клиента

В настройките bootstrap.сървъри производителят и потребителят могат да посочат множество брокери за свързване на клиенти. Идеята е, че когато един възел падне, остават няколко резервни, с които клиентът може да отвори връзка. Това не са непременно лидери на секции, а просто трамплин за първоначално зареждане. Клиентът може да ги попита кой възел хоства лидера на дяла за четене/запис.

В RabbitMQ клиентите могат да се свързват с всеки възел и вътрешното маршрутизиране изпраща заявката до мястото, където трябва да отиде. Това означава, че можете да инсталирате балансьор на натоварването пред RabbitMQ. Kafka изисква клиентите да се свързват към възела, който хоства съответния лидер на дял. В такава ситуация не можете да инсталирате балансьор на натоварването. списък bootstrap.сървъри Изключително важно е клиентите да имат достъп и да намерят правилните възли след повреда.

Консенсусна архитектура на Кафка

Досега не сме разглеждали как клъстерът научава за падането на брокера и как се избира нов лидер. За да разберете как Kafka работи с мрежови дялове, първо трябва да разберете консенсусната архитектура.

Всеки клъстер Kafka се внедрява заедно с клъстер Zookeeper, който е разпределена услуга за консенсус, която позволява на системата да постигне консенсус за дадено състояние, като дава приоритет на последователността пред наличността. Изисква се съгласието на мнозинството от възлите на Zookeeper за одобряване на операциите за четене и запис.

Zookeeper съхранява състоянието на клъстера:

  • Списък с теми, раздели, конфигурация, текущи реплики на лидери, предпочитани реплики.
  • Членове на клъстера. Всеки брокер пингва клъстера Zookeeper. Ако не получи ping в рамките на определен период от време, тогава Zookeeper записва брокера като недостъпен.
  • Избор на основни и резервни възли за контролера.

Контролният възел е един от брокерите на Kafka, който отговаря за избирането на лидери на реплики. Zookeeper изпраща известия до контролера относно членството в клъстера и промените в темите и контролерът трябва да действа спрямо тези промени.

Например, нека вземем нова тема с десет дяла и коефициент на репликация 3. Контролерът трябва да избере лидер за всеки дял, опитвайки се да разпредели оптимално лидерите между брокерите.

За всеки контролер на секция:

  • актуализира информация в Zookeeper за ISR и лидер;
  • Изпраща LeaderAndISRCommand до всеки брокер, който хоства реплика на този дял, като информира брокерите за ISR и лидера.

Когато брокер с лидер падне, Zookeeper изпраща известие до контролера и той избира нов лидер. Отново контролерът първо актуализира Zookeeper и след това изпраща команда до всеки брокер, уведомявайки ги за промяната на ръководството.

Всеки лидер е отговорен за набирането на ISR. Настройки replica.lag.time.max.ms определя кой ще влезе там. Когато ISR се промени, лидерът предава нова информация на Zookeeper.

Zookeeper винаги е информиран за всички промени, така че в случай на повреда управлението да премине плавно към нов лидер.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 21. Консенсус на Кафка

Протокол за репликация

Разбирането на детайлите на репликацията ви помага да разберете по-добре потенциалните сценарии за загуба на данни.

Заявки за вземане на проби, отместване в края на дневника (LEO) и знак за висока вода (HW)

Смятаме, че последователите периодично изпращат заявки за извличане до лидера. Интервалът по подразбиране е 500 ms. Това се различава от RabbitMQ по това, че в RabbitMQ репликацията не се инициира от огледалото на опашката, а от главния. Майсторът натиска промени в огледалата.

Лидерът и всички последователи запазват отместването на края на трупа (LEO) и етикета Highwater (HW). Маркировката LEO съхранява отместването на последното съобщение в локалната реплика, а HW държи отместването на последния комит. Не забравяйте, че за статус на ангажиране, съобщението трябва да се запази във всички ISR реплики. Това означава, че LEO обикновено е малко по-напред от HW.

Когато лидерът получи съобщение, той го съхранява локално. Последователят прави заявка за извличане, като предава своя LEO. След това лидерът изпраща пакет от съобщения, започвайки от този LEO, и също така предава текущия HW. Когато лидерът получи информация, че всички реплики са съхранили съобщението при даденото отместване, той премества знака HW. Само лидерът може да премести HW и така всички последователи ще знаят текущата стойност в отговорите на тяхната заявка. Това означава, че последователите може да изостават от лидера както в посланието, така и в знанията за HW. Потребителите получават съобщения само до текущата HW.

Обърнете внимание, че „запазен“ означава записан в паметта, а не на диска. За производителност Kafka се синхронизира с диск на определен интервал. RabbitMQ също има такъв интервал, но той ще изпрати потвърждение на издателя само след като главният и всички огледални сървъри са записали съобщението на диска. Разработчиците на Kafka, от съображения за производителност, решиха да изпратят ack веднага щом съобщението бъде записано в паметта. Кафка залага, че излишъкът компенсира риска от кратко съхраняване на потвърдените съобщения само в паметта.

Провал на лидера

Когато лидерът падне, Zookeeper уведомява контролера и той избира нова реплика на лидера. Новият лидер определя нова HW марка според своя LEO. След това последователите получават информация за новия лидер. В зависимост от версията на Kafka, последователят ще избере един от два сценария:

  1. Той ще съкрати локалния дневник до известна HW и ще изпрати заявка до новия лидер за съобщения след този знак.
  2. Ще изпрати заявка до лидера, за да открие HW по времето, когато е избран за лидер, и след това ще съкрати дневника до това отместване. След това ще започне да прави периодични заявки за извличане, започвайки от това отместване.

Може да се наложи последовател да съкрати регистрационния файл поради следните причини:

  • Когато лидерът се провали, първият последовател в набора ISR, регистриран в Zookeeper, печели изборите и става лидер. Всички последователи на ISR, въпреки че се считат за „в синхрон“, може да не са получили копия на всички съобщения от бившия лидер. Напълно възможно е представеният последовател да не разполага с най-актуалното копие. Кафка гарантира, че няма разминаване между репликите. По този начин, за да се избегнат несъответствия, всеки последовател трябва да съкрати своя дневник до HW стойността на новия лидер към момента на избирането му. Това е още една причина за настройка acks=всички толкова важно за последователността.
  • Съобщенията периодично се записват на диск. Ако всички възли на клъстера се повредят едновременно, тогава реплики с различни отмествания ще бъдат съхранени на дисковете. Възможно е, когато брокерите се върнат онлайн, новият лидер, който е избран, да е зад своите последователи, защото той е бил записан на диск преди останалите.

Обединение с клъстера

Когато се присъединят отново към клъстера, репликите правят същото, както когато лидерът се провали: те проверяват репликата на лидера и съкращават своя дневник до неговата HW (по време на избора). За сравнение, RabbitMQ еднакво третира обединените възли като напълно нови. И в двата случая брокерът отхвърля всяко съществуващо състояние. Ако се използва автоматична синхронизация, тогава главният трябва да репликира абсолютно цялото текущо съдържание към новото огледало по метода „оставете целия свят да изчака“. Главният не приема никакви операции за четене или запис по време на тази операция. Този подход създава проблеми при големи опашки.

Kafka е разпределен журнал и като цяло съхранява повече съобщения от RabbitMQ опашка, където данните се премахват от опашката, след като бъдат прочетени. Активните опашки трябва да останат относително малки. Но Kafka е дневник със собствена политика за задържане, която може да зададе период от дни или седмици. Подходът за блокиране на опашка и пълна синхронизация е абсолютно неприемлив за разпределен журнал. Вместо това, последователите на Кафка просто съкращават своя дневник до HW на лидера (по време на избирането му), ако тяхното копие е пред лидера. В по-вероятния случай, когато последователят изостава, той просто започва да прави заявки за извличане, започвайки от текущия си LEO.

Нови или присъединили се отново последователи започват извън ISR и не участват в ангажименти. Те просто работят заедно с групата, като получават съобщения възможно най-бързо, докато настигнат лидера и влязат в ISR. Няма заключване и няма нужда да изхвърляте всичките си данни.

Прекъсване на връзката

Kafka има повече компоненти от RabbitMQ, така че има по-сложен набор от поведения, когато клъстерът бъде прекъснат. Но Kafka първоначално е проектиран за клъстери, така че решенията са много добре обмислени.

По-долу са дадени няколко сценария за неуспешна връзка:

  • Сценарий 1: Последователят не вижда лидера, но все пак вижда пазителя на зоопарка.
  • Сценарий 2: Лидерът не вижда никакви последователи, но все още вижда Zookeeper.
  • Сценарий 3: Последователят вижда лидера, но не вижда пазача на зоопарка.
  • Сценарий 4: Лидерът вижда последователите, но не вижда пазителя на зоопарка.
  • Сценарий 5: Последователят е напълно отделен както от другите възли на Kafka, така и от Zookeeper.
  • Сценарий 6: Лидерът е напълно отделен както от другите възли на Kafka, така и от Zookeeper.
  • Сценарий 7: Възелът на контролера на Kafka не може да види друг възел на Kafka.
  • Сценарий 8: Контролерът Kafka не вижда Zookeeper.

Всеки сценарий има свое поведение.

Сценарий 1: Последователят не вижда лидера, но все още вижда Zookeeper

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 22. Сценарий 1: ISR на три реплики

Неуспешната връзка разделя брокер 3 от брокери 1 и 2, но не и от Zookeeper. Брокер 3 вече не може да изпраща заявки за извличане. След като изтече време replica.lag.time.max.ms той е премахнат от ISR и не участва в ангажименти на съобщения. След като връзката бъде възстановена, той ще възобнови заявките за извличане и ще се присъедини към ISR, когато настигне лидера. Zookeeper ще продължи да получава ping и ще приеме, че брокерът е жив и здрав.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 23. Сценарий 1: Брокерът се премахва от ISR, ако от него не се получи заявка за извличане в рамките на интервала replica.lag.time.max.ms

Няма разделен мозък или спиране на възли като в RabbitMQ. Вместо това излишъкът е намален.

Сценарий 2: Лидерът не вижда никакви последователи, но все още вижда Zookeeper

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 24. Сценарий 2. Лидер и двама последователи

Прекъсването на мрежовата свързаност разделя лидера от последователите, но брокерът все още може да види Zookeeper. Както в първия сценарий, ISR се свива, но този път само до лидера, тъй като всички последователи спират да изпращат заявки за извличане. Отново няма логично разделение. Вместо това има загуба на излишък за нови съобщения, докато връзката не бъде възстановена. Zookeeper продължава да получава пингове и вярва, че брокерът е жив и здрав.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 25. Сценарий 2. ISR се е свил само до лидера

Сценарий 3. Последователят вижда лидера, но не вижда пазителя на зоологическата градина

Последователят е отделен от Zookeeper, но не и от брокера с лидера. В резултат на това последователят продължава да прави заявки за извличане и да бъде член на ISR. Zookeeper вече не получава пингове и регистрира срив на брокер, но тъй като е само последовател, няма последствия след възстановяване.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 26. Сценарий 3: Последователят продължава да изпраща заявки за извличане на водача

Сценарий 4. Лидерът вижда последователи, но не вижда Zookeeper

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 27. Сценарий 4. Лидер и двама последователи

Лидерът е отделен от Zookeeper, но не и от брокерите с последователи.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 28. Сценарий 4: Лидерът е изолиран от Zookeeper

След известно време Zookeeper ще регистрира грешка на брокера и ще уведоми администратора за това. Той ще избере нов лидер сред своите последователи. Първоначалният лидер обаче ще продължи да мисли, че е лидерът и ще продължи да приема записи от acks=1. Последователите вече не му изпращат заявки за извличане, така че той ще ги смята за мъртви и ще се опита да свие ISR до себе си. Но тъй като няма връзка със Zookeeper, няма да може да направи това и в този момент ще откаже да приеме други записи.

Сообщения acks=всички няма да получи потвърждение, защото ISR първо включва всички реплики и съобщенията не достигат до тях. Когато първоначалният лидер се опита да ги премахне от ISR, той няма да може да го направи и изобщо ще спре да приема съобщения.

Клиентите скоро забелязват промяната в лидера и започват да изпращат записи към новия сървър. След като мрежата бъде възстановена, оригиналният лидер вижда, че вече не е лидер и съкращава своя журнал до HW стойността, която новият лидер е имал в момента на повреда, за да избегне разминаване в журнала. След това ще започне да изпраща заявки за извличане на новия лидер. Всички записи от първоначалния лидер, които не са репликирани към новия лидер, се губят. Това означава, че съобщенията, които не са били признати от първоначалния лидер в тези няколко секунди, когато два лидера са работили, ще бъдат загубени.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 29. Сценарий 4. Лидерът на брокер 1 става последовател след възстановяване на мрежата

Сценарий 5: Последователят е напълно отделен както от другите възли на Kafka, така и от Zookeeper

Последователят е напълно изолиран както от другите възли на Kafka, така и от Zookeeper. Той просто се премахва от ISR, докато мрежата не бъде възстановена, и след това настига останалите.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 30. Сценарий 5: Изолиран последовател се премахва от ISR

Сценарий 6: Лидерът е напълно отделен както от другите възли на Kafka, така и от Zookeeper

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 31. Сценарий 6. Лидер и двама последователи

Лидерът е напълно изолиран от своите последователи, контролера и Zookeeper. За кратък период ще продължи да приема записи от acks=1.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 32. Сценарий 6: Изолиране на лидера от други възли на Kafka и Zookeeper

Не са получени заявки след изтичане replica.lag.time.max.ms, ще се опита да свие ISR до себе си, но няма да може да го направи, защото няма комуникация със Zookeeper, след което ще спре да приема записи.

Междувременно Zookeeper ще маркира изолирания брокер като мъртъв и контролерът ще избере нов лидер.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 33. Сценарий 6. Двама лидери

Първоначалният лидер може да приема записи за няколко секунди, но след това спира да приема всякакви съобщения. Клиентите се актуализират на всеки 60 секунди с най-новите метаданни. Те ще бъдат информирани за смяната на лидера и ще започнат да изпращат записи на новия лидер.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 34. Сценарий 6: Производителите преминават към нов лидер

Всички потвърдени записи, направени от първоначалния лидер след загубата на връзка, ще бъдат загубени. След като мрежата бъде възстановена, първоначалният лидер ще открие чрез Zookeeper, че вече не е лидер. След това ще съкрати своя дневник до HW на новия лидер по време на изборите и ще започне да изпраща заявки като последовател.

RabbitMQ срещу Kafka: Толерантност към грешки и висока наличност
Ориз. 35. Сценарий 6: Първоначалният лидер става последовател след възстановяване на мрежовата свързаност

В тази ситуация може да настъпи логична раздяла за кратък период, но само ако acks=1 и min.insync.реплики също 1. Логическото разделяне автоматично приключва или след възстановяване на мрежата, когато първоначалният лидер разбере, че вече не е лидер, или когато всички клиенти разберат, че лидерът се е променил и започнат да пишат на новия лидер - което от двете се случи първо. Във всеки случай някои съобщения ще бъдат загубени, но само с acks=1.

Има друг вариант на този сценарий, при който точно преди мрежата да се раздели, последователите изостават и лидерът компресира ISR само до себе си. След това се изолира поради загуба на връзка. Избира се нов лидер, но първоначалният лидер продължава дори да приема записи acks=всички, защото в ISR няма никой друг освен него. Тези записи ще бъдат загубени, след като мрежата бъде възстановена. Единственият начин да избегнете тази опция е min.insync.replicas = 2.

Сценарий 7: Kafka Controller Node не може да види друг Kafka Node

Като цяло, след като връзката с Kafka възел бъде загубена, контролерът няма да може да предава никаква информация за промяна на лидера към него. В най-лошия случай това ще доведе до краткотрайна логична раздяла, както в сценарий 6. По-често брокерът просто няма да стане кандидат за лидерство, ако последният се провали.

Сценарий 8: Контролерът Kafka не вижда Zookeeper

Zookeeper няма да получи ping от падналия контролер и ще избере нов Kafka възел като контролер. Оригиналният контролер може да продължи да се представя като такъв, но не получава известия от Zookeeper, така че няма да има никакви задачи за изпълнение. След като мрежата бъде възстановена, той ще разбере, че вече не е контролер, а се е превърнал в обикновен Kafka възел.

Изводи от сценариите

Виждаме, че загубата на свързаност на последовател не води до загуба на съобщение, а просто временно намалява излишъка, докато мрежата бъде възстановена. Това, разбира се, може да доведе до загуба на данни, ако един или повече възли са загубени.

Ако лидерът се отдели от Zookeeper поради загуба на връзка, това може да доведе до загуба на съобщения от acks=1. Липсата на комуникация със Zookeeper предизвиква кратък логичен раздяла с двамата лидери. Този проблем се решава от параметъра acks=всички.

Параметър min.insync.реплики в две или повече реплики предоставя допълнителна увереност, че такива краткосрочни сценарии няма да доведат до загубени съобщения, както в сценарий 6.

Резюме на изгубените съобщения

Нека изброим всички начини, по които можете да загубите данни в Kafka:

  • Всяка грешка на лидера, ако съобщенията са потвърдени с помощта на acks=1
  • Всеки нечист преход на лидерство, тоест към последовател извън ISR, дори и с acks=всички
  • Изолиране на лидера от Zookeeper, ако съобщенията са потвърдени чрез acks=1
  • Пълна изолация на лидера, който вече е свил ISR групата до себе си. Дори всички съобщения ще бъдат загубени acks=всички. Това е вярно само ако min.insync.replicas=1.
  • Едновременни повреди на всички възли на дялове. Тъй като съобщенията се потвърждават от паметта, някои може още да не са записани на диска. След рестартиране на сървърите някои съобщения може да липсват.

Нечистите лидерски преходи могат да бъдат избегнати, като се забранят или осигурят поне две съкращения. Най-издръжливата конфигурация е комбинация acks=всички и min.insync.реплики повече от 1.

Директно сравнение на надеждността на RabbitMQ и Kafka

За да осигурят надеждност и висока наличност, двете платформи внедряват първична и вторична репликационна система. RabbitMQ обаче има ахилесова пета. При повторно свързване след повреда възлите изхвърлят своите данни и синхронизирането се блокира. Този двоен удар поставя под въпрос дълголетието на големите опашки в RabbitMQ. Ще трябва да приемете или намалено излишък, или дълги времена на блокиране. Намаляването на излишъка увеличава риска от масивна загуба на данни. Но ако опашките са малки, тогава в името на излишъка, кратки периоди на недостъпност (няколко секунди) могат да се справят с помощта на многократни опити за свързване.

Кафка няма този проблем. Той отхвърля данни само от точката на разминаване между лидера и последователя. Всички споделени данни се запазват. Освен това репликацията не блокира системата. Лидерът продължава да приема публикации, докато новият последовател наваксва, така че за devops присъединяването или повторното присъединяване към клъстера се превръща в тривиална задача. Разбира се, все още има проблеми като честотната лента на мрежата по време на репликация. Ако добавите няколко последователи едновременно, може да срещнете ограничение на честотната лента.

RabbitMQ превъзхожда Kafka по отношение на надеждността, когато няколко сървъра в клъстер се повредят едновременно. Както вече казахме, RabbitMQ изпраща потвърждение на издателя само след като съобщението е записано на диск от главния и всички огледални сървъри. Но това добавя допълнително забавяне по две причини:

  • fsync на всеки няколкостотин милисекунди
  • Неизправността на огледалото може да бъде забелязана само след изтичане на живота на пакетите, които проверяват наличността на всеки възел (net tick). Ако огледалото се забави или падне, това добавя забавяне.

Залогът на Kafka е, че ако едно съобщение се съхранява в множество възли, то може да потвърди съобщенията веднага щом попаднат в паметта. Поради това съществува риск от загуба на съобщения от всякакъв вид (дори acks=всички, min.insync.replicas=2) в случай на едновременен отказ.

Като цяло, Kafka показва по-добра софтуерна производителност и е проектиран от самото начало за клъстери. Броят на последователите може да бъде увеличен до 11, ако е необходимо за надеждност. Коефициент на репликация 5 и минимален брой реплики в синхронизация min.insync.replicas=3 ще направи загубата на съобщение много рядко събитие. Ако вашата инфраструктура може да поддържа това съотношение на репликация и ниво на излишък, тогава можете да изберете тази опция.

Клъстерирането на RabbitMQ е добро за малки опашки. Но дори малките опашки могат да растат бързо, когато има голям трафик. След като опашките станат големи, ще трябва да направите труден избор между наличност и надеждност. Клъстерирането на RabbitMQ е най-подходящо за нетипични ситуации, при които ползите от гъвкавостта на RabbitMQ превъзхождат всички недостатъци на неговото клъстериране.

Един антидот срещу уязвимостта на RabbitMQ към големи опашки е да ги разделите на много по-малки опашки. Ако не изисквате пълно подреждане на цялата опашка, а само съответните съобщения (например съобщения от конкретен клиент) или изобщо не поръчвате нищо, тогава тази опция е приемлива: вижте моя проект Rebalancer за разделяне на опашката (проектът все още е на ранен етап).

И накрая, не забравяйте за редица грешки в механизмите за клъстериране и репликация както на RabbitMQ, така и на Kafka. С течение на времето системите станаха по-зрели и стабилни, но никое съобщение няма да бъде 100% защитено от загуба! Освен това в центровете за данни се случват мащабни аварии!

Ако съм пропуснал нещо, допуснал съм грешка или не сте съгласни с някоя от точките, не се колебайте да напишете коментар или да се свържете с мен.

Често ме питат: „Какво да избера, Kafka или RabbitMQ?“, „Коя платформа е по-добра?“. Истината е, че наистина зависи от вашата ситуация, текущия опит и т.н. Колебая се да дам мнението си, защото би било прекалено опростяване да се препоръчва една платформа за всички случаи на употреба и възможни ограничения. Написах тази поредица от статии, за да можете да си съставите собствено мнение.

Искам да кажа, че и двете системи са водещи в тази област. Може да съм малко предубеден, защото от моя опит с проекти съм склонен да ценя неща като гарантирано подреждане на съобщения и надеждност.

Виждам други технологии, на които липсва тази надеждност и гарантирана подредба, след това разглеждам RabbitMQ и Kafka и осъзнавам невероятната стойност на двете системи.

Източник: www.habr.com

Купете надежден хостинг за сайтове с DDoS защита, VPS VDS сървъри 🔥 Купете надежден уеб хостинг със защита от DDoS атаки, VPS VDS сървъри | ProHoster