เรามีสถานการณ์ที่ฉันต้องรับมือกับเหตุการณ์ที่ไหลเข้ามาในเซิร์ฟเวอร์ของเราโดยเฉลี่ยประมาณ 1,000 เหตุการณ์ต่อวินาทีโดยเฉลี่ย
ปัญหา
ระบบของเราโฮสต์บนHerokuและใช้Heroku Postgres DBที่ค่อนข้างแพงซึ่งอนุญาตการเชื่อมต่อ DB ได้สูงสุด 500 เราใช้การเชื่อมต่อร่วมกันเพื่อเชื่อมต่อจากเซิร์ฟเวอร์ไปยังฐานข้อมูล
เหตุการณ์เข้ามาเร็วกว่าการเชื่อมต่อฐานข้อมูลที่สามารถจัดการได้
ปัญหาที่เรามีคือเหตุการณ์เกิดขึ้นเร็วกว่าพูลการเชื่อมต่อที่สามารถจัดการได้ เมื่อถึงเวลาที่การเชื่อมต่อหนึ่งเสร็จสิ้นการส่งสัญญาณเครือข่ายจากเซิร์ฟเวอร์ไปยังฐานข้อมูลดังนั้นจึงสามารถปล่อยกลับไปที่กลุ่มได้มากกว่าn
มีเหตุการณ์เพิ่มเติมเข้ามา
ในที่สุดเหตุการณ์ต่างๆก็หมดลงรอรับการบันทึกและเนื่องจากไม่มีการเชื่อมต่อที่พร้อมใช้งานในกลุ่มจึงหมดเวลาและระบบทั้งหมดไม่สามารถใช้งานได้
เราได้แก้ไขเหตุฉุกเฉินด้วยการปล่อยเหตุการณ์ความถี่สูงที่ก้าวร้าวช้าลงจากลูกค้า แต่เรายังต้องการทราบวิธีจัดการสถานการณ์นี้ในเหตุการณ์ที่เราต้องจัดการกับเหตุการณ์ความถี่สูงนั้น
ข้อ จำกัด
ลูกค้ารายอื่นอาจต้องการอ่านเหตุการณ์พร้อมกัน
ไคลเอนต์อื่น ๆ ร้องขออย่างต่อเนื่องเพื่ออ่านเหตุการณ์ทั้งหมดที่มีคีย์เฉพาะแม้ว่าพวกเขาจะยังไม่ได้บันทึกในฐานข้อมูล
ไคลเอนต์สามารถสอบถามGET api/v1/events?clientId=1
และรับเหตุการณ์ทั้งหมดที่ส่งโดยไคลเอนต์ 1 แม้ว่าเหตุการณ์เหล่านั้นจะยังไม่ได้ทำการบันทึกในฐานข้อมูล
มีตัวอย่าง "ห้องเรียน" เกี่ยวกับวิธีจัดการกับเรื่องนี้หรือไม่?
การแก้ปัญหาที่เป็นไปได้
จัดคิวเหตุการณ์บนเซิร์ฟเวอร์ของเรา
เราสามารถจัดคิวเหตุการณ์บนเซิร์ฟเวอร์ (ด้วยคิวที่มีการเกิดพร้อมกันสูงสุด 400 เพื่อให้กลุ่มการเชื่อมต่อไม่หมด)
นี่เป็นความคิดที่ไม่ดีเพราะ:
- มันจะกินหน่วยความจำเซิร์ฟเวอร์ที่มีอยู่ เหตุการณ์ที่จัดคิวเข้าด้วยกันจะใช้ RAM จำนวนมาก
- เซิร์ฟเวอร์ของเราเริ่มต้นใหม่ครั้งเดียวทุก 24 ชั่วโมง นี่เป็นข้อ จำกัด อย่างหนักจาก Heroku เซิร์ฟเวอร์สามารถรีสตาร์ทในขณะที่เหตุการณ์ถูกจัดคิวทำให้เราสูญเสียเหตุการณ์ที่จัดคิว
- มันแนะนำสถานะบนเซิร์ฟเวอร์จึงทำร้ายความยืดหยุ่น หากเรามีการตั้งค่าเซิร์ฟเวอร์หลายเครื่องและลูกค้าต้องการอ่านเหตุการณ์ที่จัดคิว + ที่บันทึกไว้ทั้งหมดเราจะไม่ทราบว่าเซิร์ฟเวอร์ใดที่มีเหตุการณ์ที่จัดคิวอยู่
ใช้คิวข้อความแยกต่างหาก
ฉันคิดว่าเราสามารถใช้คิวข้อความ (เช่นRabbitMQ ?) ที่เราปั๊มข้อความไว้และที่อื่นมีเซิร์ฟเวอร์อื่นที่เกี่ยวข้องกับการบันทึกเหตุการณ์บนฐานข้อมูลเท่านั้น
ฉันไม่แน่ใจว่าคิวข้อความอนุญาตให้สอบถามเหตุการณ์ที่เข้าคิว (ยังไม่ได้บันทึก) ดังนั้นหากไคลเอ็นต์อื่นต้องการอ่านข้อความของไคลเอ็นต์อื่นฉันสามารถรับข้อความที่บันทึกจากฐานข้อมูลและข้อความที่รอดำเนินการจากคิว และต่อกันเข้าด้วยกันเพื่อให้ฉันสามารถส่งพวกเขากลับไปยังไคลเอนต์คำขออ่าน
ใช้หลายฐานข้อมูลแต่ละส่วนบันทึกข้อความด้วยเซิร์ฟเวอร์ประสานงานฐานข้อมูลส่วนกลางเพื่อจัดการพวกเขา
วิธีแก้ปัญหาอื่นที่เราใช้คือการใช้ฐานข้อมูลหลายตัวโดยมี "DB ผู้ประสานงาน / โหลดบาลานเซอร์" ส่วนกลาง เมื่อได้รับเหตุการณ์ผู้ประสานงานนี้จะเลือกหนึ่งในฐานข้อมูลเพื่อเขียนข้อความ สิ่งนี้จะช่วยให้เราสามารถใช้ฐานข้อมูล Heroku หลายฐานจึงเพิ่มขีด จำกัด การเชื่อมต่อกับฐานข้อมูล 500 x จำนวน
เมื่ออ่านแบบสอบถามผู้ประสานงานนี้สามารถออกSELECT
แบบสอบถามไปยังแต่ละฐานข้อมูลรวมผลลัพธ์ทั้งหมดและส่งกลับไปยังไคลเอนต์ที่ร้องขอการอ่าน
นี่เป็นความคิดที่ไม่ดีเพราะ:
- ความคิดนี้ดูเหมือนจะ ... อะแฮ่ม. จะเป็นฝันร้ายในการจัดการเช่นกัน (สำรองข้อมูล ฯลฯ ) มันมีความซับซ้อนในการสร้างและบำรุงรักษาและหากจำเป็นอย่างยิ่งมันฟังดูเหมือนเป็นการละเมิดKISS
- มันเสียสละความสอดคล้อง การทำธุรกรรมข้ามฐานข้อมูลหลายรายการนั้นไม่ต้องดำเนินการหากเราไปพร้อมกับแนวคิดนี้
ANALYZE
คำสั่งด้วยตนเองและพวกเขาก็ไม่เป็นปัญหา ฉันได้สร้างต้นแบบเพื่อทดสอบสมมติฐานกลุ่มการเชื่อมต่อและตรวจสอบว่านี่เป็นปัญหา ฐานข้อมูลและเซิร์ฟเวอร์อยู่ในเครื่องที่แตกต่างกันดังนั้นเวลาแฝง นอกจากนี้เราไม่ต้องการให้ Heroku ยกเว้นกรณีที่จำเป็นอย่างแท้จริงไม่ต้องกังวลเกี่ยวกับการปรับใช้เป็นประโยชน์อย่างมากสำหรับเรา
select null
กับคนรู้จัก 500 คน ฉันเดิมพันคุณจะพบว่ากลุ่มการเชื่อมต่อนั้นไม่ใช่ปัญหา