RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์

ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงเป็นหัวข้อใหญ่ ดังนั้นเราจะอุทิศบทความแยกต่างหากให้กับ RabbitMQ และ Kafka บทความนี้เกี่ยวกับ RabbitMQ และบทความถัดไปเกี่ยวกับ Kafka เมื่อเปรียบเทียบกับ RabbitMQ นี่เป็นบทความยาว ดังนั้นทำใจให้สบาย

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

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

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

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

ดั้งเดิมความยืดหยุ่นของโหนดเดียว

การเข้าคิว/การกำหนดเส้นทางที่ยืดหยุ่น

คิวใน RabbitMQ มีสองประเภท: คงทนและไม่คงทน คิวทั้งหมดจะถูกบันทึกไว้ในฐานข้อมูล Mnesia คิวที่คงทนได้รับการโฆษณาอีกครั้งเมื่อเริ่มต้นโหนด และทำให้สามารถรีสตาร์ท ระบบล่ม หรือเซิร์ฟเวอร์ล่มได้ (ตราบใดที่ข้อมูลยังคงอยู่) ซึ่งหมายความว่าตราบใดที่คุณประกาศการกำหนดเส้นทาง (การแลกเปลี่ยน) และคิวให้มีความยืดหยุ่น โครงสร้างพื้นฐานการจัดคิว/การกำหนดเส้นทางจะกลับมาออนไลน์อีกครั้ง

คิวและการกำหนดเส้นทางที่ผันผวนจะถูกลบออกเมื่อรีสตาร์ทโหนด

ข้อความถาวร

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 1. เมทริกซ์ความยั่งยืน

การทำคลัสเตอร์ด้วยการมิเรอร์คิว

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

การมิเรอร์คิว:

  • หนึ่งคิวหลัก (มาสเตอร์) ซึ่งรับคำสั่งเขียนและอ่านทั้งหมด
  • มิเรอร์อย่างน้อยหนึ่งรายการที่ได้รับข้อความและข้อมูลเมตาทั้งหมดจากคิวหลัก กระจกเหล่านี้ไม่ได้มีไว้สำหรับปรับขนาด แต่มีไว้เพื่อความซ้ำซ้อนเท่านั้น

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 2. การมิเรอร์คิว

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

  • ha-mode: all
  • ha-mode: exactly, ha-params: 2 (หนึ่งนายและหนึ่งกระจก)
  • ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2

การยืนยันสำนักพิมพ์

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

คิวเฟลโอเวอร์

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 3. คิวที่มิเรอร์หลายรายการและนโยบาย

นายหน้า 3 ลงไป โปรดทราบว่ากระจก Queue C บนโบรกเกอร์ 2 กำลังได้รับการเลื่อนระดับเป็นผู้เชี่ยวชาญ โปรดทราบว่ามีการสร้างมิเรอร์ใหม่สำหรับ Queue C บน Broker 1 RabbitMQ จะพยายามรักษาปัจจัยการจำลองแบบที่ระบุไว้ในนโยบายของคุณเสมอ

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 4. นายหน้า 3 ล้มเหลว ทำให้คิว C ล้มเหลว

โบรคเกอร์ตัวต่อไป 1 ตก! เราเหลือนายหน้าเพียงคนเดียวเท่านั้น กระจก Queue B ได้รับการเลื่อนขั้นเป็น Master

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
มะเดื่อ 5

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

ในกรณีนี้ การสูญเสียโบรคเกอร์ 1 เสร็จสมบูรณ์ เช่นเดียวกับข้อมูล ดังนั้นคิว B ที่ไม่มีการมิเรอร์จึงสูญหายไปโดยสิ้นเชิง

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 6. นายหน้า 1 กลับมาให้บริการแล้ว

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 7. นายหน้า 3 กลับมาให้บริการแล้ว คิวหลักทั้งหมดในโหนดเดียว!

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

การประสาน

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

การซิงโครไนซ์นี้ดำเนินการโดยอัตโนมัติหรือด้วยตนเอง และจัดการโดยใช้นโยบายคิว ลองดูตัวอย่าง

เรามีคิวมิเรอร์สองคิว คิว A ซิงโครไนซ์โดยอัตโนมัติ และคิว B ซิงโครไนซ์ด้วยตนเอง ทั้งสองคิวมีข้อความสิบข้อความ

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 8. สองคิวพร้อมโหมดการซิงโครไนซ์ที่แตกต่างกัน

ตอนนี้เรากำลังสูญเสียนายหน้า 3

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 9.นายหน้า3ล้ม

นายหน้า 3 กลับมาให้บริการแล้ว คลัสเตอร์จะสร้างมิเรอร์สำหรับแต่ละคิวบนโหนดใหม่และซิงโครไนซ์คิว A ใหม่กับต้นแบบโดยอัตโนมัติ อย่างไรก็ตาม กระจกเงาของคิว B ใหม่ยังคงว่างเปล่า วิธีนี้ทำให้เรามีความซ้ำซ้อนเต็มรูปแบบในคิว A และมีมิเรอร์เพียงตัวเดียวสำหรับข้อความคิว B ที่มีอยู่

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 10. มิเรอร์ใหม่ของคิว A ได้รับข้อความที่มีอยู่ทั้งหมด แต่มิเรอร์ใหม่ของคิว B ไม่รับ

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 11. คิว A ย้อนกลับไปที่โบรกเกอร์ 1 โดยไม่สูญเสียข้อความ

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

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 12. คิว A ถูกย้อนกลับไปที่โบรกเกอร์ 3 โดยไม่สูญเสียข้อความ คิว B ย้อนกลับไปที่โบรคเกอร์ 3 โดยที่ข้อความหายไปสิบข้อความ

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 13. คิว B ยังคงไม่สามารถใช้งานได้หลังจากแพ้โบรคเกอร์ 1

คุณอาจถามว่า “อย่าใช้การซิงโครไนซ์อัตโนมัติจะดีกว่าไหม?” คำตอบก็คือการซิงโครไนซ์เป็นการดำเนินการบล็อก ในระหว่างการซิงโครไนซ์ คิวหลักไม่สามารถดำเนินการอ่านหรือเขียนใดๆ ได้!

ลองดูตัวอย่าง ตอนนี้คิวยาวมาก พวกมันจะโตขนาดนี้ได้ยังไง? ด้วยเหตุผลหลายประการ:

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 14. สองคิวขนาดใหญ่ที่มีโหมดการซิงโครไนซ์ต่างกัน

ตอนนี้นายหน้า 3 ตก

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 15. นายหน้า 3 ล้ม เหลือหนึ่งมาสเตอร์และมิเรอร์ในแต่ละคิว

นายหน้า 3 กลับมาออนไลน์อีกครั้งและมีการสร้างมิเรอร์ใหม่ คิวหลัก A เริ่มการจำลองข้อความที่มีอยู่ไปยังมิเรอร์ใหม่และในช่วงเวลานี้คิวไม่พร้อมใช้งาน การจำลองข้อมูลใช้เวลาสองชั่วโมง ส่งผลให้คิวนี้หยุดทำงานสองชั่วโมง!

อย่างไรก็ตาม คิว B ยังคงใช้ได้ตลอดระยะเวลาทั้งหมด เธอเสียสละความซ้ำซ้อนเพื่อการเข้าถึง

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 16. คิวยังคงไม่พร้อมใช้งานในระหว่างการซิงโครไนซ์

หลังจากผ่านไปสองชั่วโมง คิว A ก็จะพร้อมใช้งานและสามารถเริ่มรับการอ่านและเขียนได้อีกครั้ง

การปรับปรุง

ลักษณะการบล็อกนี้ในระหว่างการซิงโครไนซ์ทำให้การอัปเดตคลัสเตอร์ที่มีคิวขนาดใหญ่มากทำได้ยาก ในบางจุด จำเป็นต้องรีสตาร์ทโหนดหลัก ซึ่งหมายความว่าสลับไปใช้มิเรอร์หรือปิดใช้งานคิวในขณะที่เซิร์ฟเวอร์กำลังอัปเกรด หากเราเลือกที่จะเปลี่ยนผ่าน เราจะสูญเสียข้อความหากมิเรอร์ไม่ซิงโครไนซ์ ตามค่าเริ่มต้น ในระหว่างที่นายหน้าหยุดทำงาน จะไม่มีดำเนินการล้มเหลวไปยังมิเรอร์ที่ไม่ซิงโครไนซ์ ซึ่งหมายความว่าทันทีที่นายหน้ากลับมา เราจะไม่สูญเสียข้อความใด ๆ ความเสียหายเพียงอย่างเดียวคือการรอคิวแบบธรรมดา กฎการปฏิบัติเมื่อนายหน้าถูกตัดการเชื่อมต่อถูกกำหนดโดยนโยบาย ha-promote-on-shutdown. คุณสามารถตั้งค่าค่าใดค่าหนึ่งจากสองค่าได้:

  • always= เปิดใช้งานการเปลี่ยนไปใช้มิเรอร์ที่ไม่ซิงโครไนซ์
  • when-synced= เปลี่ยนเป็นมิเรอร์ที่ซิงโครไนซ์เท่านั้น ไม่เช่นนั้นคิวจะไม่สามารถอ่านและเขียนไม่ได้ คิวจะกลับมาให้บริการทันทีที่นายหน้ากลับมา

ไม่ทางใดก็ทางหนึ่ง เนื่องจากคิวจำนวนมาก คุณต้องเลือกระหว่างข้อมูลสูญหายหรือข้อมูลไม่พร้อมใช้งาน

เมื่อความพร้อมใช้งานปรับปรุงความปลอดภัยของข้อมูล

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

ที่นี่คุณต้องพิจารณาสิ่งต่อไปนี้:

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

หากผู้เผยแพร่สามารถละทิ้งข้อความได้ ที่จริงแล้ว การปรับปรุงการเข้าถึงยังช่วยปรับปรุงความปลอดภัยของข้อมูลด้วย

ดังนั้นจึงต้องหาจุดสมดุล และวิธีแก้ปัญหาจะขึ้นอยู่กับสถานการณ์เฉพาะ

ปัญหาเกี่ยวกับ ha-promote-on-failure=เมื่อซิงค์

ความคิด ฮา-เลื่อนขั้นเมื่อล้มเหลว= เมื่อซิงค์ คือเราป้องกันการสลับไปใช้มิเรอร์ที่ไม่ซิงโครไนซ์และหลีกเลี่ยงการสูญเสียข้อมูล คิวยังคงไม่สามารถอ่านหรือเขียนได้ แต่เราพยายามกู้คืนโบรกเกอร์ที่เสียหายโดยมีข้อมูลครบถ้วน เพื่อให้สามารถกลับมาทำงานต่อในฐานะต้นแบบได้โดยไม่สูญเสียข้อมูล

แต่ (และนี่เป็นเรื่องใหญ่) หากนายหน้าสูญเสียข้อมูลของเขา เราก็จะมีปัญหาใหญ่: คิวหายไป! ข้อมูลหายหมด! แม้ว่าคุณจะมีกระจกที่ตามคิวหลักเป็นส่วนใหญ่ กระจกเหล่านั้นก็จะถูกทิ้งเช่นกัน

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

ดังนั้นการซิงโครไนซ์ด้วยตนเอง (และความล้มเหลวในการซิงโครไนซ์) ร่วมกับ ha-promote-on-failure=when-syncedในความคิดของฉันค่อนข้างเสี่ยง เอกสารบอกว่าตัวเลือกนี้มีอยู่สำหรับความปลอดภัยของข้อมูล แต่เป็นมีดสองคม

การปรับสมดุลต้นแบบ

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

การปรับสมดุลต้นแบบอาจเป็นปัญหาได้ด้วยเหตุผลสองประการ:

  • ไม่มีเครื่องมือที่ดีในการปรับสมดุลใหม่
  • การซิงโครไนซ์คิว

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

มีเคล็ดลับอีกประการหนึ่งในการย้ายคิวหลักผ่านนโยบาย HA คู่มือกล่าวถึง สคริปต์ สำหรับสิ่งนี้. มันทำงานเช่นนี้:

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

ข้อเสียคือวิธีการนี้อาจใช้ไม่ได้หากคุณมีคิวจำนวนมากหรือมีข้อกำหนดด้านความซ้ำซ้อนที่เข้มงวด

ตอนนี้เรามาดูกันว่าคลัสเตอร์ RabbitMQ ทำงานอย่างไรกับพาร์ติชันเครือข่าย

สูญเสียการเชื่อมต่อ

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

ด้วย RabbitMQ เรามีสองตัวเลือกหลัก:

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

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 17. คิวหลักและมิเรอร์สองตัว แต่ละอันอยู่บนโหนดแยกกัน จากนั้นเครือข่ายก็ขัดข้องและมิเรอร์หนึ่งตัวก็หลุดออก โหนดที่แยกออกจากกันจะเห็นว่าอีกสองโหนดหลุดออกไปและเลื่อนกระจกของมันไปที่ต้นแบบ ตอนนี้เรามีคิวหลักสองคิว ทั้งแบบเขียนและอ่านได้

หากผู้เผยแพร่ส่งข้อมูลไปยังต้นแบบทั้งสอง เราจะได้สำเนาคิวที่แตกต่างกันสองชุด

โหมดต่างๆ ของ RabbitMQ มีทั้งความพร้อมใช้งานหรือความสม่ำเสมอ

โหมดละเว้น (ค่าเริ่มต้น)

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 18. ผู้จัดพิมพ์สามรายมีความเกี่ยวข้องกับนายหน้าสามราย ภายใน คลัสเตอร์จะกำหนดเส้นทางคำขอทั้งหมดไปยังคิวหลักบนโบรกเกอร์ 2

ตอนนี้เรากำลังสูญเสียนายหน้า 3 ไป เขาเห็นว่านายหน้ารายอื่นล้มลงและเลื่อนตำแหน่งกระจกของเขาให้ปรมาจารย์ นี่คือวิธีที่การแยกทางตรรกะเกิดขึ้น

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 19. การแบ่งตรรกะ (สมองแยก) บันทึกจะแบ่งออกเป็นสองคิวหลัก และทั้งสองสำเนาจะแยกออกจากกัน

การเชื่อมต่อกลับคืนมา แต่การแยกทางตรรกะยังคงอยู่ ผู้ดูแลระบบจะต้องเลือกฝ่ายแพ้ด้วยตนเอง ในกรณีด้านล่าง ผู้ดูแลระบบจะรีบูตโบรกเกอร์ 3 ข้อความทั้งหมดที่เขาไม่ได้จัดการเพื่อส่งจะสูญหาย

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 20. ผู้ดูแลระบบปิดการใช้งานโบรกเกอร์ 3

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 21. ผู้ดูแลระบบเริ่มการทำงานของ Broker 3 และเข้าร่วมคลัสเตอร์ โดยสูญเสียข้อความทั้งหมดที่เหลืออยู่ที่นั่น

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

โหมดการรักษาอัตโนมัติ

ทำงานคล้ายกับโหมด Ignore ยกเว้นว่าคลัสเตอร์จะเลือกฝั่งที่เสียโดยอัตโนมัติหลังจากแยกและกู้คืนการเชื่อมต่อ ฝั่งที่แพ้จะกลับไปยังคลัสเตอร์ที่ว่างเปล่า และคิวจะสูญเสียข้อความทั้งหมดที่ส่งไปยังฝั่งนั้นเท่านั้น

หยุดโหมดชนกลุ่มน้อยชั่วคราว

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 22. ผู้จัดพิมพ์สามรายมีความเกี่ยวข้องกับนายหน้าสามราย ภายใน คลัสเตอร์จะกำหนดเส้นทางคำขอทั้งหมดไปยังคิวหลักบนโบรกเกอร์ 2

จากนั้นโบรกเกอร์ 1 และ 2 แยกจากโบรกเกอร์ 3 แทนที่จะเลื่อนขั้นมิเรอร์เป็นมาสเตอร์ โบรกเกอร์ 3 จะระงับและไม่สามารถใช้งานได้

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 23. โบรกเกอร์ 3 หยุดชั่วคราว ยกเลิกการเชื่อมต่อไคลเอนต์ทั้งหมด และปฏิเสธคำขอการเชื่อมต่อ

เมื่อการเชื่อมต่อกลับคืนมา การเชื่อมต่อจะกลับสู่คลัสเตอร์

ลองดูอีกตัวอย่างหนึ่งที่คิวหลักอยู่ที่โบรกเกอร์ 3

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 24. คิวหลักบนโบรกเกอร์ 3.

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

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 25. เปลี่ยนไปใช้โบรคเกอร์ 2 หากโบรคเกอร์ 3 ไม่พร้อมใช้งาน

เมื่อการเชื่อมต่อกลับคืนมา โบรคเกอร์ 3 จะเข้าร่วมคลัสเตอร์

RabbitMQ กับ Kafka: ความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูงในคลัสเตอร์
ข้าว. 26. คลัสเตอร์กลับสู่การทำงานตามปกติแล้ว

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

เพื่อให้แน่ใจว่ามีความพร้อมใช้งาน สิ่งสำคัญคือต้องแน่ใจว่าไคลเอ็นต์เชื่อมต่อกับโฮสต์ได้สำเร็จ ลองดูตัวเลือกของเรา

สร้างความมั่นใจในการเชื่อมต่อของลูกค้า

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

ตัวเลือกของเรา:

  • เข้าถึงคลัสเตอร์ได้โดยใช้โหลดบาลานเซอร์ที่วนรอบโหนดและไคลเอ็นต์ลองเชื่อมต่ออีกครั้งจนกว่าจะสำเร็จ หากโหนดหยุดทำงานหรือถูกระงับ ความพยายามในการเชื่อมต่อกับโหนดนั้นจะล้มเหลว แต่ความพยายามครั้งต่อๆ ไปจะไปที่เซิร์ฟเวอร์อื่น (ในลักษณะ Round-robin) เหมาะสำหรับการสูญเสียการเชื่อมต่อในระยะสั้นหรือเซิร์ฟเวอร์ที่ล่มซึ่งจะถูกสำรองอย่างรวดเร็ว
  • เข้าถึงคลัสเตอร์ผ่านตัวจัดสรรภาระงาน และลบโหนดที่ถูกระงับ/ล้มเหลวออกจากรายการทันทีที่ตรวจพบ หากเราทำสิ่งนี้อย่างรวดเร็ว และหากลูกค้าสามารถลองเชื่อมต่ออีกครั้งได้ เราก็จะมีความพร้อมใช้งานคงที่
  • มอบรายการโหนดทั้งหมดให้กับลูกค้าแต่ละราย และไคลเอนต์จะสุ่มเลือกหนึ่งโหนดเมื่อทำการเชื่อมต่อ หากได้รับข้อผิดพลาดขณะพยายามเชื่อมต่อ ระบบจะย้ายไปยังโหนดถัดไปในรายการจนกว่าจะเชื่อมต่อ
  • ลบการรับส่งข้อมูลออกจากโหนดที่ล้มเหลว/ถูกระงับโดยใช้ DNS ทำได้โดยใช้ TTL ขนาดเล็ก

ผลการวิจัย

การทำคลัสเตอร์ RabbitMQ มีข้อดีและข้อเสีย ข้อเสียที่ร้ายแรงที่สุดคือ:

  • เมื่อเข้าร่วมคลัสเตอร์ โหนดจะละทิ้งข้อมูล
  • การบล็อกการซิงโครไนซ์ทำให้คิวไม่พร้อมใช้งาน

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

  • เครือข่ายที่ไม่น่าเชื่อถือ
  • การจัดเก็บที่ไม่น่าเชื่อถือ
  • คิวยาวมาก

เมื่อพูดถึงการตั้งค่าความพร้อมใช้งานสูง ให้พิจารณาสิ่งต่อไปนี้:

  • ha-promote-on-failure=always
  • ha-sync-mode=manual
  • cluster_partition_handling=ignore (หรือ autoheal)
  • ข้อความถาวร
  • ตรวจสอบให้แน่ใจว่าไคลเอนต์เชื่อมต่อกับโหนดที่ใช้งานอยู่เมื่อบางโหนดล้มเหลว

เพื่อความสอดคล้อง (ความปลอดภัยของข้อมูล) ให้พิจารณาการตั้งค่าต่อไปนี้:

  • ผู้จัดพิมพ์ยืนยันและการรับทราบด้วยตนเองในด้านผู้บริโภค
  • ha-promote-on-failure=when-syncedหากผู้เผยแพร่สามารถลองอีกครั้งในภายหลังและหากคุณมีพื้นที่เก็บข้อมูลที่เชื่อถือได้มาก! อย่างอื่นใส่ =always.
  • ha-sync-mode=automatic (แต่สำหรับคิวที่ไม่ได้ใช้งานขนาดใหญ่อาจจำเป็นต้องใช้โหมดแมนนวล นอกจากนี้ ให้พิจารณาว่าการไม่พร้อมใช้งานจะทำให้ข้อความสูญหายหรือไม่)
  • หยุดโหมดชนกลุ่มน้อยชั่วคราว
  • ข้อความถาวร

เรายังไม่ได้ครอบคลุมประเด็นทั้งหมดเกี่ยวกับความทนทานต่อข้อผิดพลาดและความพร้อมใช้งานสูง ตัวอย่างเช่น วิธีดำเนินการตามขั้นตอนการดูแลระบบอย่างปลอดภัย (เช่น การอัปเดตแบบต่อเนื่อง) เรายังต้องพูดคุยเกี่ยวกับสหพันธรัฐและปลั๊กอิน Shovel

หากฉันพลาดสิ่งอื่นใดโปรดแจ้งให้เราทราบ

ดูของฉันด้วย เสาโดยที่ฉันทำความเสียหายกับคลัสเตอร์ RabbitMQ โดยใช้ Docker และ Blockade เพื่อทดสอบสถานการณ์การสูญเสียข้อความบางส่วนที่อธิบายไว้ในบทความนี้

บทความก่อนหน้าในชุด:
หมายเลข 1 - habr.com/ru/company/itsumma/blog/416629
หมายเลข 2 - habr.com/ru/company/itsumma/blog/418389
หมายเลข 3 - habr.com/ru/company/itsumma/blog/437446

ที่มา: will.com

เพิ่มความคิดเห็น