Kafka'ya mesaj göndermenin bir parçası olarak anahtar gerekli mi?


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

Şu anda, anahtarlı mesajların parçası olarak herhangi bir anahtarsız mesaj gönderiyorum, yine de çalışacak delete.retention.msmı? Mesajın bir parçası olarak bir anahtar göndermem gerekiyor mu? Mesajın bir parçası olarak anahtar yapmak iyi mi?

Yanıtlar:


190

Bir anahtar için güçlü bir siparişe ihtiyacınız varsa ve bir durum makinesi gibi bir şey geliştiriyorsanız, anahtarlar çoğunlukla yararlı / gereklidir. Aynı anahtara sahip mesajların (örneğin, benzersiz bir kimlik) her zaman doğru sırada görülmesini istiyorsanız, mesajlara bir anahtar eklemek, aynı anahtara sahip mesajların her zaman bir konudaki aynı bölüme gitmesini sağlar. Kafka, bir bölüm içindeki düzeni garanti eder, ancak bir konudaki bölümler arasında garanti vermez, bu nedenle alternatif olarak bir anahtar sağlamamak - bölümler arasında yuvarlak sıralı dağıtımla sonuçlanır - bu düzeni korumaz.

Durum makinesi olması durumunda, anahtarlar aynı anahtarla girişleri tekilleştirmek için log.cleaner.enable ile kullanılabilir . Bu durumda Kafka, uygulamanızın yalnızca belirli bir anahtarın en son örneğini önemsediğini ve günlük temizleyicinin belirli bir anahtarın eski kopyalarını yalnızca anahtar boş değilse sildiğini varsayar. Bu günlük sıkıştırma biçimi, log.cleaner.delete.retention özelliği tarafından kontrol edilir ve anahtar gerektirir.

Alternatif olarak, varsayılan olarak etkinleştirilen daha yaygın olan log.retention.hours özelliği , güncel olmayan günlüğün tüm bölümlerini silerek çalışır. Bu durumda anahtarların sağlanması gerekmez. Kafka, verilen saklama süresinden daha eski olan günlük parçalarını silecektir.

Söylenecek tek şey bu, günlük sıkıştırmayı etkinleştirdiyseniz veya aynı anahtara sahip mesajlar için katı bir sıralama istiyorsanız, kesinlikle anahtarları kullanmalısınız. Aksi takdirde, boş anahtarlar daha iyi dağıtım sağlayabilir ve bazı anahtarların diğerlerinden daha fazla görünebileceği durumlarda olası sıcak nokta sorunlarını önleyebilir.


Kafka'da yeniyim, bu kadar çok soru sormanın nedeni: Bu konuda birkaç soru var: İlk Soru, Mesajı anahtar bazında tüketebilir miyiz, Şu anda MessagAndMetadata mm'den gelen mesajı tüketiyorum. veya mesajı tüketirken anahtarı yok saymak sorun değil mi? hig Level Consumer Api kullanıyorum.
gaurav

1
@kuujo Bu tekilleştirmenin yalnızca günlük girişleri için olduğunu varsayıyorum, bir konu kuyruğundaki iletileri mutlaka tekilleştirmiyor mu?
user1658296

2
@oblivion mesajların sırayla aynı bölüme gitmesi idemponent olmayan güncellemelerin işlenmesi için önemlidir, örneğin müşteri teslimat tarihini seçer (bir mesaj) ancak daha sonra fikrini değiştirir (ikinci mesaj). Mesajlar farklı bölümlere gidecekse, bu durumda her iki mesaj da ilk / son olarak işlenebilir, örneğin her bölümden 2 tüketici tüketerek. Aynı Teslimatla ilgili her iki mesaj da aynı bölüme girerse, ilk giren ilk çıkar işlenir ve doğru son teslim tarihi verilir.
Kunal

3
Sipariş garantileri anahtardan değil aynı bölümdeki mesajlardan gelir. Mesajların bölümlere yönlendirilmesi anahtar tabanlı olmak zorunda değildir. Bir bölüm oluştururken açıkça bir bölüm belirtebilirsinizProducerRecord
Malt

2
Anladığım kadarıyla, anahtara dayalı olan veya olmayan bölümü ( kafka.apache.org/documentation.html#design_loadbalancing ) seçmekten üretici istemci sorumludur . Öyleyse neden sipariş için anahtarların gerekli olduğunu söylüyorsunuz?
lfk

13

tl; dr Hayır, Kafka'ya mesaj göndermenin bir parçası olarak bir anahtar gerekmez. Fakat...


Kabul edilen çok faydalı cevaba ek olarak birkaç ayrıntı daha eklemek istiyorum

Bölümleme

Varsayılan olarak Kafka, yazdığı konunun bölümünü seçmek için mesajın anahtarını kullanır. Bu yapılır DefaultPartitionersaldırıdaki

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

Anahtar sağlanmadıysa, Kafka verileri rastgele sıralı bir şekilde bölümlere ayırır.

Kafka'da Partitionersınıfı genişleterek kendi Partitioner'ınızı oluşturmanız mümkündür . Bunun için partitionimzaya sahip yöntemi geçersiz kılmanız gerekir :

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

Genellikle, bir Kafka mesajının anahtarı bölümü seçmek için kullanılır ve dönüş değeri (türünün int) bölüm numarasıdır. Anahtar olmadan, işlenmesi çok daha karmaşık olabilecek değere güvenmeniz gerekir.

Sipariş verme

Verilen cevapta da belirtildiği gibi Kafka, mesajların sadece bölüm seviyesinde sıralanması konusunda garantiye sahiptir.

Diyelim ki müşterileriniz için finansal işlemleri iki bölümlü bir Kafka konusunda depolamak istiyorsunuz. Mesajlar şöyle görünebilir (anahtar: değer)

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}

Bir anahtar tanımlamadığımız için iki bölüm muhtemelen şöyle görünecektir:

// 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}

Bu konuyu okuyan tüketiciniz, size hesaptaki bakiyenin belirli bir zamanda 600 olduğunu söylemeye başlayabilir, ancak bu asla böyle olmamıştır! Sadece 1. bölümdeki mesajlardan önce bölüm 0'daki tüm mesajları okuyordu.

Hassas bir anahtarla (customerId gibi) bu, ayırma şu şekilde olacağından önlenebilir:

// 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}

Günlük sıkıştırma

Mesajlarınızın bir parçası olarak bir anahtar olmadan, konu yapılandırmasını cleanup.policyolarak ayarlayamazsınız compacted. Belgelere göre "günlük sıkıştırma, Kafka'nın her zaman tek bir konu bölümü için veri günlüğündeki her ileti anahtarı için en azından bilinen son değeri tutmasını sağlar."

Bu hoş ve yararlı ayar, herhangi bir anahtar olmadan kullanılamayacak.

Anahtarların Kullanımı

Gerçek hayattaki kullanım durumlarında, bir Kafka mesajının anahtarı, performansınız ve iş mantığınızın netliği üzerinde büyük bir etkiye sahip olabilir.

Örneğin bir anahtar, verilerinizi bölümlemek için doğal olarak kullanılabilir. Tüketicilerinizi belirli bölümlerden okumak için kontrol edebildiğiniz için, bu verimli bir filtre görevi görebilir. Ayrıca, anahtar, mesajın gerçek değeriyle ilgili sonraki işlemeyi kontrol etmenize yardımcı olacak bazı meta verileri içerebilir. Anahtarlar genellikle değerlerden daha küçüktür ve bu nedenle tüm değer yerine bir anahtarı ayrıştırmak daha uygundur. Aynı zamanda tüm serileştirmeleri ve şema kaydını değeriniz ile yaptığınız gibi anahtar ile de uygulayabilirsiniz.

Not olarak, bilgi depolamak için kullanılabilecek Başlık kavramı da vardır, belgelere bakın .


0

Mesaj içeren anahtar, temel olarak belirli bir alan için mesaj sırasını almak için gönderilir.

  • Anahtar = null ise, veriler sürekli olarak gönderilir (farklı bir bölüme ve dağıtılmış ortamdaki farklı bir aracıya ve tabii ki aynı konuya.).
  • Bir anahtar gönderilirse, o anahtara ilişkin tüm mesajlar her zaman aynı bölüme gider.

Açıkla ve örnek

  • anahtar herhangi bir dize veya tamsayı olabilir, vb. anahtar olarak bir tam sayı çalışan_kimliği örneği alın.
  • Böylece emplyee_id 123 her zaman 0 bölümüne gidecek, staff_id 345 her zaman bölüm 1'e gidecek. Bu, bölümlerin sayısına bağlı olan anahtar hash algoritması tarafından kararlaştırılır.
  • herhangi bir anahtar göndermezseniz, mesaj bir round-robin tekniği kullanarak herhangi bir bölüme gidebilir.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.