- เลิกใช้ RabbitMQ และเปลี่ยนมาใช้คิวบน PostgresDB ที่อาศัย SQL
- ใช้เวลาเปลี่ยนประมาณครึ่งวัน และซอร์สโค้ดลดลง 580 บรรทัด
- ที่สำคัญกว่านั้นมากคือความเสถียรและความสามารถในการฟื้นตัว (Resiliency) ดีขึ้นอย่างมาก
- นี่ไม่ใช่การพูดถึงปัญหาของระบบคิวอย่าง RabbitMQ แต่เป็นส่วนหนึ่งของความพยายามในการทำให้ระบบเรียบง่ายขึ้น
- Prequel ผู้เขียนบทความนี้ เป็นผลิตภัณฑ์ที่ช่วยให้บริษัท B2B SaaS ซิงก์กับฐานข้อมูลของลูกค้าผ่าน data pipeline ขนาดใหญ่
- เดิมประกอบด้วย RabbitMQ + AQMP + Helm + GoLang wrapper ซึ่งช่วงหนึ่งทำงานได้ดี แต่หลังจากนั้นปัญหาก็เริ่มปรากฏ
- การส่งข้อความล่าช้านานเกินไปจนทำให้ข้อความถูกยกเลิก
- เมื่อ consumer ทำ prefetch ข้อความ จะเกิดสถานการณ์ที่ข้อความถัดไปถูกจองค้างไว้จนกว่าจะประมวลผลข้อความปัจจุบันเสร็จ
- หากตั้งค่า prefetch เป็น 0 จะกลายเป็นอนันต์ ทำให้ไม่สามารถปิดการทำงานของ prefetch ได้
- ปัญหานี้เกิดขึ้นเพราะงานที่รับข้อความไปประมวลผลมักเป็นงานระยะยาว (การส่งข้อมูล)
- แม้จะเข้าใจอย่างชัดเจนแล้วว่าเกิดอะไรขึ้น แต่ก็ไม่มีวิธีแก้ได้ทันที และเพราะปัญหานี้เกิดกับลูกค้าในโปรดักชันจึงไม่สามารถรอได้
- จึงเปลี่ยนมาใช้วิธีอ่านและเขียนผ่านตารางเดียวแบบเรียบง่ายใน Postgres
- ใช้ Row-Level Lock สำหรับการอ่าน/เขียน เพื่อรับประกันว่าจะมี consumer เพียงตัวเดียวที่อ่านงานนั้นได้
- เรียบง่ายจนแทบไม่น่าเชื่อ แต่ทำงานได้อย่างสมบูรณ์แบบ
- ข้อดีคือสถานะของแอปพลิเคชันไม่ถูกแยกออกเป็น RabbitMQ กับ Postgres อีกต่อไป แต่ถูกรวมอยู่ในที่เดียว
6 ความคิดเห็น
ผมเองก็เคยทำคิวขึ้นมาใช้โดยตรงด้วย
row level lockบน MySQL และมันก็ทำงานได้ดีในโปรดักชันมาหลายปีแล้วครับผมต้องการเพียงแค่สิ่งที่ให้ความสามารถคล้ายคิวกับ worker หลายตัวได้อย่างง่าย ๆ พร้อมกับเก็บ payload ที่มีสถานะรอ/กำลังดำเนินการ/ล้มเหลว (ถ้าเสร็จแล้วก็ลบ) ไว้ในคิวเดียวกันได้
จากในบทความที่เปลี่ยนจาก RabbitMQ ไปเป็นฐานข้อมูลได้ในเวลาสั้น ๆ ก็ดูเหมือนว่าน่าจะเป็นเพราะจริง ๆ แล้วไม่ได้จำเป็นต้องใช้ความอเนกประสงค์ ฟีเจอร์ที่หลากหลาย หรือความสามารถในการตั้งค่าต่าง ๆ ของบริการคิวเฉพาะทางแยกต่างหาก
ดูเหมือนว่าจะเกิดปัญหาจากการคลาดกันระหว่างการส่ง ACK แบบแมนนวลกับทรานแซกชันของ DB,
แต่ที่น่าสนใจคือเขาเลือกแก้ด้วยการถอด RabbitMQ ออก แทนที่จะเป็นการแก้เชิงวิศวกรรม
ทั้งที่ RabbitMQ เองก็คงไม่ได้ผิดอะไร...
https://news.ycombinator.com/item?id=35526846
มีความคิดเห็นกันเยอะมากในคอมเมนต์
มีของแบบนี้ที่ทำงานคล้ายกันอยู่เหมือนกันนะครับ https://github.com/pjongy/jasyncq
ดูเหมือนว่าจะมีโอกาสถูก
selectพร้อมกันได้ เลยอยากทราบว่าแก้ปัญหานั้นอย่างไรครับดูเหมือนว่าจะเขียนว่า row level lock นะครับ