NodeJS ตอนที่ 9 [Cluster]

การทำ Cluster มีความหมายค่อนข้างกว้างและเกี่ยวกับเรื่องการจัดกลุ่ม สำหรับไลบรารี่ Cluster ของ NodeJS คือการแตกโปรเซสออกเป็นหลายๆ โปรเซส เพื่อกระจายการทำงาน สำหรับ NodeJS จะทำงานแบบ Single Thread ถ้าต้องการกระจายงานให้สามารถทำงานพร้อมกันได้หลายงานต้องทำการแตกโปรเซสออกเป็นหลายๆตัว ซึ่งก็คือการทำ Cluster

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

[img src=”/wp-content/uploads/2016/02/nodecluster.png”]

ตัวอย่างโค้ด

  1. สร้างไฟล์ชื่อ ch9_cluster.js
  2. ป้อนโค้ด ดังนี้
    const cluster = require('cluster');
    const http = require('http');
    const numCPUs = require('os').cpus().length;
    
    if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
    }
    
    cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
    });
    } else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server
    http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello worldn');
    }).listen(8000);
    }

    โค้ดนี้นำมาจาก https://nodejs.org/api/cluster.html

อธิบายโค้ด

const cluster = require('cluster');

เรียกใช้ไลบรารี่ cluster

const numCPUs = require('os').cpus().length;

เรียกใช้ ไลบรารี่ os ซึ่งจะมีข้อมูลสำคัญๆของเครื่องซึ่งเอามาจากระบบปฏิบัติการ เช่น จำนวน CPU , memory , disk

if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}

cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
}

ตรวจสอบว่าเป็น master cluster หรือไม่ จากนั้นวนลูปสร้างโปรเซสขึ้นตามจำนวน CPU

for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}

ถ้าโปรเซสไหนตายให้แสดงข้อความ บอกเลข processid ที่ตาย

cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});

หากไม่ใช่ master โปรเซสให้สร้าง http server ที่ port 8000

http.createServer((req, res) => {
res.writeHead(200);
res.end('hello worldn');
}).listen(8000);

ทำการทดสอบ เปิด Browser พิมพ์ localhost:8000

เปิดโปรแกรม Activity Monitor หรือ Task Manager

[img src=”/wp-content/uploads/2016/02/nodeclusterprocess.png”]

จากรูปจะพบว่าที่เครื่องที่มี CPU 4 Cores มี node ทั้งหมด 5 โปรเซส จะมี 1 โปรเซสที่ทำหน้าที่เป็น Load Balance คอยกระจายงานให้โปรเซสอื่นๆ

ในการใช้งานจริงผมจะไม่ได้มาเขียนฟังก์ชั่นสำหรับทำ cluster แบบนี้ จะใช้เครื่องมือสำหรับ monitor และสร้าง cluster ได้ นอกจากนั้นเมื่อมีโปรเซสตายก็จะสร้างโปรเซสใหม่ขึ้นทันที ทำให้โปรเซสของ node รันได้ตลอดเวลา โดยเครื่องมือนั้นชื่อว่า PM2

ติดตั้ง pm2

npm install pm2 -g

pm2 ต้องใช้ออพชั่น -g เพื่อให้สามารถรันคำสั่ง pm2 จาก terminal ได้

รัน pm2

นำไฟล์ตัวอย่างตอนที่ 5 มารันคำสั่ง ดังนี้

pm2 start ch5_restapi.js -i 4

[img class=”alignnone size-large wp-image-1292″ src=”/wp-content/uploads/2016/02/pm2.png”/]

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

หากต้องการ ลบโปรเซสทั้งหมดใช้คำสั่ง

pm2 kill

สำหรับคำสั่งของ pm2 สามารถพิมพ์ pm2 ที่ terminal ได้ หรือหาข้อมูลเพิ่มเติมได้ที่ https://github.com/Unitech/pm2

นอกจากนั้นยังมีเครื่องมือในการ monitor nodejs อย่าง http://pm2.keymetrics.io/

โปรดติดตามตอนที่ 10 การทำงานกับไฟล์