RabbitMQ และความสัมพันธ์ระหว่างช่องและการเชื่อมต่อ


176

ลูกค้า RabbitMQ Javaมีแนวคิดต่อไปนี้:

  • Connection - การเชื่อมต่อกับอินสแตนซ์ของเซิร์ฟเวอร์ RabbitMQ
  • Channel - ???
  • กลุ่มเธรดผู้บริโภค - กลุ่มของเธรดที่ใช้ข้อความจากคิวเซิร์ฟเวอร์ RabbitMQ
  • Queue - โครงสร้างที่เก็บข้อความตามลำดับ FIFO

ฉันพยายามเข้าใจความสัมพันธ์และที่สำคัญกว่านั้นคือความสัมพันธ์ระหว่างพวกเขา

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

ขอบคุณล่วงหน้าสำหรับความช่วยเหลือที่นี่!


คำตอบสำหรับคำถามนี้ทำให้ฉันรายงานปัญหานี้กับลูกค้า golang แทนที่จะถามคำถามที่นี่
Bruce Adams

ช่องสัญญาณเป็นแนวคิดเชิงตรรกะที่ใช้ในการเชื่อมต่อ TCP แบบฟิสิคัลเดียวระหว่างไคลเอนต์และโหนด หมายเลขสถานีจะรวมอยู่ในส่วนหัวของข้อความของกรอบ AMQP
ymas

คำตอบ:


196
  1. A Connectionแสดงถึงการเชื่อมต่อ TCP จริงกับนายหน้าข้อความในขณะที่ a Channelเป็นการเชื่อมต่อเสมือน (การเชื่อมต่อ AMQP) ภายใน วิธีนี้คุณสามารถใช้การเชื่อมต่อ (เสมือน) ได้มากเท่าที่คุณต้องการภายในแอปพลิเคชันของคุณโดยไม่ต้องโหลดโบรกเกอร์มากเกินไปด้วยการเชื่อมต่อ TCP

  2. คุณสามารถChannelใช้ได้ทุกอย่าง อย่างไรก็ตามหากคุณมีหลายเธรดแนะนำให้ใช้Channelแต่ละหัวข้อแตกต่างกัน

    Channel thread-safety ในคู่มือ Java Client API :

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

    มีไม่มีความสัมพันธ์โดยตรงระหว่างเป็นและChannel QueueA Channelใช้เพื่อส่งคำสั่ง AMQP ไปยังโบรกเกอร์ นี่อาจเป็นการสร้างคิวหรือสิ่งที่คล้ายกัน แต่แนวคิดเหล่านี้ไม่ได้เชื่อมโยงกัน

  3. แต่ละConsumerรันในเธรดของตนเองที่จัดสรรจาก consumer thread pool หากผู้บริโภคหลายคนสมัครสมาชิกคิวเดียวกันโบรกเกอร์จะใช้ round-robin เพื่อกระจายข้อความระหว่างกัน ดูการสอนที่สอง: "งานคิว"

    นอกจากนี้ยังเป็นไปได้ที่จะแนบเหมือนกันConsumerกับหลายคิว คุณสามารถเข้าใจผู้บริโภคว่าเป็นการโทรกลับ สิ่งเหล่านี้เรียกว่าทุกครั้งที่มีข้อความมาถึงคิวที่ Consumer ถูกผูกไว้ สำหรับกรณีของไคลเอนต์ Java แต่ละผู้บริโภคมีวิธีการhandleDelivery(...)ซึ่งหมายถึงวิธีการโทรกลับ สิ่งที่คุณมักจะทำคือ subclass และแทนที่DefaultConsumer handleDelivery(...)หมายเหตุ: ถ้าคุณแนบอินสแตนซ์ผู้บริโภคเดียวกันกับหลายคิววิธีนี้จะถูกเรียกโดยเธรดที่แตกต่างกัน ดังนั้นดูแลการซิงโครไนซ์ถ้าจำเป็น


4
เพียงเพิ่มจากเอกสารประกอบ: การโทรกลับไปยังผู้บริโภคถูกส่งไปยังเธรดแยกจากเธรดที่จัดการโดยการเชื่อมต่อ ซึ่งหมายความว่าผู้บริโภคสามารถโทรหาวิธีการบล็อกบนการเชื่อมต่อหรือช่องสัญญาณได้อย่างปลอดภัยเช่น queueDeclare, txCommit, basicCancel หรือ basicPublish แต่ละช่องมีเธรดการจัดส่งของตนเอง สำหรับกรณีการใช้งานที่พบบ่อยที่สุดของผู้บริโภคหนึ่งรายต่อหนึ่งช่องทางนี้หมายความว่าผู้บริโภคไม่ได้ถือครองผู้บริโภครายอื่น หากคุณมีผู้บริโภคหลายคนต่อช่องโปรดทราบว่าผู้บริโภคที่ใช้เวลานานอาจระงับการโทรกลับไปยังผู้บริโภครายอื่นในช่องนั้น
ฆา

1
หากคุณแนบอินสแตนซ์ Consumer เดียวกันกับหลายคิวจาก Channel เดียวกันซึ่งหมายความว่าการโทรกลับถูกส่งไปที่เธรดเดียวกัน ในกรณีนี้คุณไม่ต้องการการซิงโครไนซ์
ฆา

ฉันสามารถใช้การเชื่อมต่อได้เพียงครั้งเดียวและใช้กลุ่มช่องทางแทนกลุ่มการเชื่อมต่อหรือไม่ สิ่งนี้จะส่งผลต่อปริมาณงานการเผยแพร่ข้อความหรือไม่?
qeek

4
ฉันคิดว่าการอ้างอิงไปยัง Java Client API นี้ล้าสมัยแล้วและในความเป็นจริงการอ้างอิงของวันนี้ขัดแย้งกับคำพูดในคำตอบนี้โดยตรง การอ้างอิงในวันนี้กล่าวว่า "อินสแตนซ์ของช่องจะต้องไม่ถูกแชร์ระหว่างเธรด"
Edwin Dalorzo

1
@EdwinDalorzo - ดูเหมือนว่าใครก็ตามที่เดิมเขียนเอกสารไม่เข้าใจการเชื่อมต่อช่องสัญญาณ สถาปัตยกรรมพื้นฐานของ AMQP 0.9.1 ปฏิบัติกับช่องเป็นเซสชันจริงๆ ฉันเดาว่าเป็นเหตุผลของการเปลี่ยนแปลง
theMayer

53

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

TL; DR

การเชื่อมต่อเป็นซ็อกเก็ต TCP แบบต่อรองทางกายภาพกับเซิร์ฟเวอร์ AMQP ไคลเอนต์ที่ใช้งานอย่างถูกต้องจะมีหนึ่งในแอปพลิเคชันเหล่านี้ต่อเธรดที่ปลอดภัย

ช่องเป็นเซสชั่นโปรแกรมเดียวในการเชื่อมต่อ เธรดจะมีเซสชันเหล่านี้ตั้งแต่หนึ่งเซสชันขึ้นไป สถาปัตยกรรม AMQP 0.9.1 คือสิ่งเหล่านี้จะไม่ถูกใช้ร่วมกันระหว่างเธรดและควรถูกปิด / ทำลายเมื่อเธรดที่สร้างเสร็จแล้ว พวกเขายังถูกปิดโดยเซิร์ฟเวอร์เมื่อการละเมิดโปรโตคอลต่างๆเกิดขึ้น

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

ข้อเท็จจริงการเชื่อมต่อ

ก่อนอื่นตามที่คนอื่นชี้อย่างถูกต้องการเชื่อมต่อคือวัตถุที่แสดงถึงการเชื่อมต่อ TCP จริงไปยังเซิร์ฟเวอร์ การเชื่อมต่อถูกระบุที่ระดับโปรโตคอลใน AMQP และการสื่อสารทั้งหมดกับนายหน้าเกิดขึ้นผ่านการเชื่อมต่อหนึ่งหรือมากกว่า

  • เนื่องจากเป็นการเชื่อมต่อ TCP จริงจึงมีที่อยู่ IP และพอร์ต #
  • พารามิเตอร์พิธีสารมีการเจรจาบนพื้นฐานต่อลูกค้าเป็นส่วนหนึ่งของการตั้งค่าการเชื่อมต่อ (กระบวนการที่เรียกว่าการจับมือกัน
  • มันถูกออกแบบมาให้ยาวอาศัยอยู่ ; มีบางกรณีที่การปิดการเชื่อมต่อเป็นส่วนหนึ่งของการออกแบบโปรโตคอล
  • จากมุมมองของ OSI มันอาจอยู่ที่ไหนสักแห่งรอบ ๆเลเยอร์ 6
  • สามารถตั้งค่า Heartbeats เพื่อตรวจสอบสถานะการเชื่อมต่อได้เนื่องจาก TCP ไม่มีสิ่งใดที่อยู่ภายในตัวเองเพื่อทำสิ่งนี้
  • วิธีที่ดีที่สุดคือให้เธรดเฉพาะจัดการอ่านและเขียนไปยังซ็อกเก็ต TCP พื้นฐาน ส่วนใหญ่หากไม่ใช่ทั้งหมดลูกค้า RabbitMQ จะทำสิ่งนี้ ในเรื่องนั้นพวกเขามักจะปลอดภัยเธรด
  • ความสัมพันธ์ค่อนข้าง "แพง" ในการสร้าง (เนื่องจากการจับมือกัน) แต่การพูดจริงแล้วสิ่งนี้ไม่สำคัญ กระบวนการส่วนใหญ่จะต้องใช้วัตถุการเชื่อมต่อเดียวเท่านั้น แต่คุณสามารถรักษาการเชื่อมต่อในพูลหากคุณพบว่าคุณต้องการปริมาณงานมากกว่าเธรด / ซ็อกเก็ตเดียวที่สามารถให้ได้ (ไม่น่าจะเกิดขึ้นกับเทคโนโลยีการคำนวณปัจจุบัน)

ข้อเท็จจริงช่องทาง

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

  • เนื่องจากเป็นส่วนหนึ่งของตรรกะของแอปพลิเคชันแต่ละช่องมักจะมีอยู่ในเธรดของตัวเอง
  • โดยทั่วไปช่องทั้งหมดที่แอปของคุณเปิดจะแชร์การเชื่อมต่อเดียว (เป็นเซสชันที่มีน้ำหนักเบาซึ่งทำงานบนการเชื่อมต่อ) การเชื่อมต่อเป็น thread-safe ดังนั้นจึงเป็นสิ่งที่ตกลง
  • การดำเนินการ AMQP ส่วนใหญ่เกิดขึ้นผ่านช่องทาง
  • จากมุมมองของชั้น OSI ช่องอาจจะรอบชั้น 7
  • ช่องถูกออกแบบมาให้ชั่วคราว ; ส่วนหนึ่งของการออกแบบของ AMQP คือโดยทั่วไปแล้วช่องทางจะปิดเพื่อตอบสนองต่อข้อผิดพลาด (เช่นการประกาศคิวอีกครั้งด้วยพารามิเตอร์ที่แตกต่างกันก่อนที่จะลบคิวที่มีอยู่)
  • เนื่องจากแอพพลิเคชั่นนั้นไม่ได้รวมแอพของคุณไว้
  • เซิร์ฟเวอร์ใช้จำนวนเต็มเพื่อระบุช่อง เมื่อเธรดที่จัดการการเชื่อมต่อได้รับแพ็คเก็ตสำหรับช่องสัญญาณใดช่องหนึ่งจะใช้หมายเลขนี้เพื่อบอกนายหน้าว่าช่องทางใด / เซสชันที่แพ็คเก็ตเป็นของ
  • โดยทั่วไปแชแนลจะไม่ปลอดภัยสำหรับเธรดเนื่องจากจะไม่มีความหมายในการแบ่งปันระหว่างเธรด หากคุณมีเธรดอื่นที่จำเป็นต้องใช้นายหน้าคุณจำเป็นต้องมีช่องทางใหม่

ข้อมูลผู้บริโภค

Consumer คือวัตถุที่กำหนดโดยโปรโตคอล AMQP ไม่ใช่ช่องหรือการเชื่อมต่อแทนที่จะเป็นสิ่งที่แอปพลิเคชันของคุณใช้เป็น "กล่องจดหมาย" หลายประเภทเพื่อวางข้อความ

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

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


1
"ช่องทางไม่ควรรวมตัวกัน" นั่นคือสิ่งที่ฉันกำลังมองหา
ospider

"เนื่องจากแอพพลิเคชั่นเหล่านี้ไม่ได้ใช้งานแอปของคุณจึงไม่ควรรวมช่อง - คุณช่วยอธิบายได้ไหมว่าคุณมาถึงข้อสรุปนี้ได้อย่างไร เอกสารแนะนำให้ใช้การรวมช่องสัญญาณหากการใช้งาน "หนึ่งช่องสัญญาณต่อเธรด" ใช้ทรัพยากรมากเกินไปดูที่นี่: rabbitmq.com/channels.html#resource-usage
ymas

@ymas - เอกสารที่คุณอ้างถึงเป็นการเก็งกำไรและในความคิดของฉันคำแนะนำที่ไม่ดี ฉันกำลังอ่านซอร์สโค้ดและข้อมูลจำเพาะโปรโตคอล แชแนลจะไม่ถูกรวมกันเป็นช่วงเวลา นอกจากนี้หนึ่งช่องสัญญาณต่อเธรดเป็นแนวทางที่ยึดตามหลักการเดียวกันนี้ หากคุณพบว่าคุณมีช่องทางเปิดมากมายที่เซิร์ฟเวอร์ จำกัด ทรัพยากรคุณต้องประเมินสถาปัตยกรรมของคุณใหม่ (เช่นเปลี่ยนเป็นรูปแบบความพร้อมใช้งานสูงและ / หรือลดการทำงานพร้อมกัน)
theMayer

21

ฉันพบบทความนี้ซึ่งอธิบายทุกด้านของโมเดล AMQP ซึ่งช่องเป็นหนึ่ง ฉันพบว่ามันมีประโยชน์มากในการทำความเข้าใจ

https://www.rabbitmq.com/tutorials/amqp-concepts.html

บางแอพพลิเคชั่นต้องการการเชื่อมต่อหลายจุดกับนายหน้า AMQP อย่างไรก็ตามมันไม่เป็นที่พึงปรารถนาที่จะเปิดการเชื่อมต่อ TCP จำนวนมากในเวลาเดียวกันเนื่องจากการทำเช่นนั้นจะใช้ทรัพยากรของระบบและทำให้การกำหนดค่าไฟร์วอลล์ทำได้ยากขึ้น การเชื่อมต่อ AMQP 0-9-1 มีมัลติเพล็กซ์พร้อมช่องสัญญาณที่ถือได้ว่าเป็น "การเชื่อมต่อแบบ Lightweight ที่ใช้การเชื่อมต่อ TCP เดียว"

สำหรับแอปพลิเคชันที่ใช้หลายเธรด / กระบวนการสำหรับการประมวลผลเป็นเรื่องธรรมดามากที่จะเปิดช่องทางใหม่ต่อเธรด / กระบวนการและไม่แชร์ช่องระหว่างกัน

การสื่อสารในช่องทางเฉพาะนั้นแยกจากการสื่อสารในช่องทางอื่นอย่างสิ้นเชิงดังนั้นทุกวิธี AMQP จึงมีหมายเลขช่องสัญญาณที่ลูกค้าใช้เพื่อหาช่องทางที่วิธีการนั้นใช้ (และดังนั้นจึงต้องเรียกใช้ตัวจัดการเหตุการณ์ใด) .


4

มีความสัมพันธ์ระหว่างเช่นการเชื่อมต่อ TCP สามารถมีหลายช่องสัญญาณได้

แชนเนล : เป็นการเชื่อมต่อเสมือนจริงภายในการเชื่อมต่อ เมื่อเผยแพร่หรือบริโภคข้อความจากคิว - ทั้งหมดทำผ่านช่องทางขณะที่การเชื่อมต่อ : เป็นการเชื่อมต่อ TCP ระหว่างแอปพลิเคชันของคุณกับนายหน้า RabbitMQ

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.