Kako je Kafka postal resničnost

Kako je Kafka postal resničnost

Pozdravljeni, Habr!

Delam v ekipi Tinkoff, ki razvija svoj center za obveščanje. Večinoma razvijam v Javi s pomočjo Spring boota in rešujem različne tehnične težave, ki nastanejo pri projektu.

Večina naših mikrostoritev komunicira med seboj asinhrono prek posrednika sporočil. Prej smo kot posrednika uporabljali IBM MQ, ki ni več kos obremenitvi, hkrati pa je imel visoke garancije za dostavo.

Kot zamenjavo nam je bil ponujen Apache Kafka, ki ima velik skalirni potencial, a na žalost zahteva skoraj individualen pristop konfiguracije za različne scenarije. Poleg tega mehanizem za vsaj enkratno dostavo, ki privzeto deluje v Kafki, ni omogočal vzdrževanja zahtevane ravni doslednosti takoj po namestitvi. Nato bom delil naše izkušnje s konfiguracijo Kafka, zlasti vam bom povedal, kako konfigurirati in živeti z natanko enkratno dostavo.

Zagotovljena dostava in več

Spodaj obravnavane nastavitve bodo pomagale preprečiti številne težave s privzetimi nastavitvami povezave. Toda najprej bi rad pozoren na en parameter, ki bo olajšal morebitno odpravljanje napak.

To bo pomagalo client.id za proizvajalca in potrošnika. Na prvi pogled lahko kot vrednost uporabite ime aplikacije in v večini primerov bo to delovalo. Čeprav situacija, ko aplikacija uporablja več porabnikov in jim dodelite isti client.id, povzroči naslednje opozorilo:

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

Če želite uporabiti JMX v aplikaciji s Kafko, je to lahko težava. V tem primeru je najbolje uporabiti kombinacijo imena aplikacije in na primer imena teme kot vrednost client.id. Rezultat naše konfiguracije je viden v izhodu ukaza kafka-potrošniške skupine iz pripomočkov Confluent:

Kako je Kafka postal resničnost

Zdaj pa poglejmo scenarij za zajamčeno dostavo sporočil. Kafka Producer ima parameter acks, ki vam omogoča, da konfigurirate, po koliko potrditvah mora vodja gruče upoštevati, da je sporočilo uspešno napisano. Ta parameter ima lahko naslednje vrednosti:

  • 0 — potrditev ne bo upoštevana.
  • 1 je privzeti parameter, za potrditev je potrebna samo 1 replika.
  • −1 — potrebna je potrditev vseh sinhroniziranih replik (nastavitev gruče min.insync.replicas).

Iz navedenih vrednosti je razvidno, da acks enak −1 daje najmočnejšo garancijo, da sporočilo ne bo izgubljeno.

Kot vsi vemo, so porazdeljeni sistemi nezanesljivi. Za zaščito pred prehodnimi napakami nudi Kafka Producer možnost ponovnih poskusov, ki vam omogoča nastavitev števila poskusov ponovnega pošiljanja znotraj dostava.časovna omejitev.ms. Ker ima parameter ponovnih poskusov privzeto vrednost Integer.MAX_VALUE (2147483647), je mogoče število ponovnih poskusov sporočil prilagoditi tako, da spremenite samo delivery.timeout.ms.

Približujemo se točno enkratni dostavi

Navedene nastavitve omogočajo našemu Producerju dostavo sporočil z visoko garancijo. Pogovorimo se zdaj o tem, kako zagotoviti, da je samo ena kopija sporočila napisana na Kafkino temo? V najpreprostejšem primeru morate za to nastaviti parameter na Producer omogočiti.idempotence do res. Idempotenca zagotavlja, da je v določeno particijo ene teme zapisano samo eno sporočilo. Predpogoj za omogočanje idempotence so vrednote acks = vse, ponovi > 0, max.in.flight.requests.per.connection ≤ 5. Če teh parametrov razvijalec ne določi, bodo zgornje vrednosti samodejno nastavljene.

Ko je idempotenca konfigurirana, je treba zagotoviti, da ista sporočila vsakič končajo v istih particijah. To lahko storite tako, da ključ in parameter partitioner.class nastavite na Producer. Začnimo s ključem. Za vsako oddajo mora biti enak. To je mogoče zlahka doseči z uporabo katerega koli poslovnega ID-ja iz prvotne objave. Parameter partitioner.class ima privzeto vrednost − Privzeti razdelilnik. S to strategijo particioniranja privzeto delujemo takole:

  • Če je particija ob pošiljanju sporočila izrecno navedena, jo uporabimo.
  • Če particija ni navedena, je pa podan ključ, izberite particijo glede na zgoščeno vrednost ključa.
  • Če particija in ključ nista določena, izberite particije eno za drugo (krožno).

Tudi uporaba ključa in idempotentno pošiljanje s parametrom max.in.flight.requests.per.connection = 1 vam omogoča poenostavljeno obdelavo sporočil pri potrošniku. Prav tako si velja zapomniti, da če je nadzor dostopa konfiguriran v vaši gruči, boste potrebovali pravice za idempotentno pisanje v temo.

Če nenadoma nimate zmožnosti idempotentnega pošiljanja s ključem ali logika na strani proizvajalca zahteva vzdrževanje skladnosti podatkov med različnimi particijami, bodo transakcije priskočile na pomoč. Poleg tega lahko z uporabo verižne transakcije pogojno sinhronizirate zapis v Kafki, na primer z zapisom v bazi podatkov. Da omogočimo transakcijsko pošiljanje Producerju, mora biti idempotenten in dodatno nastavljen transakcijski.id. Če je nadzor dostopa konfiguriran v vaši gruči Kafka, bo transakcijski zapis, tako kot idempotentni zapis, potreboval pravice pisanja, ki jih je mogoče podeliti z masko z uporabo vrednosti, shranjene v transakcijskem.id.

Formalno se lahko kateri koli niz, kot je ime aplikacije, uporabi kot identifikator transakcije. Toda če zaženete več primerkov iste aplikacije z istim transakcijskim idom, bo prvi zagnani primerek ustavljen z napako, saj ga bo Kafka obravnaval kot zombi proces.

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.

Za rešitev te težave dodamo imenu aplikacije pripono v obliki imena gostitelja, ki ga pridobimo iz spremenljivk okolja.

Proizvajalec je konfiguriran, vendar transakcije na Kafki nadzorujejo samo obseg sporočila. Ne glede na status transakcije sporočilo takoj preide v temo, vendar ima dodatne sistemske atribute.

Da potrošnik takih sporočil ne bi prebral pred časom, mora nastaviti parameter izolacija.raven za read_committed vrednost. Tak potrošnik bo lahko bral netransakcijska sporočila kot prej, transakcijska sporočila pa šele po potrditvi.
Če ste nastavili vse prej navedene nastavitve, ste konfigurirali točno enkratno dostavo. čestitke!

Vendar obstaja še en odtenek. Transactional.id, ki smo ga konfigurirali zgoraj, je pravzaprav predpona transakcije. Na upravljalniku transakcij se mu doda zaporedna številka. Prejeti identifikator se izda transakcijski.id.iztek.ms, ki je konfiguriran na gruči Kafka in ima privzeto vrednost "7 dni". Če v tem času aplikacija ni prejela nobenega sporočila, ga boste prejeli ob naslednjem transakcijskem pošiljanju InvalidPidMappingException. Koordinator transakcij bo nato izdal novo zaporedno številko za naslednjo transakcijo. Vendar se lahko sporočilo izgubi, če se izjema InvalidPidMappingException ne obravnava pravilno.

Namesto vsot

Kot lahko vidite, Kafki ni dovolj samo poslati sporočila. Izbrati morate kombinacijo parametrov in biti pripravljeni na hitre spremembe. V tem članku sem poskušal podrobno prikazati nastavitev točno enkratne dostave in opisal več težav s konfiguracijama client.id in transactional.id, na katere smo naleteli. Spodaj je povzetek nastavitev proizvajalca in potrošnika.

Producent:

  1. acks = vse
  2. ponovni poskusi > 0
  3. enable.idempotence = res
  4. max.in.flight.requests.per.connection ≤ 5 (1 za urejeno pošiljanje)
  5. transactional.id = ${application-name}-${hostname}

Potrošnik:

  1. isolation.level = read_committed

Da bi zmanjšali napake v prihodnjih aplikacijah, smo izdelali svoj ovoj nad vzmetno konfiguracijo, kjer so vrednosti za nekatere od navedenih parametrov že nastavljene.

Tukaj je nekaj gradiv za samostojno učenje:

Vir: www.habr.com

Dodaj komentar