Apakah kunci diperlukan sebagai bagian dari pengiriman pesan ke Kafka?

102
KeyedMessage<String, byte[]> keyedMessage = new KeyedMessage<String, byte[]>(request.getRequestTopicName(), SerializationUtils.serialize(message)); 
producer.send(keyedMessage);

Saat ini, saya mengirim pesan tanpa kunci apa pun sebagai bagian dari pesan kunci, apakah masih akan berfungsi delete.retention.ms? Apakah saya perlu mengirim kunci sebagai bagian dari pesan? Apakah baik menjadikan kunci sebagai bagian dari pesan?

gaurav
sumber

Jawaban:

184

Kunci sebagian besar berguna / diperlukan jika Anda memerlukan pesanan yang kuat untuk sebuah kunci dan sedang mengembangkan sesuatu seperti mesin negara. Jika Anda mengharuskan pesan dengan kunci yang sama (misalnya, id unik) selalu terlihat dalam urutan yang benar, melampirkan kunci ke pesan akan memastikan pesan dengan kunci yang sama selalu masuk ke partisi yang sama dalam suatu topik. Kafka menjamin keteraturan dalam sebuah partisi, tetapi tidak di seluruh partisi dalam sebuah topik, jadi sebagai alternatif tidak memberikan kunci - yang akan menghasilkan distribusi round-robin di seluruh partisi - tidak akan mempertahankan urutan tersebut.

Dalam kasus mesin negara, kunci dapat digunakan dengan log.cleaner.enable untuk menghapus duplikat entri dengan kunci yang sama. Dalam kasus tersebut, Kafka mengasumsikan bahwa aplikasi Anda hanya peduli tentang contoh terbaru dari kunci tertentu dan pembersih log menghapus duplikat lama dari kunci tertentu hanya jika kunci tersebut tidak null. Bentuk pemadatan log ini dikontrol oleh properti log.cleaner.delete.retention dan membutuhkan kunci.

Alternatifnya, properti log.retention.hours yang lebih umum , yang diaktifkan secara default, bekerja dengan menghapus seluruh segmen log yang kedaluwarsa. Dalam kasus ini, kunci tidak harus disediakan. Kafka hanya akan menghapus potongan log yang lebih lama dari periode penyimpanan yang diberikan.

Itu saja untuk mengatakan, jika Anda telah mengaktifkan pemadatan log atau memerlukan urutan ketat untuk pesan dengan kunci yang sama, maka Anda pasti harus menggunakan kunci. Jika tidak, kunci null dapat memberikan distribusi yang lebih baik dan mencegah potensi masalah hot spot dalam kasus di mana beberapa kunci mungkin muncul lebih dari yang lain.

kuujo
sumber
Saya baru mengenal Kafka itulah alasannya mengajukan begitu banyak pertanyaan: Ada beberapa pertanyaan tentang ini: Pertanyaan Pertama, Bisakah kita menggunakan pesan berdasarkan kunci, Saat ini saya mengonsumsi pesan dari MessagAndMetadata mm. atau apakah boleh mengabaikan kunci pada saat mengonsumsi pesan. Saya menggunakan Api Konsumen Tingkat hig.
gaurav
1
@kuujo Saya berasumsi bahwa penghilangan duplikat ini hanya untuk entri log, belum tentu menghapus duplikat pesan pada antrian topik?
pengguna1658296
2
@oblivion memiliki pesan yang masuk ke partisi yang sama secara berurutan penting untuk menangani update non-idemponent misalnya pelanggan memilih tanggal pengiriman (satu pesan) tetapi berubah pikiran nanti (pesan kedua). Jika pesan akan dikirim ke partisi yang berbeda maka salah satu pesan dapat diproses pertama / terakhir misalnya dengan 2 konsumen mengkonsumsi dari setiap partisi. Jika kedua pesan yang berkaitan dengan Pengiriman yang sama masuk ke partisi yang sama, maka pesan tersebut diproses pertama kali masuk pertama keluar, memberikan tanggal pengiriman akhir yang benar.
Kunal
3
Jaminan urutan tidak berasal dari kunci tetapi dari pesan yang berada di partisi yang sama. Perutean pesan ke partisi tidak harus berbasis kunci. Anda dapat secara eksplisit menentukan partisi saat membuatProducerRecord
Malt
2
Pemahaman saya adalah klien produsen bertanggung jawab untuk memilih partisi ( kafka.apache.org/documentation.html#design_loadbalancing ), yang mungkin didasarkan pada kunci atau tidak. Jadi mengapa Anda mengatakan kunci diperlukan untuk memesan?
lfk
11

Selain jawaban yang diterima yang sangat membantu, saya ingin menambahkan beberapa detail lagi

Mempartisi

Secara default, Kafka menggunakan kunci pesan untuk memilih partisi topik yang ditulinya. Ini dilakukan di DefaultPartitionerby

kafka.common.utils.Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;

Jika tidak ada kunci yang diberikan, maka Kafka akan mempartisi data secara acak dengan cara round-robin.

Di Kafka, dimungkinkan untuk membuat Partitioner Anda sendiri dengan memperluas Partitionerkelas. Untuk ini, Anda perlu mengganti partitionmetode yang memiliki tanda tangan:

int partition(String topic, 
              Object key,
              byte[] keyBytes,
              Object value,
              byte[] valueBytes,
              Cluster cluster)

Biasanya, kunci pesan Kafka digunakan untuk memilih partisi. Tanpa kunci, Anda perlu mengandalkan nilai yang mungkin jauh lebih rumit untuk diproses.

Memerintah

Seperti yang dinyatakan dalam jawaban yang diberikan, Kafka memiliki jaminan untuk memesan pesan hanya di tingkat partisi.

Katakanlah Anda ingin menyimpan transaksi keuangan untuk pelanggan Anda dalam topik Kafka dengan dua partisi. Pesan akan terlihat seperti (key: value)

null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": -1337}
null:{"customerId": 1, "changeInBankAccount": +200}

Karena kami belum menentukan kunci, kedua partisi akan terlihat seperti

// partition 0
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": -1337}

Konsumen Anda yang membaca topik tersebut dapat memberi tahu Anda bahwa saldo pada akun adalah 600 pada waktu tertentu meskipun itu tidak pernah terjadi! Hanya karena itu membaca semua pesan di partisi 0 sebelum pesan di partisi 1.

Dengan kunci yang masuk akal (seperti customerId) ini dapat dihindari karena partitoning akan seperti ini:

// partition 0
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": -1337}
1:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
2:{"customerId": 2, "changeInBankAccount": +100}

Pemadatan log

Tanpa kunci sebagai bagian dari pesan Anda, Anda tidak akan dapat menyetel konfigurasi topik cleanup.policyke compacted. Menurut dokumentasi, "pemadatan log memastikan bahwa Kafka akan selalu mempertahankan setidaknya nilai terakhir yang diketahui untuk setiap kunci pesan dalam log data untuk satu partisi topik.".

Pengaturan yang baik dan bermanfaat ini tidak akan tersedia tanpa kunci apa pun.

Penggunaan Kunci

Dalam kasus penggunaan kehidupan nyata, kunci pesan Kafka dapat berpengaruh besar pada kinerja dan kejelasan logika bisnis Anda.

Misalnya, kunci dapat digunakan secara alami untuk mempartisi data Anda. Karena Anda dapat mengontrol konsumen untuk membaca dari partisi tertentu, ini dapat berfungsi sebagai filter yang efisien. Selain itu, kunci dapat menyertakan beberapa data meta pada nilai sebenarnya dari pesan yang membantu Anda mengontrol pemrosesan selanjutnya. Kunci biasanya lebih kecil dari nilai dan oleh karena itu lebih mudah untuk mengurai kunci daripada nilai keseluruhan. Pada saat yang sama, Anda dapat menerapkan semua serialisasi dan pendaftaran skema seperti yang dilakukan dengan nilai Anda juga dengan kunci.

Sebagai catatan, ada juga konsep Header yang bisa digunakan untuk menyimpan informasi, lihat dokumentasi .

mike
sumber
0

Kunci dengan pesan pada dasarnya dikirim untuk mendapatkan pesan yang memesan untuk bidang tertentu.

  • Jika key = null, data dikirim secara round-robin (ke partisi yang berbeda dan ke broker yang berbeda di lingkungan terdistribusi dan tentu saja ke topik yang sama.).
  • Jika kunci dikirim, maka semua pesan untuk kunci itu akan selalu masuk ke partisi yang sama.

Jelaskan dan contoh

  • key bisa berupa string atau integer, dll. ambil contoh integer employee_id sebagai key.
  • Jadi emplyee_id 123 akan selalu pergi ke partisi 0, employee_id 345 akan selalu pergi ke partisi 1. Ini ditentukan oleh algoritma hashing kunci yang bergantung pada jumlah partisi.
  • jika Anda tidak mengirim kunci apa pun, pesan dapat masuk ke partisi mana pun menggunakan teknik round-robin.
Pradeep Singh
sumber