Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка

Продължение на превода на малка книжка:
Разбиране на брокерите на съобщения
автор: Якуб Кораб, издател: O'Reilly Media, Inc., дата на публикуване: юни 2017 г., ISBN: 9781492049296.

Предишна преведена част: Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 1 Въведение

ГЛАВА 3

Кафка

Kafka е разработен от LinkedIn, за да заобиколи някои от ограниченията на традиционните брокери на съобщения и да избегне необходимостта от настройване на множество брокери на съобщения за различни взаимодействия от точка до точка, което е описано в тази книга под „Мащабиране и разширяване“ на страница 28 Случаи на използване LinkedIn до голяма степен разчита на еднопосочно поглъщане на много големи количества данни, като кликвания върху страници и регистрационни файлове за достъп, като същевременно позволява тези данни да се използват от множество системи, без да се засяга производителността на производителите или другите потребители. Всъщност причината Kafka да съществува е да получи архитектурата за съобщения, която описва Universal Data Pipeline.

Предвид тази крайна цел естествено възникнаха и други изисквания. Кафка трябва:

  • Бъдете изключително бързи
  • Осигурете повече честотна лента при работа със съобщения
  • Поддръжка на модели издател-абонат и от точка до точка
  • Не забавяйте с добавянето на потребители. Например, производителността както на опашката, така и на темата в ActiveMQ се влошава с нарастването на броя на потребителите в дестинацията.
  • Да бъде хоризонтално мащабируем; ако един брокер, който продължава съобщенията, може да го направи само при максимална скорост на диска, тогава има смисъл да отидете отвъд един екземпляр на брокер, за да увеличите производителността
  • Ограничете достъпа до съхраняване и повторно извличане на съобщения

За да постигне всичко това, Kafka възприе архитектура, която предефинира ролите и отговорностите на клиентите и брокерите за съобщения. Моделът JMS е много ориентиран към брокера, където брокерът отговаря за разпространението на съобщения, а клиентите трябва да се тревожат само за изпращането и получаването на съобщения. Kafka, от друга страна, е ориентирана към клиента, като клиентът приема много от характеристиките на традиционен брокер, като справедливо разпределение на подходящи съобщения до потребителите, в замяна на изключително бърз и мащабируем брокер. За хората, които са работили с традиционни системи за съобщения, работата с Kafka изисква фундаментална промяна на съзнанието.
Тази инженерна посока доведе до създаването на инфраструктура за съобщения, способна да увеличи пропускателната способност с много порядъци в сравнение с конвенционален брокер. Както ще видим, този подход идва с компромиси, което означава, че Kafka не е подходящ за определени видове натоварвания и инсталиран софтуер.

Унифициран модел на дестинация

За да изпълни изискванията, описани по-горе, Kafka комбинира публикуване-абониране и съобщения от точка до точка под един вид дестинация − тема. Това е объркващо за хората, които са работили със системи за съобщения, където думата "тема" се отнася до механизъм за излъчване, от който (от темата) четенето е нетрайно. Темите на Кафка трябва да се считат за хибриден тип дестинация, както е дефинирано във въведението към тази книга.

За останалата част от тази глава, освен ако изрично не посочим друго, терминът "тема" ще се отнася до тема на Кафка.

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

Термините "дневник" и "указател" не се появяват в Документация на Кафка. Тези добре познати термини се използват тук за подпомагане на разбирането.

Този модел е напълно различен от ActiveMQ, където съобщенията от всички опашки се съхраняват в един журнал и брокерът маркира съобщенията като изтрити, след като са били прочетени.
Нека сега копаем малко по-дълбоко и да разгледаме дневника на темата по-подробно.
Дневникът на Кафка се състои от няколко дяла (Фигура 3-1). Kafka гарантира строг ред във всяка преграда. Това означава, че съобщенията, записани в дяла в определен ред, ще бъдат прочетени в същия ред. Всеки дял е реализиран като непрекъснат лог файл, който съдържа подмножество (подмножество) от всички съобщения, изпратени до темата от нейните производители. Създадената тема съдържа по подразбиране един дял. Идеята за дялове е централната идея на Кафка за хоризонтално мащабиране.

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-1. Кафка Прегради

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

Четене на съобщения

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

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

Проблемът с четенето може да бъде представен по следния начин:

  • Темата има няколко дяла
  • Няколко групи потребители могат да използват една тема едновременно
  • Група потребители може да има множество отделни инстанции

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

Потребители и потребителски групи

Да вземем за отправна точка тема с един дял (Фигура 3-2).

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-2. Потребителят чете от дяла

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

Когато втори логически потребител се свърже с помощта на различен group_id, той управлява втори указател, който е независим от първия (Фигура 3-3). По този начин тема на Kafka действа като опашка, където има един потребител, и като нормална тема за публикуване-абониране (pub-sub), за която се абонират множество потребители, с допълнителното предимство, че всички съобщения се съхраняват и могат да се обработват многократно.

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-3. Два консуматора в различни потребителски групи четат от един и същи дял

Потребители в потребителска група

Когато един потребителски екземпляр чете данни от дял, той има пълен контрол върху указателя и обработва съобщенията, както е описано в предишния раздел.
Ако няколко екземпляра на потребители са били свързани с един и същ group_id към тема с един дял, тогава екземплярът, който се е свързал последен, ще получи контрол върху показалеца и от този момент нататък ще получава всички съобщения (Фигура 3-4).

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-4. Два консуматора в една и съща консуматорска група четат от един и същи дял

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

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

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

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

Каноничният начин за решаване на този проблем в Кафка е да се използва bОповече дялове.

Преграждане

Дяловете са основният механизъм за паралелно четене и мащабиране на тема извън честотната лента на един екземпляр на брокер. За да разберем по-добре това, нека разгледаме ситуация, при която има тема с два дяла и един потребител се абонира за тази тема (Фигура 3-5).

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-5. Един потребител чете от множество дялове

В този сценарий потребителят получава контрол над указателите, съответстващи на неговия group_id в двата дяла и започва да чете съобщения от двата дяла.
Когато към тази тема се добави допълнителен консуматор за същия group_id, Kafka пренасочва един от дяловете от първия към втория консуматор. След това всеки екземпляр на потребителя ще чете от един дял на темата (Фигура 3-6).

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

Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 3. Кафка
Фигура 3-6. Два консуматора в една и съща консуматорска група четат от различни дялове

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

  • Кой потребител трябва да получи следващото съобщение въз основа на кръговото разпределение, текущия капацитет на буферите за предварително извличане или предишни съобщения (както за JMS групи съобщения).
  • Кои съобщения се изпращат до кои потребители и дали трябва да бъдат доставени отново в случай на повреда.

Всичко, което брокерът Kafka трябва да направи, е да предава съобщения последователно на потребителя, когато последният ги поиска.

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

Изпращане на съобщения

Отговорност на производителя на това съобщение е да реши към кой дял да изпрати съобщение. За да разберем механизма, по който става това, първо трябва да преценим какво точно изпращаме всъщност.

Докато в JMS използваме структура на съобщение с метаданни (заглавки и свойства) и тяло, съдържащо полезния товар (полезен товар), в Kafka съобщението е двойка "ключ-стойност". Полезният товар на съобщението се изпраща като стойност. Ключът, от друга страна, се използва главно за разделяне и трябва да съдържа специфичен ключ за бизнес логикатаза да поставите свързани съобщения в същия дял.

В глава 2 обсъдихме сценария за онлайн залагане, при който свързани събития трябва да бъдат обработени по ред от един потребител:

  1. Потребителският акаунт е конфигуриран.
  2. Парите се кредитират по сметката.
  3. Прави се залог, който тегли пари от сметката.

Ако всяко събитие е съобщение, публикувано в тема, тогава естественият ключ ще бъде ID на акаунта.
Когато се изпрати съобщение с помощта на API на Kafka Producer, то се предава на функция за дял, която, като се има предвид съобщението и текущото състояние на клъстера Kafka, връща идентификатора на дяла, към който трябва да бъде изпратено съобщението. Тази функция е реализирана в Java чрез интерфейса на Partitioner.

Този интерфейс изглежда така:

interface Partitioner {
    int partition(String topic,
        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
}

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

Писане на собствена стратегия за разделяне

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

Тъй като стойността е полезен товар за банков превод, чиято цялост искаме да запазим, нямаме друг избор освен да дефинираме структурата на данните, която да използваме в ключа. Ако приемем, че се нуждаем от идентификатор на акаунт за разделяне, тъй като всички съобщения, свързани с акаунт, трябва да бъдат обработени по ред, ще излезем със следната JSON структура:

{
  "signature": "541661622185851c248b41bf0cea7ad0",
  "accountId": "10007865234"
}

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

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

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

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

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

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

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

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

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

JMS брокерите също трябва да се справят с подобни изисквания. Интересното е, че механизмът за изпращане на свързани съобщения до един и същ потребител, реализиран чрез JMS Message Groups (вариация на стратегията за лепкаво балансиране на натоварването (SLB)), също изисква подателят да маркира съобщенията като свързани. В случая на JMS, брокерът е отговорен за изпращането на тази група от свързани съобщения до един потребител от многото и прехвърлянето на собствеността върху групата, ако потребителят отпадне.

Споразумения с продуценти

Разделянето не е единственото нещо, което трябва да имате предвид, когато изпращате съобщения. Нека да разгледаме методите send() на класа Producer в Java API:

Future < RecordMetadata > send(ProducerRecord < K, V > record);
Future < RecordMetadata > send(ProducerRecord < K, V > record, Callback callback);

Веднага трябва да се отбележи, че и двата метода връщат Future, което показва, че операцията за изпращане не се изпълнява веднага. Резултатът е, че съобщение (ProducerRecord) се записва в буфера за изпращане за всеки активен дял и се изпраща на брокера като фонова нишка в клиентската библиотека на Kafka. Въпреки че това прави нещата невероятно бързи, това означава, че неопитно приложение може да загуби съобщения, ако процесът му бъде спрян.

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

RecordMetadata metadata = producer.send(record).get();

Повече за четенето на съобщения

Четенето на съобщения има допълнителни сложности, за които трябва да се спекулира. За разлика от JMS API, който може да стартира слушател на съобщения в отговор на съобщение, the Потребител Кафка само анкети. Нека разгледаме по-отблизо метода анкета()използвани за тази цел:

ConsumerRecords < K, V > poll(long timeout);

Върнатата стойност на метода е контейнерна структура, съдържаща множество обекти потребителски рекорд от потенциално няколко дяла. потребителски рекорд сам по себе си е обект на притежател за двойка ключ-стойност със свързани метаданни, като например дяла, от който е извлечен.

Както беше обсъдено в Глава 2, трябва да имаме предвид какво се случва със съобщенията, след като са били обработени успешно или неуспешно, например, ако клиентът не може да обработи съобщението или ако то прекъсне. В JMS това беше обработено чрез режим на потвърждение. Брокерът или ще изтрие успешно обработеното съобщение, или ще предаде необработеното или фалшивото съобщение (при условие, че са използвани транзакции).
Кафка работи много различно. Съобщенията не се изтриват в брокера след корекция и какво се случва при повреда е отговорност на самия код за корекция.

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

Връщайки се към модела на четене, обсъден по-рано, обработката на съобщения се състои от три етапа:

  1. Извличане на съобщение за четене.
  2. Обработете съобщението.
  3. Потвърдете съобщението.

Потребителят на Kafka идва с опция за конфигурация enable.auto.commit. Това е често използвана настройка по подразбиране, както е често срещано при настройки, съдържащи думата "автоматично".

Преди Kafka 0.10, клиент, използващ тази опция, изпращаше отместването на последното прочетено съобщение при следващото повикване анкета() след обработка. Това означаваше, че всички съобщения, които вече са били извлечени, могат да бъдат обработени повторно, ако клиентът вече ги е обработил, но е бил неочаквано унищожен преди извикване анкета(). Тъй като брокерът не поддържа никакво състояние за това колко пъти е било прочетено съобщение, следващият потребител, който извлече това съобщение, няма да разбере, че се е случило нещо лошо. Това поведение беше псевдо-транзакция. Отместването се извършва само ако съобщението е обработено успешно, но ако клиентът прекъсне, брокерът ще изпрати същото съобщение отново на друг клиент. Това поведение беше в съответствие с гаранцията за доставка на съобщения "поне веднъж".

В Kafka 0.10 клиентският код е променен, така че ангажиментът да се задейства периодично от клиентската библиотека, както е конфигурирано auto.commit.interval.ms. Това поведение е някъде между режимите JMS AUTO_ACKNOWLEDGE и DUPS_OK_ACKNOWLEDGE. При използване на автоматичен ангажимент съобщенията могат да бъдат ангажименти, независимо дали действително са обработени - това може да се случи в случай на бавен потребител. Ако даден потребител прекъсне, съобщенията ще бъдат извлечени от следващия потребител, започвайки от ангажираната позиция, което може да доведе до пропуснато съобщение. В този случай Kafka не е загубил съобщенията, просто кодът за четене не ги е обработил.

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

Както беше обсъдено в „Четене на съобщения от опашка“ на страница 21, няма такова нещо като еднократна доставка на съобщение в система за съобщения, когато се вземат под внимание режимите на отказ.

В Kafka има два начина за извършване (комитиране) на компенсиране (офсет): автоматично и ръчно. И в двата случая съобщенията могат да се обработват многократно, ако съобщението е било обработено, но е било неуспешно преди ангажимента. Можете също така да изберете да не обработвате съобщението изобщо, ако ангажиментът се е случил във фонов режим и вашият код е бил завършен, преди да може да бъде обработен (може би в Kafka 0.9 и по-стари).

Можете да контролирате процеса на ръчно отместване в потребителския API на Kafka, като зададете параметъра enable.auto.commit до false и изрично извикване на един от следните методи:

void commitSync();
void commitAsync();

Ако искате да обработите съобщението "поне веднъж", трябва да извършите отместването ръчно с commitSync()като изпълните тази команда веднага след обработката на съобщенията.

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

  • Автоматично връщане назад на фалшиво съобщение. Самите потребители трябва да се справят с изключения, произтичащи от проблемни полезни натоварвания и прекъсвания на бекенда, тъй като не могат да разчитат на брокера да доставя повторно съобщения.
  • Изпращайте съобщения до множество теми в една атомна операция. Както ще видим скоро, контролът върху различни теми и дялове може да се намира на различни машини в клъстера на Kafka, които не координират транзакциите при изпращане. По време на писането на тази статия беше свършена известна работа, за да стане това възможно с KIP-98.
  • Свържете четенето на едно съобщение от една тема с изпращането на друго съобщение в друга тема. Отново, архитектурата на Kafka зависи от много независими машини, работещи като една шина и не се прави опит да се скрие това. Например, няма API компоненти, които биха ви позволили да се свържете консуматор и производител в сделка. В JMS това се предоставя от обекта Сесияот които се създават MessageProducers и MessageConsumers.

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

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

void seek(TopicPartition partition, long offset);
void seekToBeginning(Collection < TopicPartition > partitions);

метод търси () може да се използва с метод
offsetsForTimes(Карта timestampsToSearch) за пренавиване до състояние в определен момент в миналото.

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

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

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

Висока наличност

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

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

Кафка е винаги включен система. Много големи потребители на Kafka никога не изключват своите клъстери и софтуерът винаги се актуализира с последователно рестартиране. Това се постига чрез гарантиране на съвместимост с предишната версия за съобщения и взаимодействия между брокери.

Брокери, свързани със сървърен клъстер ZooKeeper, който действа като регистър на конфигурационните данни и се използва за координиране на ролите на всеки брокер. Самият ZooKeeper е разпределена система, която осигурява висока достъпност чрез репликация на информация чрез установяване кворум.

В основния случай се създава тема в клъстер Kafka със следните свойства:

  • Броят на дяловете. Както беше обсъдено по-рано, точната стойност, използвана тук, зависи от желаното ниво на паралелно четене.
  • Коефициентът на репликация (коефициент) определя колко копия на брокер в клъстера трябва да съдържат регистрационни файлове за този дял.

Използвайки ZooKeepers за координация, Kafka се опитва да разпредели справедливо нови дялове между брокерите в клъстера. Това се прави от един екземпляр, който действа като контролер.

По време на изпълнение за всеки раздел на тема контрольор възлагане на роли на брокер лидер (водещ, майстор, водещ) и последователи (последователи, роби, подчинени). Брокерът, действащ като лидер за тази част, отговаря за получаването на всички съобщения, изпратени до него от производителите и разпространението на съобщенията до потребителите. Когато съобщенията се изпращат до раздел на тема, те се копират към всички брокерски възли, действащи като последователи за този дял. Извиква се всеки възел, съдържащ регистрационни файлове за дял реплика. Брокерът може да действа като лидер за някои дялове и като последовател за други.

Извиква се последовател, съдържащ всички съобщения, държани от лидера синхронизирана реплика (реплика, която е в синхронизирано състояние, синхронизирана реплика). Ако брокер, действащ като лидер за дял, отпадне, всеки брокер, който е актуален или синхронизиран за този дял, може да поеме водещата роля. Това е невероятно устойчив дизайн.

Част от конфигурацията на производителя е параметърът АСК, което определя колко реплики трябва да потвърдят (потвърдят) получаването на съобщение, преди нишката на приложението да продължи да изпраща: 0, 1 или всички. Ако е зададено на all, тогава когато се получи съобщение, лидерът ще изпрати потвърждение обратно на производителя веднага щом получи потвърждения (потвърждения) на записа от няколко сигнали (включително самия него), дефинирани от настройката на темата min.insync.реплики (по подразбиране 1). Ако съобщението не може да бъде репликирано успешно, тогава производителят ще хвърли изключение на приложението (NotEnoughReplicas или NotEnoughReplicasAfterAppend).

Типична конфигурация създава тема с коефициент на репликация 3 (1 лидер, 2 последователи на дял) и параметъра min.insync.реплики е настроен на 2. В този случай клъстерът ще позволи на един от брокерите, управляващи дяла на темата, да излезе от работа, без да засяга клиентските приложения.

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

Използвайки тази схема за репликация, Kafka умело избягва необходимостта от физическо записване на всяко съобщение на диск с операцията синхронизиране (). Всяко съобщение, изпратено от производителя, ще бъде записано в регистрационния файл на дяла, но както беше обсъдено в Глава 2, записът във файл първоначално се извършва в буфера на операционната система. Ако това съобщение се репликира към друг екземпляр на Kafka и е в неговата памет, загубата на лидера не означава, че самото съобщение е загубено - то може да бъде поето от синхронизирана реплика.
Отказ от извършване на операцията синхронизиране () означава, че Kafka може да получава съобщения толкова бързо, колкото може да ги записва в паметта. Обратно, колкото по-дълго можете да избягвате изчистването на паметта на диска, толкова по-добре. Поради тази причина не е необичайно за брокерите на Kafka да бъдат разпределени 64 GB или повече памет. Това използване на паметта означава, че един екземпляр на Kafka може лесно да работи със скорости много хиляди пъти по-бързи от традиционния брокер на съобщения.

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

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

Резултати от

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

Предишна преведена част: Разбиране на брокерите на съобщения. Изучаване на механиката на съобщенията с ActiveMQ и Kafka. Глава 1

Извършен превод: tele.gg/middle_java

За да се продължи ...

В анкетата могат да участват само регистрирани потребители. Впиши се, Моля те.

Кафка използва ли се във вашата организация?

  • Да

  • Не

  • Използван преди, сега не

  • Планираме да използваме

38 потребители гласуваха. 8 потребители се въздържаха.

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

Добавяне на нов коментар