จำเป็นต้องมีคีย์เป็นส่วนหนึ่งของการส่งข้อความถึงคาฟคาหรือไม่


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

ขณะนี้ฉันกำลังส่งข้อความโดยไม่มีคีย์ใด ๆ เป็นส่วนหนึ่งของข้อความที่ถูกคีย์จะยังใช้งานได้delete.retention.msหรือไม่ ฉันต้องส่งคีย์เป็นส่วนหนึ่งของข้อความหรือไม่? การสร้างคีย์เป็นส่วนหนึ่งของข้อความนี้ดีหรือไม่

คำตอบ:


195

คีย์ส่วนใหญ่มีประโยชน์ / จำเป็นหากคุณต้องการคำสั่งที่ชัดเจนสำหรับคีย์และกำลังพัฒนาบางอย่างเช่นเครื่องของรัฐ หากคุณต้องการให้ข้อความที่มีคีย์เดียวกัน (เช่น id เฉพาะ) ปรากฏในลำดับที่ถูกต้องเสมอการแนบคีย์ไปยังข้อความจะช่วยให้แน่ใจว่าข้อความที่มีคีย์เดียวกันจะไปที่พาร์ติชันเดียวกันในหัวข้อเสมอ Kafka รับประกันคำสั่งซื้อภายในพาร์ติชัน แต่ไม่ใช่ข้ามพาร์ติชันในหัวข้อหนึ่งดังนั้นอีกทางเลือกหนึ่งคือไม่ให้คีย์ซึ่งจะส่งผลให้มีการกระจายแบบ round-robin ข้ามพาร์ติชัน - จะไม่คงลำดับ

ในกรณีของเครื่องสถานะสามารถใช้คีย์กับlog.cleaner.enableเพื่อลบรายการที่ซ้ำกันด้วยคีย์เดียวกัน ในกรณีนี้ Kafka จะถือว่าแอปพลิเคชันของคุณสนใจเฉพาะอินสแตนซ์ล่าสุดของคีย์ที่ระบุและตัวล้างบันทึกจะลบรายการที่ซ้ำกันเก่ากว่าของคีย์ที่กำหนดเฉพาะในกรณีที่คีย์นั้นไม่เป็นโมฆะ รูปแบบของการบีบอัดบันทึกนี้ถูกควบคุมโดยคุณสมบัติlog.cleaner.delete.retentionและต้องใช้คีย์

หรืออีกวิธีหนึ่งคุณสมบัติทั่วไปlog.retention.hoursซึ่งเปิดใช้งานตามค่าเริ่มต้นจะทำงานโดยการลบเซ็กเมนต์ทั้งหมดของบันทึกที่ล้าสมัย ในกรณีนี้ไม่จำเป็นต้องให้คีย์ Kafka จะลบส่วนของบันทึกที่เก่ากว่าระยะเวลาเก็บรักษาที่กำหนด

นั่นคือทั้งหมดที่จะกล่าวได้หากคุณเปิดใช้งานการบีบอัดบันทึกหรือต้องการคำสั่งที่เข้มงวดสำหรับข้อความที่มีคีย์เดียวกันคุณควรใช้คีย์อย่างแน่นอน มิฉะนั้นคีย์ว่างอาจให้การกระจายที่ดีขึ้นและป้องกันปัญหาจุดร้อนที่อาจเกิดขึ้นในกรณีที่บางคีย์อาจปรากฏมากกว่าคีย์อื่น ๆ


ฉันยังใหม่กับ Kafka นั่นคือเหตุผลที่ถามคำถามมากมาย: มีคำถามสองข้อเกี่ยวกับสิ่งนี้: คำถามแรกเราสามารถใช้ข้อความตามหลักสำคัญได้หรือไม่ขณะนี้ฉันกำลังบริโภคข้อความจาก MessagAndMetadata mm หรือเป็นการดีที่จะเพิกเฉยต่อคีย์ในช่วงเวลาที่มีข้อความเสียฉันใช้ระดับสูง Consumer Api
gaurav

1
@kuujo ฉันสมมติว่าการยกเลิกการทำซ้ำนี้มีไว้สำหรับรายการบันทึกเท่านั้นไม่จำเป็นต้องลบข้อความที่ซ้ำกันในคิวหัวข้อ?
user1658296

2
@oblivion การมีข้อความเข้าสู่พาร์ติชันเดียวกันตามลำดับเป็นสิ่งสำคัญสำหรับการจัดการการอัปเดตที่ไม่ระบุรายละเอียดเช่นลูกค้าเลือกวันที่จัดส่ง (หนึ่งข้อความ) แต่จะเปลี่ยนใจในภายหลัง (ข้อความที่สอง) หากข้อความถูกส่งไปยังพาร์ติชันที่แตกต่างกันข้อความใดข้อความหนึ่งอาจถูกประมวลผลก่อน / สุดท้ายเช่นกับผู้บริโภค 2 รายที่ใช้จากแต่ละพาร์ติชัน หากข้อความทั้งสองที่เกี่ยวข้องกับการจัดส่งเดียวกันไปอยู่ในพาร์ติชันเดียวกันระบบจะประมวลผลก่อนเข้าก่อนออกโดยระบุวันที่จัดส่งสุดท้ายที่ถูกต้อง
Kunal

3
การรับประกันคำสั่งซื้อไม่ได้มาจากคีย์ แต่มาจากข้อความที่อยู่ในพาร์ติชันเดียวกัน การกำหนดเส้นทางข้อความไปยังพาร์ติชันไม่จำเป็นต้องใช้คีย์ คุณสามารถระบุพาร์ติชันอย่างชัดเจนได้เมื่อสร้างProducerRecord
Malt

2
ความเข้าใจของฉันคือไคลเอนต์ผู้ผลิตมีหน้าที่รับผิดชอบในการเลือกพาร์ติชัน ( kafka.apache.org/documentation.html#design_loadbalancing ) ซึ่งอาจขึ้นอยู่กับคีย์หรือไม่ก็ได้ ทำไมคุณถึงบอกว่าคีย์จำเป็นสำหรับการสั่งซื้อ?
lfk

14

tl; dr ไม่ไม่จำเป็นต้องใช้คีย์ในการส่งข้อความถึงคาฟคา แต่...


นอกจากคำตอบที่เป็นที่ยอมรับที่เป็นประโยชน์แล้วฉันยังต้องการเพิ่มรายละเอียดอีกเล็กน้อย

การแบ่งพาร์ติชัน

โดยค่าเริ่มต้น Kafka จะใช้คีย์ของข้อความเพื่อเลือกพาร์ติชันของหัวข้อที่เขียนถึง สิ่งนี้ทำได้DefaultPartitionerโดย

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

หากไม่มีคีย์ให้ Kafka จะแบ่งข้อมูลแบบสุ่มในรูปแบบ Round-robin

ในคาฟคาคุณสามารถสร้างพาร์ติชันเนอร์ของคุณเองได้โดยการขยายPartitionerคลาส สำหรับสิ่งนี้คุณต้องแทนที่partitionวิธีการที่มีลายเซ็น:

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

โดยปกติคีย์ของข้อความ Kafka จะใช้เพื่อเลือกพาร์ติชันและค่าส่งคืน (ประเภทint) คือหมายเลขพาร์ติชัน หากไม่มีคีย์คุณจะต้องพึ่งพาค่าซึ่งอาจซับซ้อนกว่าในการประมวลผล

การสั่งซื้อ

ตามที่ระบุไว้ในคำตอบที่ระบุ Kafka รับประกันการสั่งซื้อข้อความในระดับพาร์ติชันเท่านั้น

สมมติว่าคุณต้องการจัดเก็บธุรกรรมทางการเงินสำหรับลูกค้าของคุณในหัวข้อ Kafka ที่มีสองพาร์ติชัน ข้อความอาจมีลักษณะ (คีย์: ค่า)

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}

เนื่องจากเราไม่ได้กำหนดคีย์ทั้งสองพาร์ติชันจึงน่าจะมีลักษณะดังนี้

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

ผู้บริโภคของคุณที่อ่านหัวข้อนั้นอาจบอกคุณได้ว่ายอดเงินในบัญชีคือ 600 ในช่วงเวลาหนึ่งแม้ว่าจะไม่เคยเป็นเช่นนั้นก็ตาม! เพียงเพราะอ่านข้อความทั้งหมดในพาร์ติชัน 0 ก่อนข้อความในพาร์ติชัน 1

ด้วยคีย์ที่มีความหมาย (เช่น customerId) สิ่งนี้สามารถหลีกเลี่ยงได้เนื่องจากการแบ่งส่วนจะเป็นดังนี้:

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

บันทึกการบดอัด

โดยไม่ต้องคีย์เป็นส่วนหนึ่งของข้อความของคุณคุณจะไม่สามารถตั้งค่าการกำหนดค่าหัวข้อการcleanup.policy compactedตามเอกสารประกอบ "การบีบอัดบันทึกช่วยให้มั่นใจได้ว่า Kafka จะรักษาค่าสุดท้ายที่ทราบไว้เป็นอย่างน้อยสำหรับแต่ละคีย์ข้อความภายในบันทึกข้อมูลสำหรับพาร์ติชันหัวข้อเดียว"

การตั้งค่าที่ดีและเป็นประโยชน์นี้จะไม่สามารถใช้ได้หากไม่มีคีย์ใด ๆ

การใช้คีย์

ในกรณีการใช้งานจริงกุญแจสำคัญของข้อความ Kafka อาจมีอิทธิพลอย่างมากต่อประสิทธิภาพและความชัดเจนของตรรกะทางธุรกิจของคุณ

ตัวอย่างเช่นสามารถใช้คีย์สำหรับการแบ่งพาร์ติชันข้อมูลของคุณได้ ในขณะที่คุณสามารถควบคุมผู้บริโภคของคุณให้อ่านจากพาร์ติชันเฉพาะได้สิ่งนี้สามารถใช้เป็นตัวกรองที่มีประสิทธิภาพได้ นอกจากนี้คีย์ยังสามารถรวมข้อมูลเมตาบางส่วนเกี่ยวกับค่าจริงของข้อความที่ช่วยให้คุณควบคุมการประมวลผลในภายหลังได้ โดยปกติแล้วคีย์จะมีขนาดเล็กกว่าดังนั้นจึงสะดวกกว่าในการแยกวิเคราะห์คีย์แทนค่าทั้งหมด ในเวลาเดียวกันคุณสามารถใช้การทำให้เป็นอนุกรมและการลงทะเบียนสคีมาทั้งหมดเมื่อเสร็จสิ้นกับค่าของคุณพร้อมกับคีย์

เป็นบันทึกนอกจากนี้ยังมีแนวคิดของส่วนหัวที่สามารถใช้ในการจัดเก็บข้อมูลดูเอกสาร


0

โดยพื้นฐานแล้วคีย์ที่มีข้อความจะถูกส่งไปเพื่อรับข้อความที่เรียงลำดับสำหรับฟิลด์เฉพาะ

  • หากคีย์ = null ข้อมูลจะถูกส่งไปยังพาร์ติชันอื่นและไปยังโบรกเกอร์อื่นในสภาพแวดล้อมแบบกระจายและแน่นอนในหัวข้อเดียวกัน)
  • หากมีการส่งคีย์ข้อความทั้งหมดสำหรับคีย์นั้นจะไปที่พาร์ติชันเดียวกันเสมอ

อธิบายและยกตัวอย่าง

  • คีย์อาจเป็นสตริงหรือจำนวนเต็มก็ได้เป็นต้นใช้ตัวอย่างของจำนวนเต็ม staff_id เป็นคีย์
  • ดังนั้น emplyee_id 123 จะไปที่พาร์ติชัน 0 เสมอซึ่งพนักงาน _id 345 จะไปที่พาร์ติชัน 1 เสมอซึ่งจะถูกกำหนดโดยอัลกอริธึมการแฮชคีย์ซึ่งขึ้นอยู่กับจำนวนพาร์ติชัน
  • หากคุณไม่ส่งคีย์ใด ๆ ข้อความจะไปที่พาร์ติชันใดก็ได้โดยใช้เทคนิค round-robin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.