Qanday qilib Kafka haqiqatga aylandi

Qanday qilib Kafka haqiqatga aylandi

Hey Xabr!

Men o'z bildirishnoma markazini ishlab chiqayotgan Tinkoff jamoasida ishlayman. Men asosan Java-da Spring boot-dan foydalanib ishlab chiqaman va loyihada yuzaga keladigan turli texnik muammolarni hal qilaman.

Aksariyat mikroxizmatlarimiz bir-biri bilan asinxron tarzda xabarlar brokeri orqali muloqot qiladi. Ilgari biz IBM MQ’dan broker sifatida foydalanardik, u endi yukni ko‘tara olmasdi, biroq ayni paytda yetkazib berish kafolatlari yuqori edi.

O'rniga bizga Apache Kafka taklif qilindi, u yuqori masshtablash potentsialiga ega, ammo, afsuski, turli stsenariylar uchun konfiguratsiyaga deyarli individual yondashuvni talab qiladi. Bundan tashqari, Kafkada sukut bo'yicha ishlaydigan kamida bir marta etkazib berish mexanizmi kerakli darajadagi mustahkamlikni saqlashga imkon bermadi. Keyinchalik, men Kafka konfiguratsiyasi bo'yicha tajribamiz bilan o'rtoqlashaman, xususan, men sizga bir marta etkazib berish bilan qanday sozlash va yashashni aytib beraman.

Kafolatlangan yetkazib berish va boshqalar

Quyida muhokama qilingan sozlamalar standart ulanish sozlamalari bilan bog'liq bir qator muammolarni oldini olishga yordam beradi. Lekin birinchi navbatda men mumkin bo'lgan disk raskadrovkani osonlashtiradigan bitta parametrga e'tibor qaratmoqchiman.

Bu yordam beradi client.id Ishlab chiqaruvchi va iste'molchi uchun. Bir qarashda siz dastur nomini qiymat sifatida ishlatishingiz mumkin va ko'p hollarda bu ishlaydi. Ilova bir nechta iste'molchilardan foydalansa va siz ularga bir xil client.id ni bergan bo'lsangiz ham, quyidagi ogohlantirishga olib keladi:

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

Agar siz JMX-ni Kafka bilan dasturda ishlatmoqchi bo'lsangiz, bu muammo bo'lishi mumkin. Bunday holda, mijoz.id qiymati sifatida dastur nomi va masalan, mavzu nomi kombinatsiyasidan foydalanish yaxshidir. Bizning konfiguratsiyamiz natijasini buyruq chiqishida ko'rish mumkin kafka-iste'molchi guruhlari Confluent-dan kommunal xizmatlardan:

Qanday qilib Kafka haqiqatga aylandi

Endi xabarni kafolatlangan yetkazib berish stsenariysini ko‘rib chiqamiz. Kafka Producer parametriga ega acks, bu sizga klaster rahbari xabarni muvaffaqiyatli yozilgan deb hisoblashi kerak bo'lgan qancha tasdiqdan keyin sozlash imkonini beradi. Ushbu parametr quyidagi qiymatlarni olishi mumkin:

  • 0 - tan olish ko'rib chiqilmaydi.
  • 1 standart parametr, tan olish uchun faqat 1 nusxa talab qilinadi.
  • −1 - barcha sinxronlashtirilgan replikalarni tasdiqlash talab qilinadi (klasterni sozlash min.insync.replicas).

Ro'yxatga olingan qiymatlardan ma'lum bo'lishicha, -1 ga teng acks xabar yo'qolmasligiga eng kuchli kafolat beradi.

Hammamizga ma'lumki, taqsimlangan tizimlar ishonchsizdir. Vaqtinchalik nosozliklardan himoya qilish uchun Kafka Producer variantni taqdim etadi qayta urinish, bu sizga ichida qayta yuborish urinishlari sonini belgilash imkonini beradi yetkazib berish.timeout.ms. Qayta urinishlar parametri standart Integer.MAX_VALUE (2147483647) qiymatiga ega bo'lgani uchun xabarlarni qayta urinishlar sonini faqat delivery.timeout.ms ni o'zgartirish orqali sozlash mumkin.

Biz aynan bir marta yetkazib berish tomon harakat qilmoqdamiz

Ro'yxatda keltirilgan sozlamalar Prodyuserimizga xabarlarni yuqori kafolatli yetkazib berish imkonini beradi. Keling, Kafka mavzusiga xabarning faqat bitta nusxasi yozilishini qanday ta'minlash haqida gapiraylik? Eng oddiy holatda, buni amalga oshirish uchun siz Producer-ga parametrni o'rnatishingiz kerak faollashtirish.idempotence haqiqatga. Idempotency bir mavzuning ma'lum bir qismiga faqat bitta xabar yozilishini kafolatlaydi. Idempotentlikni ta'minlashning dastlabki sharti qadriyatlardir acks = hammasi, qayta urinish > 0, max.in.flight.requests.per.connection ≤ 5. Agar ushbu parametrlar ishlab chiquvchi tomonidan belgilanmagan bo'lsa, yuqoridagi qiymatlar avtomatik ravishda o'rnatiladi.

Idempotentlik sozlanganda, har safar bir xil xabarlar bir xil bo'limlarda tugashini ta'minlash kerak. Buni partitioner.class kaliti va parametrini Producer ga o'rnatish orqali amalga oshirish mumkin. Kalitdan boshlaylik. Har bir taqdimot uchun bir xil bo'lishi kerak. Bunga asl postdagi biznes identifikatorlaridan har qanday foydalanish orqali osongina erishish mumkin. Partitioner.class parametri standart qiymatga ega - DefaultPartitioner. Ushbu bo'lim strategiyasi bilan sukut bo'yicha biz shunday harakat qilamiz:

  • Agar bo'lim xabarni yuborishda aniq ko'rsatilgan bo'lsa, biz undan foydalanamiz.
  • Agar bo'lim ko'rsatilmagan bo'lsa, lekin kalit ko'rsatilgan bo'lsa, bo'limni kalitning xeshi bo'yicha tanlang.
  • Agar bo'lim va kalit ko'rsatilmagan bo'lsa, bo'limlarni birma-bir tanlang (round-robin).

Bundan tashqari, kalit va parametr bilan idempotent yuborishdan foydalanish max.in.flight.requests.per.connection = 1 sizga iste'molchida xabarlarni qayta ishlashni osonlashtiradi. Shuni ham yodda tutish kerakki, agar sizning klasteringizda kirishni boshqarish sozlangan bo'lsa, sizga mavzuga idempotent tarzda yozish huquqi kerak bo'ladi.

Agar siz to'satdan kalit orqali idempotent jo'natish qobiliyatiga ega bo'lmasangiz yoki Ishlab chiqaruvchi tomonidagi mantiq turli bo'limlar o'rtasida ma'lumotlar izchilligini saqlashni talab qilsa, tranzaktsiyalar yordamga keladi. Bundan tashqari, zanjirli tranzaktsiyadan foydalanib, siz Kafkadagi yozuvni, masalan, ma'lumotlar bazasidagi yozuv bilan shartli ravishda sinxronlashtirishingiz mumkin. Ishlab chiqaruvchiga tranzaksiya yuborishni yoqish uchun u idempotent bo'lishi va qo'shimcha ravishda o'rnatilishi kerak transactional.id. Agar Kafka klasteringizda kirishni boshqarish sozlangan bo'lsa, tranzaksiya yozuvi, masalan, idempotent yozuv, transferal.id da saqlangan qiymatdan foydalangan holda niqob orqali berilishi mumkin bo'lgan yozish ruxsatlariga muhtoj bo'ladi.

Rasmiy ravishda, har qanday satr, masalan, dastur nomi, tranzaktsiya identifikatori sifatida ishlatilishi mumkin. Ammo agar siz bir xil dasturning bir nechta nusxalarini bir xil transactional.id bilan ishga tushirsangiz, birinchi ishga tushirilgan nusxa xato bilan to'xtatiladi, chunki Kafka buni zombi jarayon deb hisoblaydi.

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.

Ushbu muammoni hal qilish uchun biz dastur nomiga muhit o'zgaruvchilaridan olingan xost nomi ko'rinishidagi qo'shimchani qo'shamiz.

Ishlab chiqaruvchi sozlangan, ammo Kafkadagi tranzaktsiyalar faqat xabar doirasini nazorat qiladi. Tranzaksiya holatidan qat'i nazar, xabar darhol mavzuga o'tadi, lekin qo'shimcha tizim atributlariga ega.

Bunday xabarlarni Iste'molchi tomonidan oldindan o'qilishining oldini olish uchun u parametrni o'rnatishi kerak izolyatsiya.daraja read_committed qiymatiga. Bunday Iste'molchi avvalgidek tranzaksiyaga aloqador bo'lmagan xabarlarni va tranzaksiya xabarlarini faqat majburiyatdan keyin o'qiy oladi.
Agar siz ilgari sanab o'tilgan barcha sozlamalarni o'rnatgan bo'lsangiz, siz etkazib berishni aynan bir marta sozlagansiz. Tabriklaymiz!

Ammo yana bir nuance bor. Biz yuqorida sozlagan Transactional.id aslida tranzaksiya prefiksidir. Tranzaksiya menejerida unga tartib raqami qo'shiladi. Qabul qilingan identifikator beriladi transactional.id.expiration.ms, Kafka klasterida sozlangan va standart qiymati “7 kun”. Agar shu vaqt ichida dastur hech qanday xabar olmagan bo'lsa, keyingi tranzaksiya jo'natmasini sinab ko'rganingizda sizga xabar keladi InvalidPidMappingException. Keyin tranzaksiya koordinatori keyingi tranzaksiya uchun yangi tartib raqamini beradi. Biroq, InvalidPidMappingException to'g'ri ishlanmasa, xabar yo'qolishi mumkin.

Umumiy hisoblar o'rniga

Ko'rib turganingizdek, Kafkaga shunchaki xabar yuborishning o'zi etarli emas. Siz parametrlar kombinatsiyasini tanlashingiz va tezkor o'zgarishlarni amalga oshirishga tayyor bo'lishingiz kerak. Ushbu maqolada men aynan bir marta etkazib berishni sozlashni batafsil ko'rsatishga harakat qildim va biz duch kelgan client.id va transactional.id konfiguratsiyalari bilan bog'liq bir nechta muammolarni tasvirlab berdim. Quyida ishlab chiqaruvchi va iste'molchi sozlamalari haqida qisqacha ma'lumot berilgan.

Ishlab chiqaruvchi:

  1. acks = hammasi
  2. qayta urinish > 0
  3. enable.idempotence = rost
  4. max.in.flight.requests.per.connection ≤ 5 (tartibli yuborish uchun 1)
  5. transactional.id = ${application-name}-${hostname}

Iste'molchi:

  1. isolation.level = read_committed

Kelgusi ilovalardagi xatolarni kamaytirish uchun biz ro'yxatdagi ba'zi parametrlar uchun qiymatlar allaqachon o'rnatilgan bahor konfiguratsiyasiga o'z qo'limizni o'rnatdik.

O'z-o'zini o'rganish uchun bir nechta materiallar:

Manba: www.habr.com

a Izoh qo'shish