Kā Kafka kļuva par realitāti

Kā Kafka kļuva par realitāti

Čau Habr!

Es strādāju Tinkoff komandā, kas izstrādā savu paziņojumu centru. Es galvenokārt izstrādāju Java, izmantojot Spring boot un risinu dažādas tehniskas problēmas, kas rodas projektā.

Lielākā daļa mÅ«su mikropakalpojumu savstarpēji sazinās asinhroni, izmantojot ziņojumu brokeri. IepriekÅ” kā brokeris izmantojām IBM MQ, kas vairs netika galā ar slodzi, bet tajā paŔā laikā bija augstas piegādes garantijas.

Kā nomaiņa mums tika piedāvāta Apache Kafka, kurai ir augsts mērogoÅ”anas potenciāls, bet diemžēl nepiecieÅ”ama gandrÄ«z individuāla pieeja dažādu scenāriju konfigurÄ“Å”anai. Turklāt vismaz vienreizējais piegādes mehānisms, kas pēc noklusējuma darbojas Kafkā, neļāva saglabāt nepiecieÅ”amo konsekvences lÄ«meni no kastes. Tālāk es dalÄ«Å”os pieredzē par Kafka konfigurāciju, jo Ä«paÅ”i, es jums pastāstÄ«Å”u, kā konfigurēt un dzÄ«vot ar precÄ«zi piegādes reizi.

Garantēta piegāde un vairāk

Tālāk aprakstÄ«tie iestatÄ«jumi palÄ«dzēs novērst vairākas problēmas ar noklusējuma savienojuma iestatÄ«jumiem. Bet vispirms es gribētu pievērst uzmanÄ«bu vienam parametram, kas atvieglos iespējamo atkļūdoÅ”anu.

Tas palÄ«dzēs klienta.id ražotājiem un patērētājiem. No pirmā acu uzmetiena kā vērtÄ«bu varat izmantot lietojumprogrammas nosaukumu, un vairumā gadÄ«jumu tas darbosies. Lai gan situācija, kad lietojumprogramma izmanto vairākus patērētājus un jÅ«s tiem pieŔķirat vienu un to paÅ”u client.id, tiek parādÄ«ts Ŕāds brÄ«dinājums:

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

Ja vēlaties izmantot JMX lietojumprogrammā ar Kafka, tā varētu būt problēma. Šajā gadījumā kā klienta.id vērtību vislabāk ir izmantot lietojumprogrammas nosaukuma un, piemēram, tēmas nosaukuma kombināciju. Mūsu konfigurācijas rezultātu var redzēt komandas izvadē kafka-patērētāju grupas no komunālajiem pakalpojumiem no Confluent:

Kā Kafka kļuva par realitāti

Tagad apskatÄ«sim scenāriju garantētai ziņojumu piegādei. Kafka Producer ir parametrs acks, kas ļauj konfigurēt pēc cik apstiprinājumiem klastera vadÄ«tājam ir nepiecieÅ”ams uzskatÄ«t, ka ziņojums ir veiksmÄ«gi uzrakstÄ«ts. Å im parametram var bÅ«t Ŕādas vērtÄ«bas:

  • 0 ā€” apstiprinājums netiks ņemts vērā.
  • 1 ir noklusējuma parametrs, lai apstiprinātu, ir nepiecieÅ”ama tikai 1 kopija.
  • āˆ’1 ā€” ir nepiecieÅ”ams apstiprinājums no visām sinhronizētajām replikām (klastera iestatÄ«Å”ana min.insync.replicas).

No uzskaitÄ«tajām vērtÄ«bām ir skaidrs, ka acks, kas vienāds ar āˆ’1, dod visspēcÄ«gāko garantiju, ka ziņojums netiks pazaudēts.

Kā mēs visi zinām, sadalÄ«tās sistēmas nav uzticamas. Lai aizsargātu pret pārejoÅ”iem defektiem, Kafka Producer nodroÅ”ina iespēju mēģina vēlreiz, kas ļauj iestatÄ«t atkārtotas nosÅ«tÄ«Å”anas mēģinājumu skaitu piegāde.timeout.ms. Tā kā atkārtojumu parametra noklusējuma vērtÄ«ba ir Integer.MAX_VALUE (2147483647), ziņojuma atkārtojumu skaitu var pielāgot, mainot tikai delivery.timeout.ms.

Mēs virzāmies uz precīzi vienu piegādi

NorādÄ«tie iestatÄ«jumi ļauj mÅ«su ražotājam piegādāt ziņojumus ar augstu garantiju. Tagad parunāsim par to, kā nodroÅ”ināt, lai Kafkas tēmai tiktu rakstÄ«ta tikai viena ziņojuma kopija? VienkārŔākajā gadÄ«jumā, lai to izdarÄ«tu, ir jāiestata parametrs Producer iespējot.idempotence uz patiesÄ«bu. Idempotence garantē, ka vienas tēmas noteiktā nodalÄ«jumā tiek rakstÄ«ts tikai viens ziņojums. Idempotences iespējoÅ”anas priekÅ”noteikums ir vērtÄ«bas acks = visi, mēģiniet vēlreiz > 0, max.in.flight.requests.per.connection ā‰¤ 5. Ja izstrādātājs nav norādÄ«jis Å”os parametrus, iepriekÅ” minētās vērtÄ«bas tiks iestatÄ«tas automātiski.

Kad idempotence ir konfigurēta, ir jānodroÅ”ina, lai tie paÅ”i ziņojumi katru reizi nonāktu vienādos nodalÄ«jumos. To var izdarÄ«t, iestatot partitioner.class atslēgu un parametru uz Producer. Sāksim ar atslēgu. Tam ir jābÅ«t vienādam katram iesniegumam. To var viegli panākt, izmantojot jebkuru no sākotnējās ziņas uzņēmuma ID. Parametram partitioner.class ir noklusējuma vērtÄ«ba āˆ’ DefaultPartitioner. Izmantojot Å”o sadalÄ«Å”anas stratēģiju, pēc noklusējuma mēs rÄ«kojamies Ŕādi:

  • Ja, nosÅ«tot ziņojumu, nodalÄ«jums ir skaidri norādÄ«ts, mēs to izmantojam.
  • Ja nodalÄ«jums nav norādÄ«ts, bet atslēga ir norādÄ«ta, atlasiet nodalÄ«jumu pēc atslēgas jaukÅ”anas.
  • Ja nodalÄ«jums un atslēga nav norādÄ«ti, atlasiet nodalÄ«jumus pa vienam (apkārtējā pārbaude).

ArÄ« atslēgas izmantoÅ”ana un idempotenta sÅ«tÄ«Å”ana ar parametru max.in.flight.requests.per.connection = 1 sniedz jums racionalizētu ziņojumu apstrādi patērētājam. Ir arÄ« vērts atcerēties, ka, ja jÅ«su klasterÄ« ir konfigurēta piekļuves kontrole, jums bÅ«s nepiecieÅ”amas tiesÄ«bas identiski rakstÄ«t tēmā.

Ja pēkŔņi jums trÅ«kst idempotenta sÅ«tÄ«Å”anas ar atslēgu iespēju vai loÄ£ika Producer pusē prasa saglabāt datu konsekvenci starp dažādiem nodalÄ«jumiem, tad transakcijas nāks palÄ«gā. Turklāt, izmantojot ķēdes darÄ«jumu, jÅ«s varat nosacÄ«ti sinhronizēt ierakstu Kafkā, piemēram, ar ierakstu datubāzē. Lai iespējotu darÄ«jumu nosÅ«tÄ«Å”anu Ražotājam, tai jābÅ«t idempotentam un papildus iestatÄ«tam transakciju.id. Ja jÅ«su Kafka klasterim ir konfigurēta piekļuves kontrole, darÄ«juma ierakstam, tāpat kā idempotentam ierakstam, bÅ«s nepiecieÅ”amas rakstÄ«Å”anas atļaujas, kuras var pieŔķirt, izmantojot masku, izmantojot transakcijā.id saglabāto vērtÄ«bu.

Formāli jebkuru virkni, piemēram, lietojumprogrammas nosaukumu, var izmantot kā darÄ«juma identifikatoru. Bet, ja palaižat vairākas vienas un tās paÅ”as lietojumprogrammas instances ar vienu un to paÅ”u transakciju.id, pirmā palaitā instance tiks apturēta ar kļūdu, jo Kafka to uzskatÄ«s par zombiju procesu.

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

Lai atrisinātu Å”o problēmu, lietojumprogrammas nosaukumam pievienojam sufiksu resursdatora nosaukuma formā, ko iegÅ«stam no vides mainÄ«gajiem.

Ražotājs ir konfigurēts, bet darījumi Kafka kontrolē tikai ziņojuma apjomu. Neatkarīgi no darījuma statusa, ziņojums nekavējoties pāriet uz tēmu, bet tam ir papildu sistēmas atribūti.

Lai novērstu Ŕādu ziņojumu lasÄ«Å”anu Patērētājam pirms laika, tam ir jāiestata parametrs izolācija.lÄ«menis uz read_committed vērtÄ«bu. Šāds Patērētājs varēs lasÄ«t ziņojumus, kas nav saistÄ«ti ar darÄ«jumiem, tāpat kā iepriekÅ”, un darÄ«jumu ziņojumus tikai pēc apņemÅ”anās.
Ja esat iestatÄ«jis visus iepriekÅ” norādÄ«tos iestatÄ«jumus, tad esat konfigurējis tieÅ”i piegādes reizi. Apsveicam!

Bet ir vēl viena nianse. Transaction.id, kuru mēs konfigurējām iepriekÅ”, faktiski ir darÄ«juma prefikss. DarÄ«jumu pārvaldniekā tam tiek pievienots kārtas numurs. Saņemtais identifikators tiek izsniegts transakcija.id.expiration.ms, kas ir konfigurēts Kafka klasterÄ« un kura noklusējuma vērtÄ«ba ir ā€œ7 dienasā€. Ja Å”ajā laikā aplikācija nav saņēmusi nevienu ziņojumu, tad, izmēģinot nākamo darÄ«juma sÅ«tÄ«jumu, jÅ«s saņemsit InvalidPidMappingException. Pēc tam darÄ«juma koordinators nākamajam darÄ«jumam izsniegs jaunu kārtas numuru. Tomēr ziņojums var tikt pazaudēts, ja InvalidPidMappingException netiek pareizi apstrādāts.

Kopsummu vietā

Kā redzat, nepietiek vienkārÅ”i nosÅ«tÄ«t ziņojumus Kafkai. Jums ir jāizvēlas parametru kombinācija un jābÅ«t gatavam ātri veikt izmaiņas. Å ajā rakstā es centos detalizēti parādÄ«t precÄ«zu piegādes iestatÄ«Å”anu un aprakstÄ«ju vairākas problēmas ar konfigurācijām client.id un transactional.id, ar kurām mēs saskārāmies. Tālāk ir sniegts ražotāju un patērētāju iestatÄ«jumu kopsavilkums.

Ražotājs:

  1. acks = viss
  2. mēģinājumi > 0
  3. enable.idempotence = patiess
  4. max.in.flight.requests.per.connection ā‰¤ 5 (1 kārtÄ«gai nosÅ«tÄ«Å”anai)
  5. transakcijas.id = ${lietojumprogrammas nosaukums}-${saimniekdatora nosaukums}

Patērētājs:

  1. isolation.level = read_committed

Lai samazinātu kļūdas turpmākajās lietojumprogrammās, mēs izveidojām paÅ”i savu aptinumu virs atsperes konfigurācijas, kur jau ir iestatÄ«tas vērtÄ«bas dažiem no uzskaitÄ«tajiem parametriem.

Šeit ir daži materiāli paŔmācībai:

Avots: www.habr.com

Pievieno komentāru