Kuidas Kafka sai reaalsuseks

Kuidas Kafka sai reaalsuseks

Tere, Habr!

Töötan Tinkoffi meeskonnas, mis tegeleb enda teavituskeskuse arendamisega. Enamasti arendan Java-s, kasutades Spring Boot'i, ja lahendan erinevaid tehnilisi probleeme, mis projektis ilmnevad.

Enamik meie mikroteenustest suhtleb omavahel asĂŒnkroonselt sĂ”numite vahendaja kaudu. Varem kasutasime brokerina IBM MQ-d, mis ei suutnud koormuse tĂ”ttu enam hakkama saada, kuid pakkus siiski kĂ”rgeid kohaletoimetamise garantiisid.

Asenduseks pakuti meile Apache Kafka, mis omab suurt skaleeritavuse potentsiaali, kuid nÔuab paraku praktiliselt individuaalset lÀhenemist erinevate stsenaariumide seadistamisel. Lisaks ei vÔimaldanud vaikimisi töötav at least once delivery mehhanism Kafkas sÀilitada vajalikku jÀrjepidevuse taset. Edasi jagan meie kogemust Kafka seadistamisel, milles rÀÀgin, kuidas seadistada ja elada exactly once delivery'ga.

Kohustatud kohaletoimetamine ja mitte ainult

Seadistused, millest rÀÀgime, aitavad vĂ€ltida rida probleeme vaikeseadistustega. Kuid enne tahaksin pöörata tĂ€helepanu ĂŒhele seadistusele, mis lihtsustab vĂ”imalikku veaotsingut.

Sellel aitab client.id Produceri ja Consumeri jaoks. Esmapilgul saab vÀÀrtusena kasutada rakenduse nime ja enamikul juhtudel see ka toimib. Siiski, olukord, kus rakenduses kasutatakse mitu Consumer'i ja seadistate neile ĂŒhe ja sama client.id, toob kaasa jĂ€rgmise hoiatuse:

org.apache.kafka.common.utils.AppInfoParser — Veateade AppInfo mbean'i registreerimisel javax.management.InstanceAlreadyExistsException: kafka.consumer:type=app-info,id=kafka.test-0

Kui soovite kasutada JMX-i rakenduses Kafkaga, vÔib see olla probleem. Sellise juhtumi jaoks on kÔige parem kasutada client.id vÀÀrtusena rakenduse nime ja nÀiteks teema nime kombinatsiooni. Meie seadistuse tulemust saab vaadata kÀsu kafka-consumer-groups Confluenti utiliidilt:

Kuidas Kafka sai reaalsuseks

NĂŒĂŒd vaatame ĂŒle sĂ”numi garantii kohaletoimetamise stsenaariumi. Kafkal on Produceril parameeter acks, mille abil saab seadistada, pĂ€rast kui palju tunnustusi peab klastriliider sĂ”numit edukaks kirjutamiseks lugema. Sellel parameetril vĂ”ivad olla jĂ€rgmised vÀÀrtused:

  • 0 — tunnustusi ei arvestata.
  • 1 — vaikimisi parameeter, nĂ”uab tunnustust ainult 1 repliigilt.
  • −1 — vajalik tunnustus kĂ”ikidelt sĂŒnkroniseeritud repliikidelt (klastriseade min.insync.replicas).

Loetletud vÀÀrtustest on nĂ€ha, et acks, mille vÀÀrtus on −1, tagab kĂ”ige tugevama kinnituse, et sĂ”num ei kao.

Kuna me kĂ”ik teame, on jaotatud sĂŒsteemid ebausaldusvÀÀrsed. Ajutiste tĂ”rgete kaitsmiseks pakub Kafka Producer parameetrit retries, mis vĂ”imaldab mÀÀrata saatmise katsete arvu jooksul delivery.timeout.ms. Kuna parameetri retries vaikimisi vÀÀrtus on Integer.MAX_VALUE (2147483647), saab sĂ”numi korduskatsete arvu reguleerida, muutes ainult delivery.timeout.ms.

Liigume edasi exactly once delivery

Loetletud seaded vĂ”imaldavad meie Producer'itel sĂ”numeid kĂ”rge garantii jĂ€rgi edastada. RÀÀgime nĂŒĂŒd, kuidas tagada, et ainult ĂŒks koopia sĂ”numist salvestatakse Kafka teemas? KĂ”ige lihtsamal juhul peab Producer seadma parameetri enable.idempotence tĂ”eks. Idempotentsus tagab, et konstateeritakse ainult ĂŒks sĂ”num kindlasse partitsiooni ĂŒhes teemas. Idempotentsuse aktiveerimise eelduseks on vÀÀrtused acks = all, retry > 0, max.in.flight.requests.per.connection ≀ 5. Kui need parameetrid pole arendaja poolt mÀÀratud, mÀÀratakse automaatselt eespool loetletud vÀÀrtused.

Kui idempotentsus on seadistatud, tuleb tagada, et samad sÔnumid jÔuavad iga kord samadesse partitsioonidesse. Seda saab teha tootja vÔtme ja parameetri partitioner.class seadistamisega. Alustame vÔtmega. Iga saatmise korral peab see olema sama. Seda on lihtne saavutada, kasutades mÔnda Àridentifikaatorit algsest sÔnumist. Parameetri partitioner.class vaikimisi vÀÀrtus on DefaultPartitioner. Selle vaikimisi partitsioneerimise strateegia kohaselt toimime jÀrgmiselt:

  • Kui partitsioon on selgesĂ”naliselt mÀÀratud sĂ”numi saatmise ajal, siis kasutame seda.
  • Kui partitsioon ei ole mÀÀratud, kuid vĂ”ti on mÀÀratud — valime partitsiooni vĂ”tme hash'i pĂ”hjal.
  • Kui partitsioon ja vĂ”ti ei ole mÀÀratud — valime partitsioonide jĂ€rgnevuse alusel (round-robin).

Lisaks sellele pÔhjustab vÔti ja idempotentne saatmine parameetriga max.in.flight.requests.per.connection = 1 annab teie jaoks korrastatud sÔnumite töötlemise Consumeris. Oluline on meeles pidada, et kui teie klastris on seadistatud juurdepÀÀsu haldamine, vajate Ôigusi idempotentseks kirjutamiseks teemasse.

Kui teil on puudus idempotentsest saatmisest vĂ”tme jĂ€rgi vĂ”i Produceri poolel nĂ”uab loogika erinevate partitsioonide vahel andmete jĂ€rjepidevuse sĂ€ilitamist, tulevad appi tehingud. Lisaks saab ketittehingute abil tinglikult sĂŒnkroonida kirjutamist Kafka's, nĂ€iteks andmebaasi kirjaga. Tehingulise saatmise lubamiseks peab Producer omama idempotentsust ja lisaks mÀÀrama transactional.id. Kui teie Kafka klastris on seadistatud juurdepÀÀsu haldamine, vajate tehinguliste kirjutiste jaoks, nagu ka idempotentsete jaoks, kirjutamisĂ”igusi, mis vĂ”ivad olla antud maskeeri kaudu, kasutades vÀÀrtust, mis on salvestatud transactional.id-sse.

Formaalselt vÔib tehingu identifikaatorina kasutada mistahes stringi, nÀiteks rakenduse nime. Kuid kui kÀitate mitut sarnase nimega rakenduse instantsi sama transactional.id-ga, peatub esmakÀivitunud instants tÔrge tÔttu, kuna Kafka peab seda zombiprotsessiks.

org.apache.kafka.common.errors.ProducerFencedException: Producer ĂŒritas toimingut vanas ajas. VĂ”i on olemas uuem tootja sama transactionalId-ga vĂ”i tootja tehingu on brokeri poolt aegunud.

Selle probleemi lahendamiseks lisame rakenduse nimele sufiksi, milleks on hostinimi, mille saame keskkonnamuutujatest.

Producer on seadistatud, kuid tehingud Kafka's haldavad vaid sĂ”numi nĂ€htavuse ulatus. Olenemata tehingu staatust on sĂ”num vahetult teema juurde viidud, kuid sellel on tĂ€iendavad sĂŒsteemi atribuudid.

Et selliseid sÔnumeid ei loetaks Consumer'i poolt liiga vara, tuleb tal seada parameeter isolation.level vÀÀrtusele read_committed. Selline Consumer suudab lugeda mitte-tehingulisi sÔnumeid nagu varem, kuid tehingulisi ainult pÀrast kinnitamist.
Kui olete seadistanud kÔik eelnevalt loetletud seaded, olete seadistanud exactly once delivery. Palju Ônne!

Kuid on veel ĂŒks nĂŒanss. Transactional.id, mida me ĂŒlal seadistasime, on tegelikult tehingu eelosa. Tehingu halduri juurde lisatakse sellele jĂ€rjestusnumber. Saadud identifikaator vĂ€ljastatakse transactional.id.expiration.ms, mis on konfigureeritud Kafka klastris ja mille vaikimisi vÀÀrtus on „7 pĂ€eva“. Kui selle aja jooksul rakendus ei saa mingeid sĂ”numeid, siis jĂ€rgmise tehingu saatmise katse korral saate InvalidPidMappingException. PĂ€rast seda annab tehingute koordineerija jĂ€rgmise tehingu jaoks uue jĂ€rjestusnumbri. Samuti vĂ”ib sĂ”num kaduda, kui InvalidPidMappingException ei kĂ€sitleta Ă”igesti.

KokkuvÔtete asemel

Nagu nĂ€ha, ei piisa lihtsalt sĂ”numite saatmisest Kafka-sse. Tuleb valida parameetrite kombinatsioon ja olla valmis kiireteks muutusteks. Selles artiklis pĂŒĂŒdsin detailides nĂ€idata exactly once delivery seadistust ja kirjeldasin mitmeid client.id ja transactional.id konfiguratsiooni probleeme, millega me kokku puutusime. Allpool on lĂŒhidalt toodud tootja ja tarbija seadistused.

Tootja:

  1. acks = kÔik
  2. retries > 0
  3. enable.idempotence = true
  4. max.in.flight.requests.per.connection ≀ 5 (1 — jĂ€rjekorras saatmiseks)
  5. transactional.id = ${application-name}-${hostname}

Tarbija:

  1. isolation.level = read_committed

Tulevaste rakenduste vigade minimeerimiseks lĂ”ime oma mĂ€hise spring-konfiguratsiooni ĂŒmber, kus on juba seatud vÀÀrtused mĂ”nele ĂŒlalnimetatud parameetrile.

Ja siin on paar materjali iseseisvaks Ôppimiseks:

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster