Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka

Sambungan terjemahan sebuah buku kecil:
Memahami Broker Mesej
pengarang: Jakub Korab, penerbit: O'Reilly Media, Inc., tarikh diterbitkan: Jun 2017, ISBN: 9781492049296.

Bahagian terjemahan sebelumnya: Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 1 Pengenalan

BAB 3

Kafka

Kafka dibangunkan di LinkedIn untuk mengatasi beberapa batasan broker mesej tradisional dan mengelak daripada menyediakan berbilang broker mesej untuk interaksi point-to-point yang berbeza, yang diterangkan dalam buku ini di bawah "Menskalakan dan keluar" pada halaman 28 Kes penggunaan LinkedIn sebahagian besarnya bergantung pada pengingesan sehala bagi jumlah data yang sangat besar, seperti klik halaman dan log akses, sementara masih membenarkan data tersebut digunakan oleh berbilang sistem tanpa menjejaskan produktiviti pengeluar atau pengguna lain. Sebenarnya, sebab Kafka wujud adalah untuk mendapatkan jenis seni bina pemesejan yang diterangkan oleh Paip Data Universal.

Memandangkan matlamat utama ini, keperluan lain secara semula jadi timbul. Kafka sepatutnya:

  • Cepat sangat
  • Menyediakan lebih lebar jalur apabila bekerja dengan mesej
  • Sokong model Penerbit-Pelanggan dan Point-to-Point
  • Jangan perlahan dengan menambah pengguna. Sebagai contoh, prestasi kedua-dua baris gilir dan topik dalam ActiveMQ merosot apabila bilangan pengguna di destinasi bertambah.
  • Berskala mendatar; jika satu broker yang meneruskan mesej hanya boleh berbuat demikian pada kelajuan cakera maksimum, maka masuk akal untuk melampaui satu contoh broker untuk meningkatkan prestasi
  • Hadkan akses kepada menyimpan dan mendapatkan semula mesej

Untuk mencapai semua ini, Kafka menggunakan seni bina yang mentakrifkan semula peranan dan tanggungjawab pelanggan dan broker pemesejan. Model JMS sangat berorientasikan broker, di mana broker bertanggungjawab untuk mengedarkan mesej dan pelanggan hanya perlu risau tentang menghantar dan menerima mesej. Kafka, sebaliknya, mementingkan pelanggan, dengan pelanggan menggunakan banyak ciri broker tradisional, seperti pengedaran adil mesej yang berkaitan kepada pengguna, sebagai pertukaran untuk broker yang sangat pantas dan berskala. Bagi orang yang telah bekerja dengan sistem pemesejan tradisional, bekerja dengan Kafka memerlukan perubahan minda yang asas.
Arah kejuruteraan ini telah membawa kepada penciptaan infrastruktur pemesejan yang mampu meningkatkan daya pengeluaran dengan banyak pesanan magnitud berbanding dengan broker konvensional. Seperti yang akan kita lihat, pendekatan ini datang dengan pertukaran, yang bermaksud bahawa Kafka tidak sesuai untuk jenis beban kerja tertentu dan perisian yang dipasang.

Model Destinasi Bersatu

Untuk memenuhi keperluan yang diterangkan di atas, Kafka telah menggabungkan penerbitan-langganan dan pemesejan point-to-point di bawah satu jenis destinasi βˆ’ topik. Ini mengelirukan kepada orang yang telah bekerja dengan sistem pemesejan, di mana perkataan "topik" merujuk kepada mekanisme penyiaran yang (daripada topik) bacaan tidak dapat bertahan. Topik Kafka harus dianggap sebagai jenis destinasi hibrid, seperti yang ditakrifkan dalam pengenalan buku ini.

Untuk baki bab ini, melainkan kami menyatakan sebaliknya secara eksplisit, istilah "topik" akan merujuk kepada topik Kafka.

Untuk memahami sepenuhnya cara topik berkelakuan dan jaminan yang disediakan, kita perlu melihat terlebih dahulu cara topik tersebut dilaksanakan dalam Kafka.
Setiap topik dalam Kafka mempunyai log sendiri.
Pengeluar yang menghantar mesej kepada Kafka menulis ke log ini dan pengguna membaca daripada log menggunakan penunjuk yang sentiasa bergerak ke hadapan. Secara berkala, Kafka memadam bahagian tertua log, sama ada mesej dalam bahagian tersebut telah dibaca atau tidak. Bahagian tengah reka bentuk Kafka ialah broker tidak peduli sama ada mesej dibaca atau tidak - itu adalah tanggungjawab pelanggan.

Istilah "log" dan "penunjuk" tidak muncul di dalamnya dokumentasi Kafka. Istilah yang terkenal ini digunakan di sini untuk membantu pemahaman.

Model ini berbeza sama sekali daripada ActiveMQ, di mana mesej daripada semua baris gilir disimpan dalam log yang sama, dan broker menandakan mesej sebagai dipadamkan selepas ia dibaca.
Sekarang mari kita gali lebih dalam dan lihat log topik dengan lebih terperinci.
Log Kafka terdiri daripada beberapa partition (Rajah 3-1). Kafka menjamin pesanan yang ketat dalam setiap partition. Ini bermakna mesej yang ditulis kepada partition dalam susunan tertentu akan dibaca dalam susunan yang sama. Setiap partition dilaksanakan sebagai fail log rolling yang mengandungi subset (subset) semua mesej yang dihantar kepada topik oleh pengeluarnya. Topik yang dibuat mengandungi, secara lalai, satu partition. Idea partition adalah idea utama Kafka untuk penskalaan mendatar.

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-1. Pembahagian Kafka

Apabila pengeluar menghantar mesej kepada topik Kafka, ia memutuskan partition mana untuk menghantar mesej itu. Kami akan melihat perkara ini dengan lebih terperinci kemudian.

Membaca mesej

Pelanggan yang ingin membaca mesej menguruskan penunjuk bernama dipanggil kumpulan pengguna, yang menunjuk kepada mengimbangi mesej dalam partition. Offset ialah kedudukan tambahan yang bermula pada 0 pada permulaan partition. Kumpulan pengguna ini, yang dirujuk dalam API melalui group_id yang ditentukan pengguna, sepadan dengan satu pengguna atau sistem logik.

Kebanyakan sistem pemesejan membaca data dari destinasi menggunakan berbilang kejadian dan urutan untuk memproses mesej secara selari. Oleh itu, biasanya terdapat banyak contoh pengguna yang berkongsi kumpulan pengguna yang sama.

Masalah membaca boleh diwakili seperti berikut:

  • Topik mempunyai berbilang partition
  • Berbilang kumpulan pengguna boleh menggunakan topik pada masa yang sama
  • Sekumpulan pengguna boleh mempunyai berbilang kejadian berasingan

Ini adalah masalah banyak-ke-banyak yang tidak remeh. Untuk memahami cara Kafka mengendalikan perhubungan antara kumpulan pengguna, kejadian pengguna dan sekatan, mari kita lihat satu siri senario bacaan yang semakin kompleks.

Pengguna dan kumpulan pengguna

Mari kita ambil sebagai titik permulaan topik dengan satu partition (Rajah 3-2).

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-2. Pengguna membaca dari partition

Apabila tika pengguna bersambung dengan group_idnya sendiri kepada topik ini, ia diberikan partition baca dan offset dalam partition itu. Kedudukan offset ini boleh dikonfigurasikan dalam klien sebagai penunjuk kepada kedudukan terkini (mesej terbaharu) atau kedudukan terawal (mesej tertua). Pengguna meminta (pungutan suara) mesej daripada topik, yang menyebabkan mesej itu dibaca secara berurutan daripada log.
Kedudukan offset sentiasa dikomit kembali kepada Kafka dan disimpan sebagai mesej dalam topik dalaman _pengimbangan_pengguna. Mesej yang dibaca masih tidak dipadamkan, tidak seperti broker biasa, dan pelanggan boleh memundurkan semula offset untuk memproses semula mesej yang telah dilihat.

Apabila pengguna logik kedua menyambung menggunakan group_id yang berbeza, ia menguruskan penunjuk kedua yang bebas daripada yang pertama (Rajah 3-3). Oleh itu, topik Kafka bertindak seperti baris gilir di mana terdapat satu pengguna dan seperti topik terbitan-langganan (pub-sub) biasa yang dilanggan oleh berbilang pengguna, dengan faedah tambahan bahawa semua mesej disimpan dan boleh diproses beberapa kali.

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-3. Dua pengguna dalam kumpulan pengguna berbeza membaca dari partition yang sama

Pengguna dalam kumpulan pengguna

Apabila satu contoh pengguna membaca data daripada partition, ia mempunyai kawalan penuh ke atas penuding dan memproses mesej seperti yang diterangkan dalam bahagian sebelumnya.
Jika beberapa kejadian pengguna disambungkan dengan group_id yang sama kepada topik dengan satu partition, maka contoh yang terakhir disambungkan akan diberi kawalan ke atas penunjuk dan mulai saat itu ia akan menerima semua mesej (Rajah 3-4).

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-4. Dua pengguna dalam kumpulan pengguna yang sama membaca dari partition yang sama

Cara pemprosesan ini, di mana bilangan kejadian pengguna melebihi bilangan partition, boleh dianggap sebagai sejenis pengguna eksklusif. Ini boleh berguna jika anda memerlukan pengelompokan "aktif-pasif" (atau "panas-panas") contoh pengguna anda, walaupun menjalankan berbilang pengguna secara selari ("aktif-aktif" atau "panas-panas") adalah lebih tipikal daripada pengguna.Dalam bersedia.

Tingkah laku pengedaran mesej yang diterangkan di atas boleh mengejutkan berbanding cara baris gilir JMS biasa berkelakuan. Dalam model ini, mesej yang dihantar ke baris gilir akan diedarkan sama rata antara kedua-dua pengguna.

Selalunya, apabila kami mencipta berbilang contoh pengguna, kami melakukan ini sama ada untuk memproses mesej secara selari, atau untuk meningkatkan kelajuan membaca, atau untuk meningkatkan kestabilan proses pembacaan. Memandangkan hanya satu contoh pengguna boleh membaca data daripada partition pada satu masa, bagaimanakah perkara ini dicapai dalam Kafka?

Satu cara untuk melakukan ini ialah menggunakan contoh pengguna tunggal untuk membaca semua mesej dan menghantarnya ke kumpulan benang. Walaupun pendekatan ini meningkatkan daya pemprosesan, ia meningkatkan kerumitan logik pengguna dan tidak melakukan apa-apa untuk meningkatkan keteguhan sistem bacaan. Jika satu salinan pengguna terputus disebabkan kegagalan kuasa atau peristiwa serupa, maka penolakan akan berhenti.

Cara kanonik untuk menyelesaikan masalah ini dalam Kafka adalah dengan menggunakan bОlebih banyak partition.

Pembahagian

Pemisahan ialah mekanisme utama untuk menyelaraskan pembacaan dan skala topik melebihi lebar jalur satu contoh broker. Untuk lebih memahami perkara ini, mari kita pertimbangkan situasi di mana terdapat topik dengan dua partition dan satu pengguna melanggan topik ini (Rajah 3-5).

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-5. Seorang pengguna membaca daripada berbilang partition

Dalam senario ini, pengguna diberi kawalan ke atas penunjuk yang sepadan dengan group_idnya dalam kedua-dua partition dan mula membaca mesej dari kedua-dua partition.
Apabila pengguna tambahan untuk group_id yang sama ditambahkan pada topik ini, Kafka memperuntukkan semula salah satu partition daripada pengguna pertama kepada pengguna kedua. Selepas itu, setiap contoh pengguna akan membaca dari satu partition topik (Rajah 3-6).

Untuk memastikan bahawa mesej diproses secara selari dalam 20 utas, anda memerlukan sekurang-kurangnya 20 sekatan. Sekiranya terdapat lebih sedikit sekatan, anda akan ditinggalkan dengan pengguna yang tidak mempunyai apa-apa untuk diusahakan, seperti yang diterangkan sebelum ini dalam perbincangan tentang pengguna eksklusif.

Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 3. Kafka
Rajah 3-6. Dua pengguna dalam kumpulan pengguna yang sama membaca dari partition yang berbeza

Skim ini sangat mengurangkan kerumitan broker Kafka berbanding pengedaran mesej yang diperlukan untuk mengekalkan baris gilir JMS. Di sini anda tidak perlu risau tentang perkara berikut:

  • Pengguna manakah yang harus menerima mesej seterusnya, berdasarkan peruntukan round-robin, kapasiti semasa penimbal prefetch atau mesej sebelumnya (seperti untuk kumpulan mesej JMS).
  • Mesej mana yang dihantar kepada pengguna dan sama ada ia perlu dihantar semula sekiranya berlaku kegagalan.

Apa yang perlu dilakukan oleh broker Kafka ialah menghantar mesej secara berurutan kepada pengguna apabila pengguna memintanya.

Walau bagaimanapun, keperluan untuk menyelaraskan penyemakan pruf dan menghantar semula mesej yang gagal tidak hilang - tanggungjawab untuk mereka hanya berpindah dari broker kepada pelanggan. Ini bermakna ia mesti diambil kira dalam kod anda.

Menghantar mesej

Adalah menjadi tanggungjawab pengeluar mesej itu untuk memutuskan partition mana untuk menghantar mesej. Untuk memahami mekanisme ini dilakukan, kita perlu mempertimbangkan terlebih dahulu apa sebenarnya yang kita hantar.

Manakala dalam JMS kita menggunakan struktur mesej dengan metadata (pengepala dan sifat) dan badan yang mengandungi muatan (muatan), dalam Kafka mesej itu pasangan "nilai kunci". Muatan mesej dihantar sebagai nilai. Kunci, sebaliknya, digunakan terutamanya untuk pembahagian dan mesti mengandungi kunci khusus logik perniagaanuntuk meletakkan mesej berkaitan dalam partition yang sama.

Dalam Bab 2, kami membincangkan senario pertaruhan dalam talian di mana acara berkaitan perlu diproses mengikut urutan oleh pengguna tunggal:

  1. Akaun pengguna dikonfigurasikan.
  2. Wang dikreditkan ke akaun.
  3. Pertaruhan dibuat yang mengeluarkan wang dari akaun.

Jika setiap acara ialah mesej yang disiarkan ke topik, maka kunci semula jadi ialah ID akaun.
Apabila mesej dihantar menggunakan API Pengeluar Kafka, ia dihantar ke fungsi partition yang, memandangkan mesej dan keadaan semasa gugusan Kafka, mengembalikan ID partition yang mesej harus dihantar. Ciri ini dilaksanakan dalam Java melalui antara muka Partitioner.

Antara muka ini kelihatan seperti ini:

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

Pelaksanaan Partitioner menggunakan algoritma pencincangan tujuan am lalai di atas kekunci untuk menentukan partition atau round-robin jika tiada kunci ditentukan. Nilai lalai ini berfungsi dengan baik dalam kebanyakan kes. Walau bagaimanapun, pada masa hadapan anda akan mahu menulis sendiri.

Menulis strategi pembahagian anda sendiri

Mari lihat contoh di mana anda ingin menghantar metadata bersama-sama dengan muatan mesej. Muatan dalam contoh kami ialah arahan untuk membuat deposit ke akaun permainan. Arahan ialah sesuatu yang kami ingin dijamin tidak akan diubah suai pada penghantaran dan ingin memastikan bahawa hanya sistem huluan yang dipercayai boleh memulakan arahan itu. Dalam kes ini, sistem penghantaran dan penerimaan bersetuju dengan penggunaan tandatangan untuk mengesahkan mesej.
Dalam JMS biasa, kami hanya mentakrifkan sifat "tandatangan mesej" dan menambahkannya pada mesej. Walau bagaimanapun, Kafka tidak memberikan kami mekanisme untuk menghantar metadata, hanya kunci dan nilai.

Oleh kerana nilainya ialah muatan pindahan bank yang integritinya ingin kami pelihara, kami tidak mempunyai pilihan selain menentukan struktur data untuk digunakan dalam kunci. Dengan mengandaikan bahawa kami memerlukan ID akaun untuk pembahagian, kerana semua mesej yang berkaitan dengan akaun mesti diproses mengikut urutan, kami akan menghasilkan struktur JSON berikut:

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

Oleh kerana nilai tandatangan akan berbeza-beza bergantung pada muatan, strategi pencincangan lalai antara muka Pembahagi tidak akan pasti mengumpulkan mesej berkaitan. Oleh itu, kami perlu menulis strategi kami sendiri yang akan menghuraikan kunci ini dan membahagikan nilai accountId.

Kafka menyertakan jumlah semak untuk mengesan kerosakan mesej dalam kedai dan mempunyai set lengkap ciri keselamatan. Walaupun begitu, keperluan khusus industri, seperti yang di atas, kadangkala muncul.

Strategi pembahagian pengguna mesti memastikan bahawa semua mesej yang berkaitan berakhir dalam partition yang sama. Walaupun ini kelihatan mudah, keperluan itu boleh menjadi rumit oleh kepentingan memesan mesej berkaitan dan cara menetapkan bilangan partition dalam topik.

Bilangan partition dalam topik boleh berubah dari semasa ke semasa, kerana ia boleh ditambah jika trafik melebihi jangkaan awal. Oleh itu, kekunci mesej boleh dikaitkan dengan partition asalnya dihantar, membayangkan sekeping keadaan untuk dikongsi antara contoh pengeluar.

Faktor lain yang perlu dipertimbangkan ialah pengedaran mesej yang sekata merentas partition. Biasanya, kunci tidak diedarkan secara sama rata merentas mesej, dan fungsi cincang tidak menjamin pengedaran mesej yang adil untuk set kunci yang kecil.
Adalah penting untuk ambil perhatian bahawa walau bagaimanapun anda memilih untuk memisahkan mesej, pemisah itu sendiri mungkin perlu digunakan semula.

Pertimbangkan keperluan untuk mereplikasi data antara kelompok Kafka di lokasi geografi yang berbeza. Untuk tujuan ini, Kafka dilengkapi dengan alat baris arahan yang dipanggil MirrorMaker, yang digunakan untuk membaca mesej daripada satu gugusan dan memindahkannya ke yang lain.

MirrorMaker mesti memahami kunci topik yang direplikasi untuk mengekalkan susunan relatif antara mesej apabila mereplikasi antara gugusan, kerana bilangan partition untuk topik itu mungkin tidak sama dalam dua gugusan.

Strategi pembahagian tersuai agak jarang berlaku, kerana pencincangan lalai atau round robin berfungsi dengan baik dalam kebanyakan senario. Walau bagaimanapun, jika anda memerlukan jaminan pesanan yang kukuh atau perlu mengekstrak metadata daripada muatan, maka pembahagian ialah sesuatu yang perlu anda lihat dengan lebih dekat.

Manfaat berskala dan prestasi Kafka datang daripada mengalihkan beberapa tanggungjawab broker tradisional kepada pelanggan. Dalam kes ini, keputusan dibuat untuk mengedarkan mesej yang berpotensi berkaitan di kalangan beberapa pengguna yang bekerja secara selari.

Broker JMS juga perlu menangani keperluan tersebut. Menariknya, mekanisme untuk menghantar mesej berkaitan kepada pengguna yang sama, dilaksanakan melalui Kumpulan Mesej JMS (variasi pada strategi pengimbangan beban melekat (SLB)), juga memerlukan pengirim untuk menandakan mesej sebagai berkaitan. Dalam kes JMS, broker bertanggungjawab untuk menghantar kumpulan mesej berkaitan ini kepada satu pengguna daripada banyak, dan memindahkan pemilikan kumpulan jika pengguna gagal.

Perjanjian Pengeluar

Pembahagian bukan satu-satunya perkara yang perlu dipertimbangkan semasa menghantar mesej. Mari kita lihat kaedah send() kelas Producer dalam Java API:

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

Perlu segera diambil perhatian bahawa kedua-dua kaedah mengembalikan Masa Depan, yang menunjukkan bahawa operasi penghantaran tidak dilakukan dengan serta-merta. Hasilnya ialah mesej (ProducerRecord) ditulis kepada penimbal hantar untuk setiap partition aktif dan dihantar kepada broker sebagai utas latar belakang dalam perpustakaan pelanggan Kafka. Walaupun ini menjadikan perkara itu sangat pantas, ini bermakna aplikasi yang tidak berpengalaman boleh kehilangan mesej jika prosesnya dihentikan.

Seperti biasa, terdapat cara untuk menjadikan operasi penghantaran lebih dipercayai dengan mengorbankan prestasi. Saiz penimbal ini boleh ditetapkan kepada 0, dan utas aplikasi penghantaran akan terpaksa menunggu sehingga pemindahan mesej kepada broker selesai, seperti berikut:

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

Lebih lanjut mengenai membaca mesej

Membaca mesej mempunyai kerumitan tambahan yang perlu dibuat spekulasi. Tidak seperti API JMS, yang boleh menjalankan pendengar mesej sebagai tindak balas kepada mesej, the Sektor Peralatan Domestik Kafka hanya mengundi. Mari kita lihat lebih dekat kaedahnya tinjauan pendapat()digunakan untuk tujuan ini:

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

Nilai pulangan kaedah ialah struktur bekas yang mengandungi berbilang objek rekod pengguna daripada beberapa partition yang berpotensi. rekod pengguna itu sendiri adalah objek pemegang untuk pasangan nilai kunci dengan metadata yang berkaitan, seperti partition dari mana ia diperoleh.

Seperti yang dibincangkan dalam Bab 2, kita mesti mengingati apa yang berlaku kepada mesej selepas ia berjaya atau tidak berjaya diproses, contohnya, jika pelanggan tidak dapat memproses mesej atau jika ia dibatalkan. Dalam JMS, ini dikendalikan melalui mod pengakuan. Broker akan sama ada memadamkan mesej yang berjaya diproses, atau menghantar semula mesej mentah atau palsu (dengan mengandaikan transaksi telah digunakan).
Kafka berfungsi dengan sangat berbeza. Mesej tidak dipadamkan dalam broker selepas semakan pruf, dan apa yang berlaku apabila kegagalan adalah tanggungjawab kod semakan pruf itu sendiri.

Seperti yang telah kami katakan, kumpulan pengguna dikaitkan dengan offset dalam log. Kedudukan log yang dikaitkan dengan ofset ini sepadan dengan mesej seterusnya yang akan dikeluarkan sebagai tindak balas kepada tinjauan pendapat(). Titik masa apabila ofset ini meningkat adalah penentu untuk membaca.

Berbalik kepada model bacaan yang dibincangkan sebelum ini, pemprosesan mesej terdiri daripada tiga peringkat:

  1. Dapatkan semula mesej untuk dibaca.
  2. Memproses mesej.
  3. Sahkan mesej.

Pengguna Kafka datang dengan pilihan konfigurasi enable.auto.commit. Ini ialah tetapan lalai yang kerap digunakan, seperti biasa dengan tetapan yang mengandungi perkataan "auto".

Sebelum Kafka 0.10, pelanggan yang menggunakan pilihan ini akan menghantar offset mesej terakhir yang dibaca pada panggilan seterusnya tinjauan pendapat() selepas diproses. Ini bermakna bahawa sebarang mesej yang telah diambil boleh diproses semula jika pelanggan telah memprosesnya tetapi secara tidak dijangka dimusnahkan sebelum memanggil tinjauan pendapat(). Oleh kerana broker tidak menyimpan sebarang keadaan tentang berapa kali mesej telah dibaca, pengguna seterusnya yang mendapatkan semula mesej itu tidak akan mengetahui apa-apa perkara buruk berlaku. Tingkah laku ini adalah pseudo-transaksional. Offset hanya dilakukan jika mesej berjaya diproses, tetapi jika pelanggan membatalkan, broker akan menghantar mesej yang sama sekali lagi kepada pelanggan lain. Tingkah laku ini konsisten dengan jaminan penghantaran mesej "sekurang-kurangnya sekali".

Dalam Kafka 0.10, kod klien telah ditukar supaya komit dicetuskan secara berkala oleh pustaka klien, seperti yang dikonfigurasikan auto.commit.interval.ms. Tingkah laku ini berada di antara mod JMS AUTO_ACKNOWLEDGE dan DUPS_OK_ACKNOWLEDGE. Apabila menggunakan autokomit, mesej boleh dilakukan tanpa mengira sama ada ia benar-benar diproses - ini boleh berlaku dalam kes pengguna yang lambat. Jika pengguna menggugurkan, mesej akan diambil oleh pengguna seterusnya, bermula pada kedudukan komited, yang boleh mengakibatkan mesej terlepas. Dalam kes ini, Kafka tidak kehilangan mesej, kod bacaan hanya tidak memprosesnya.

Mod ini mempunyai janji yang sama seperti dalam versi 0.9: mesej boleh diproses, tetapi jika ia gagal, ofset mungkin tidak dilakukan, yang berpotensi menyebabkan penghantaran menjadi dua kali ganda. Lebih banyak mesej yang anda ambil semasa melaksanakan tinjauan pendapat(), semakin banyak masalah ini.

Seperti yang dibincangkan dalam "Membaca Mesej daripada Baris Gilir" pada halaman 21, tiada perkara seperti penghantaran satu kali mesej dalam sistem pemesejan apabila mod kegagalan diambil kira.

Dalam Kafka, terdapat dua cara untuk melakukan (commit) offset (offset): secara automatik dan manual. Dalam kedua-dua kes, mesej boleh diproses beberapa kali jika mesej diproses tetapi gagal sebelum komit. Anda juga boleh memilih untuk tidak memproses mesej sama sekali jika komit berlaku di latar belakang dan kod anda telah selesai sebelum ia boleh diproses (mungkin dalam Kafka 0.9 dan lebih awal).

Anda boleh mengawal proses komit mengimbangi manual dalam API pengguna Kafka dengan menetapkan parameter enable.auto.commit kepada palsu dan secara eksplisit memanggil salah satu daripada kaedah berikut:

void commitSync();
void commitAsync();

Jika anda ingin memproses mesej "sekurang-kurangnya sekali", anda mesti melakukan offset secara manual dengan commitSync()dengan melaksanakan arahan ini sejurus selepas memproses mesej.

Kaedah ini tidak membenarkan mesej diakui sebelum ia diproses, tetapi ia tidak melakukan apa-apa untuk menghapuskan kelewatan pemprosesan yang berpotensi sambil memberikan rupa sebagai transaksi. Tiada transaksi di Kafka. Pelanggan tidak mempunyai keupayaan untuk melakukan perkara berikut:

  • Putar semula mesej palsu secara automatik. Pengguna sendiri mesti mengendalikan pengecualian yang timbul daripada muatan bermasalah dan gangguan hujung belakang, kerana mereka tidak boleh bergantung pada broker untuk menghantar semula mesej.
  • Hantar mesej kepada berbilang topik dalam satu operasi atom. Seperti yang akan kita lihat sebentar lagi, kawalan ke atas topik dan partition yang berbeza boleh berada pada mesin yang berbeza dalam kelompok Kafka yang tidak menyelaraskan transaksi apabila dihantar. Pada masa penulisan ini, beberapa kerja telah dilakukan untuk menjadikannya mungkin dengan KIP-98.
  • Kaitkan membaca satu mesej daripada satu topik dengan menghantar mesej lain ke topik lain. Sekali lagi, seni bina Kafka bergantung pada banyak mesin bebas yang berjalan sebagai satu bas dan tiada percubaan dibuat untuk menyembunyikan ini. Sebagai contoh, tiada komponen API yang membolehkan anda memautkan pengguna ΠΈ Pengeluar dalam sesuatu transaksi. Dalam JMS, ini disediakan oleh objek Sesidaripadanya diciptakan MessageProducers ΠΈ MessageConsumers.

Jika kita tidak boleh bergantung pada urus niaga, bagaimanakah kita boleh menyediakan semantik lebih dekat dengan yang disediakan oleh sistem pemesejan tradisional?

Sekiranya terdapat kemungkinan bahawa pengimbangan pengguna mungkin meningkat sebelum mesej diproses, seperti semasa kemalangan pengguna, maka pengguna tidak mempunyai cara untuk mengetahui sama ada kumpulan penggunanya terlepas mesej apabila ia diberikan partition. Jadi satu strategi adalah untuk memundurkan offset ke kedudukan sebelumnya. API pengguna Kafka menyediakan kaedah berikut untuk ini:

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

Kaedah cari() boleh digunakan dengan kaedah
offsetsForTimes(Peta cap masaToSearch) untuk memundurkan ke keadaan pada satu titik tertentu pada masa lalu.

Secara tersirat, menggunakan pendekatan ini bermakna kemungkinan besar beberapa mesej yang diproses sebelum ini akan dibaca dan diproses semula. Untuk mengelakkan ini, kita boleh menggunakan bacaan idempoten, seperti yang diterangkan dalam Bab 4, untuk menjejaki mesej yang dilihat sebelum ini dan menghapuskan pendua.

Sebagai alternatif, kod pengguna anda boleh disimpan dengan mudah, selagi kehilangan atau penduaan mesej boleh diterima. Apabila kami melihat kes penggunaan yang Kafka biasa digunakan, seperti mengendalikan peristiwa log, metrik, penjejakan klik, dsb., kami menyedari bahawa kehilangan mesej individu tidak mungkin mempunyai kesan yang ketara pada aplikasi sekeliling. Dalam kes sedemikian, nilai lalai boleh diterima dengan sempurna. Sebaliknya, jika permohonan anda perlu menghantar pembayaran, anda mesti berhati-hati menjaga setiap mesej individu. Semuanya bergantung kepada konteks.

Pemerhatian peribadi menunjukkan bahawa apabila intensiti mesej meningkat, nilai setiap mesej individu berkurangan. Mesej besar cenderung bernilai apabila dilihat dalam bentuk agregat.

Ketersediaan Tinggi

Pendekatan Kafka terhadap ketersediaan tinggi sangat berbeza daripada pendekatan ActiveMQ. Kafka direka bentuk sekitar kelompok skala kecil di mana semua kejadian broker menerima dan mengedarkan mesej pada masa yang sama.

Kelompok Kafka terdiri daripada berbilang contoh broker yang dijalankan pada pelayan yang berbeza. Kafka direka bentuk untuk berjalan pada perkakasan kendiri biasa, di mana setiap nod mempunyai storan khusus tersendiri. Penggunaan storan terpasang rangkaian (SAN) tidak disyorkan kerana berbilang nod pengiraan boleh bersaing untuk masa.Π«e selang penyimpanan dan mewujudkan konflik.

Kafka adalah sentiasa hidup sistem. Ramai pengguna Kafka yang besar tidak pernah menutup kluster mereka dan perisian sentiasa dikemas kini dengan mulakan semula berurutan. Ini dicapai dengan menjamin keserasian dengan versi sebelumnya untuk mesej dan interaksi antara broker.

Broker disambungkan ke kluster pelayan Penjaga zoo, yang bertindak sebagai pendaftaran data konfigurasi dan digunakan untuk menyelaraskan peranan setiap broker. ZooKeeper sendiri ialah sistem teragih yang menyediakan ketersediaan tinggi melalui replikasi maklumat dengan menubuhkan kuorum.

Dalam kes asas, topik dicipta dalam gugusan Kafka dengan sifat berikut:

  • Bilangan partition. Seperti yang dibincangkan sebelum ini, nilai tepat yang digunakan di sini bergantung pada tahap bacaan selari yang dikehendaki.
  • Faktor replikasi (faktor) menentukan bilangan contoh broker dalam kelompok harus mengandungi log untuk partition ini.

Menggunakan ZooKeepers untuk penyelarasan, Kafka cuba untuk mengedarkan partition baharu secara adil di kalangan broker dalam kluster. Ini dilakukan oleh satu contoh yang bertindak sebagai Pengawal.

Pada masa larian untuk setiap pembahagian topik Pengawal memberikan peranan kepada broker Ketua (pemimpin, tuan, penyampai) dan pengikut (pengikut, hamba, orang bawahan). Broker, bertindak sebagai ketua untuk partition ini, bertanggungjawab untuk menerima semua mesej yang dihantar kepadanya oleh pengeluar dan mengedarkan mesej kepada pengguna. Apabila mesej dihantar ke partition topik, ia direplikasi kepada semua nod broker yang bertindak sebagai pengikut untuk partition tersebut. Setiap nod yang mengandungi log untuk partition dipanggil replika. Seorang broker boleh bertindak sebagai ketua untuk beberapa partition dan sebagai pengikut untuk yang lain.

Seorang pengikut yang mengandungi semua mesej yang dipegang oleh pemimpin dipanggil replika yang disegerakkan (replika yang berada dalam keadaan disegerakkan, replika dalam penyegerakan). Jika broker yang bertindak sebagai ketua untuk partition turun, mana-mana broker yang terkini atau disegerakkan untuk partition itu boleh mengambil alih peranan ketua. Ia adalah reka bentuk yang sangat mampan.

Sebahagian daripada konfigurasi pengeluar ialah parameter acks, yang menentukan bilangan replika mesti mengakui (mengakui) penerimaan mesej sebelum urutan aplikasi terus menghantar: 0, 1 atau semua. Jika ditetapkan kepada semua, maka apabila mesej diterima, ketua akan menghantar pengesahan kembali kepada pengeluar sebaik sahaja ia menerima pengesahan (pengiktirafan) rekod daripada beberapa isyarat (termasuk dirinya sendiri) yang ditakrifkan oleh tetapan topik min.insync.replicas (lalai 1). Jika mesej tidak berjaya direplikasi, maka pengeluar akan membuang pengecualian aplikasi (NotEnoughReplika atau NotEnoughReplikaSelepasLampirkan).

Konfigurasi biasa mencipta topik dengan faktor replikasi 3 (1 ketua, 2 pengikut setiap partition) dan parameter min.insync.replicas ditetapkan kepada 2. Dalam kes ini, kluster akan membenarkan salah satu broker yang menguruskan partition topik turun tanpa menjejaskan aplikasi pelanggan.

Ini membawa kita kembali kepada pertukaran yang sudah biasa antara prestasi dan kebolehpercayaan. Replikasi berlaku dengan mengorbankan masa menunggu tambahan untuk pengesahan (pengiktirafan) daripada pengikut. Walaupun, kerana ia berjalan secara selari, replikasi kepada sekurang-kurangnya tiga nod mempunyai prestasi yang sama seperti dua (mengabaikan peningkatan dalam penggunaan lebar jalur rangkaian).

Dengan menggunakan skema replikasi ini, Kafka bijak mengelak keperluan untuk menulis secara fizikal setiap mesej ke cakera dengan operasi segerak(). Setiap mesej yang dihantar oleh pengeluar akan ditulis pada log partition, tetapi seperti yang dibincangkan dalam Bab 2, menulis ke fail pada mulanya dilakukan dalam penimbal sistem pengendalian. Jika mesej ini direplikasi kepada contoh Kafka yang lain dan berada dalam ingatannya, kehilangan pemimpin tidak bermakna mesej itu sendiri hilang - ia boleh diambil alih oleh replika yang disegerakkan.
Keengganan untuk melakukan operasi segerak() bermakna Kafka boleh menerima mesej secepat ia boleh menulisnya ke ingatan. Sebaliknya, lebih lama anda boleh mengelak daripada membuang memori ke cakera, lebih baik. Atas sebab ini, tidak jarang broker Kafka diperuntukkan 64 GB atau lebih memori. Penggunaan memori ini bermakna bahawa satu contoh Kafka boleh berjalan dengan mudah pada kelajuan beribu-ribu kali lebih pantas daripada broker mesej tradisional.

Kafka juga boleh dikonfigurasikan untuk menggunakan operasi segerak() kepada pakej mesej. Memandangkan segala-galanya dalam Kafka adalah berorientasikan pakej, ia sebenarnya berfungsi dengan baik untuk banyak kes penggunaan dan merupakan alat yang berguna untuk pengguna yang memerlukan jaminan yang sangat kuat. Kebanyakan prestasi murni Kafka datang daripada mesej yang dihantar kepada broker sebagai paket dan mesej ini dibaca daripada broker dalam blok berurutan menggunakan salinan sifar operasi (operasi semasa tugas menyalin data dari satu kawasan memori ke kawasan memori yang lain tidak dilakukan). Yang terakhir ialah prestasi besar dan keuntungan sumber dan hanya boleh dilakukan melalui penggunaan struktur data log asas yang mentakrifkan skema partition.

Prestasi yang lebih baik boleh didapati dalam gugusan Kafka berbanding dengan satu broker Kafka, kerana partition topik boleh diperluaskan merentasi banyak mesin yang berasingan.

Keputusan

Dalam bab ini, kami melihat bagaimana seni bina Kafka membayangkan semula hubungan antara pelanggan dan broker untuk menyediakan saluran pemesejan yang sangat mantap, dengan daya pemprosesan berkali-kali lebih besar daripada broker mesej konvensional. Kami telah membincangkan fungsi yang digunakan untuk mencapai ini dan melihat secara ringkas seni bina aplikasi yang menyediakan fungsi ini. Dalam bab seterusnya, kita akan melihat masalah biasa yang perlu diselesaikan oleh aplikasi berasaskan pemesejan dan membincangkan strategi untuk menanganinya. Kami akan menamatkan bab ini dengan menggariskan cara bercakap tentang teknologi pemesejan secara umum supaya anda boleh menilai kesesuaiannya untuk kes penggunaan anda.

Bahagian terjemahan sebelumnya: Memahami broker mesej. Mempelajari mekanik pemesejan dengan ActiveMQ dan Kafka. Bab 1

Terjemahan selesai: tele.gg/middle_java

Perlu diteruskan ...

Hanya pengguna berdaftar boleh mengambil bahagian dalam tinjauan. Log masuk, Sama-sama.

Adakah Kafka digunakan dalam organisasi anda?

  • Ya

  • Tiada

  • Dahulu digunakan, kini tidak

  • Kami bercadang untuk menggunakan

38 pengguna mengundi. 8 pengguna berpantang.

Sumber: www.habr.com

Tambah komen