สำหรับวันนี้เราจะมาทำความรู้จักกับ RabbitMQ ซอฟต์แวร์ที่เป็นตัวกลางรับส่งข้อความระหว่างแอปพลิเคชันต่างๆ เสมือนเป็นกระต่ายน้อย ผู้ไปรับรับข้อความจากผู้ส่ง (แอปพลิเคชันหนึ่ง) เก็บไว้รอการคัดแยก และส่งต่อให้ผู้รับ (แอปพลิเคชันอีกแอปพลิเคชันหนึ่ง) เหมาะสำหรับการทำแอปพลิเคชันที่ต้องมีการจัดคิวในการส่งข้อความ ระบบที่เป็นไมโครเซอร์วิสเอาไว้สื่อสารกันได้อย่างมีประสิทธิภาพ ทำให้สามารถแบ่งงานขนาดใหญ่เป็นงานย่อยๆ และส่งไปยังระบบอื่นๆ เพื่อประมวลผลได้นั่นเอง ในบทความนี้เราจะมาดูกันว่า “การเริ่มใช้งาน RabbitMQ สำหรับมือใหม่ ที่ใช้ Node.js อยู่จะมีวิธีการเริ่มต้นยังไงบ้าง?” มาดูกันเลย!
RabbitMQ คืออะไร?
จากที่เราได้รู้จัก RabbitMQ เบื้องต้นกันไปแล้วนะครับว่ามันเป็นตัวกลางที่จัดการกับข้อความทั้งภายในแอปพลิเคชันเดียวกัน และระหว่าแอปพลิเคชันหลาย ๆ ตัว โดย RabbitMQ ยังเป็น Open Source ที่รองรับโปรโตคอลการส่งข้อความได้หลายรูปแบบ แต่ที่นิยมจริง ๆ คือ AMQP (Advanced Message Queuing Protocol)
RabbitMQ ทำงานยังไง?
โดย concept การทำงานของ RabbitMQ จะมี Producers ที่เป็นส่วนที่สร้างและส่งข้อความไปยัง Queue โดยมีตัวกลางที่รับจาก Producers และคอยกำหนดว่าข้อความเหล่านี้จะส่งไปที่ Queue ไหน เราจะเรียกว่า “Exchange” โดยเมื่อข้อความไปถึง Queue แต่ละ Queue จะมี Consumers ดึงข้อความไปประมวลผลต่อ
การใช้งาน RabbitMQ
สำหรับการใช้งาน RabbitMQ เราจะต้องติดตั้ง RabbitMQ บนเซิร์ฟเวอร์ก่อน หรือถ้าใครไม่อยากมาติดตั้งให้ยุ่งยาก ก็สามารถใช้ RabbitMQ Cloud ที่มีผู้ให้บริการอย่าง CloudAMQP หรือ AWS MQ ที่เราสามารถใช้ RabbitMQ ผ่านหน้าเว็บหรือใช้ CLI ได้เลย แต่ในบทความนี้ผมจะพามาติดตั้งบนเครื่องผ่านท่าที่ใช้ Docker กัน
โดยเมื่อเครื่องเราติดตั้ง Docker และ Enable ให้ Docker ทำงานแล้วเราสามารถใช้คำสั่งด้านล่างนี้
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
สำหรับรัน Docker Container จาก RabbitMQ image เวอร์ชัน 3 ที่มาพร้อมกับระบบจัดการ (management) โดยจากคำสั่งด้านบนเราได้กำหนด Port ที่ Host จะเข้าถึงไว้ที่ 15672 ดังนั้นเราจะสามารถเข้าไปยังหน้าจัดการ RabbitMQ ได้ที่ http://localhost:15672 โดยหน้า Login ตัว username และ password เริ่มต้นจะเป็น “guest” ทั้งคู่
โดยในหน้า RabbitMQ Management เราสามารถจัดการและตรวจสอบ RabbitMQ ผ่านหน้าเว็บได้ โดยส่วนที่สำคัญบนนี้จะประกอบไปด้วย
Overview (ภาพรวม) จะเป็นส่วนที่แสดงสถานะและสถิติของ RabbitMQ เช่น จำนวนการเชื่อมต่อ, จำนวนคิว, จำนวน channel, และ message rate รวมไปถึงแสดงข้อมูลเกี่ยวกับการตั้งค่า cluster ของ RabbitMQ และ รายละเอียดของ node ต่างๆ
Connections (การเชื่อมต่อ) ส่วนนี้จะแสดงรายชื่อและรายละเอียดของการเชื่อมต่อทั้งหมด เช่น IP Address, Virtual Host, และสถานะการเชื่อมต่อ เราสามารถปิด connection ที่ไม่ต้องการได้จากหน้านี้
Channels (ช่องสื่อสาร) ส่วนที่แสดงรายชื่อ channel ทั้งหมดที่ถูกสร้างขึ้น เอาไว้ดูข้อมูลเกี่ยวกับ channel เช่น connection ที่ใช้, virtual host, และจำนวนข้อความที่ถูกส่งผ่าน channel นั้นๆ
Exchanges (ตัวแลกเปลี่ยน) เป็นส่วนที่แสดงรายการ exchanges ทั้งหมดในระบบ เราสามารถสร้าง, แก้ไข, หรือลบ exchanges ได้ อีกทั้งยังดูสถิติการใช้งาน exchanges เช่น จำนวนข้อความที่ถูกส่งมาและส่งออกจากหน้านี้ได้เลย
Queues (คิว) ส่วนที่เอาไว้ดูคิวทั้งหมดที่มีอยู่ สร้าง, แก้ไข, หรือลบคิวได้ และดูรายละเอียดสถิติของคิว เช่น จำนวนข้อความในคิว, จำนวนผู้บริโภค (consumers), และ message rate ได้
Admin (ผู้ดูแลระบบ) เป็นหน้าที่เราสามารถจัดการ User ใน RabbitMQ ได้ เช่น การสร้างผู้ใช้ใหม่, แก้ไขข้อมูลผู้ใช้, และกำหนดสิทธิ์การเข้าถึง จัดการ virtual hosts ที่ใช้ในการแยกการทำงานของระบบ RabbitMQ กำหนดสิทธิ์การเข้าถึงสำหรับผู้ใช้แต่ละคนในแต่ละ virtual host
ขั้นตอนการใช้งาน RabbitMQ กับ Node.js
ในการใช้ RabbitMQ กับ Node.js เราจะใช้ไลบรารี amqplib ซึ่งเป็นไลบรารีที่ใช้โปรโตคอล AMQP โดยเราจะใช้คำสั่ง npm install amqplib ในการติดตั้งลงในโปรเจกต์
mkdir rabbitmq-nodejs
cd rabbitmq-nodejs
npm init --y
npm install amqplib
เขียนโค้ดสำหรับส่วนส่งข้อความ (Producer) โดยการสร้างไฟล์ชื่อว่า send.js
var amqp = require('amqplib/callback_api');
// เชื่อมต่อกับ RabbitMQ server
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
// สร้าง channel
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
var msg = 'Hello World';
// ประกาศ queue
channel.assertQueue(queue, {
durable: false
});
// ส่งข้อความไปยัง queue
channel.sendToQueue(queue, Buffer.from(msg));
console.log(" [x] Sent %s", msg);
setTimeout(function() {
connection.close();
process.exit(0)
}, 500);
});
});
ต่อมาก็เป็นส่วนของ Consumer ที่ไปดึงข้อความมาจากคิวนั่นเอง โดยเราจะสร้างไฟล์ชื่อว่า receive.js ขึ้นมา
#!/usr/bin/env node
var amqp = require('amqplib/callback_api');
// เชื่อมต่อกับ RabbitMQ server
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
// สร้าง channel
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
// ประกาศ queue
channel.assertQueue(queue, {
durable: false
});
console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue);
// รอรับข้อความจาก queue
channel.consume(queue, function(msg) {
console.log(" [x] Received %s", msg.content.toString());
}, {
noAck: true
});
});
});
ต่อมาตอนที่รัน เราสามารถใช้คำสั่ง node send.js เพื่อรันโค้ดตัวส่งข้อความไป
แต่จะเห็นได้ว่าตัวอย่างผมรันไป 3 รอบ ส่งไป 3 ครั้งแต่ยังไม่ได้รันตัว Consumer มาดึงข้อความไป แสดงว่าข้อความนี้จะถูกเก็บอยู่ในคิวแน่ ๆ ว่าแล้วก็ไปดูที่คิวเลย
จะเห็นได้ว่ามีข้อความไปรออยู่ในคิวแล้วทั้ง 3 ข้อความ ทีนี้ก็เป็นหน้าที่ของ Consumer มาเอาไปใช้แล้ว เราก็ทำการรันด้วยคำสั่ง node receive.js ก็จะเห็นได้ว่าข้อความทั้งหมดถูกดึงออกมาจากคิวทั้งหมด
หากเรากลับไปดูที่ RabbitMQ แล้วก็จะเห็นว่าข้อความทั้งหมดถูกดึงออกไปจากคิวแล้วนั้นเอง และหากไปดูในหน้าจัดการ RabbitMQ ก็จะเห็นได้ว่า Message ก็โดนดึงออกไปจากคิวหมดแล้ว
และนี่ก็คือการใช้งาน RabbitMQ กับ Node.js เบื้องต้นสำหรับการส่งและรับข้อความ โดยเราสามารถปรับเพิ่มเพื่อเอาไปประยุกต์กับโปรเจกต์อื่น ๆ ได้ ไม่ว่าจะเป็น ระบบแจ้งเตือนแบบเรียลไทม์ (Real-Time Notification System) เมื่อมีเหตุการณ์สำคัญเกิดขึ้น (เช่น มีผู้ใช้ใหม่ลงทะเบียน, มีการสั่งซื้อสินค้าใหม่) ระบบจะส่งข้อความแจ้งเตือนไปยังผู้ใช้หรือแอดมินแบบเรียลไทม์ โดยใช้ RabbitMQ ในการส่งข้อความแจ้งเตือนจากส่วน backend ไปยัง frontend หรือไปยังผู้ใช้ผ่านทาง SMS หรืออีเมล