[NODE] 📚 클러스터(cluster) 모듈 - 멀티 프로세서
클러스터 모듈은 기본적으로 싱글 프로세스로 동작하는 노드를 CPU 코어를 모두 사용할 수 있게 해주는 모듈이다. 포트를 공유하는 노트 프로세스를 여러 개 둘 수도 있으므로, 요청이 많이 들어왔을 때 병렬로 실행된 서버의 개수만큼 요청이 분산되게 할 수 있다. 서버에 무리가 덜 가게 되는 셈이다.
코어가 8개인 개인 서버가 있을 때 노드는 보통 코어 1개만 사용한다. 이를 클러스터 모듈을 설정해서 코어 하나당 노드 프로세스 하나가 돌아가게 해줄 수 있다. 성능이 8배가 되는 것은 아니지만 코어를 하나만 사용할 때에 비해 성능이 개선된다.
하지만 장점만 있는 것은 아니다. 메모리를 공유하지 못하는 등의 단점도 있다. 세션을 메모리에 저장하는 경우 문제가 될 수 있다. 이는 레디스 등의 서버를 도입하여 해결할 수 있다.
const cluster = require('cluster');
const http = require('http');
const numCUPs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master Process ID : ${process.pid}`);
// CPU 개수만큼 워커를 생성
for (let i = 0; i < numCUPs; i++) {
cluster.fork();
}
// 워커가 종료되었을 때
cluster.on('exit', (worker, code, signal) => {
console.log(`${worker.process.pid} 번 워커 종료됨`);
console.log('code ', code, 'signal ', signal);
})
} else {
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type' : 'text/html; charset=utf-8;'});
res.end('<h1>Cluster Server!!</h1>');
}).listen(8086);
console.log(`${process.pid} 번 워커 실행!`)
}
worker_threads와 구조가 조금 비슷하다. 다만 스레드가 아니라 프로세스이다. 클러스터에는 마스터 프로세스와 워커 프로세스가 있다. 마스터 프로세스는 CPU 개수만큼 워커 프로세스를 만들고 대기한다. 요청이 들어오면 만들어진 워커 프로세스에 요청을 분배한다. 워커 프로세스가 실질적인 일을 하는 프로세스이다.
const cluster = require('cluster');
const http = require('http');
const numCUPs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master Process ID : ${process.pid}`);
// CPU 개수만큼 워커를 생성
for (let i = 0; i < numCUPs; i++) {
cluster.fork();
}
// 워커가 종료되었을 때
cluster.on('exit', (worker, code, signal) => {
console.log(`${worker.process.pid} 번 워커 종료됨`);
console.log('code ', code, 'signal ', signal);
cluster.fork();
})
} else {
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type' : 'text/html; charset=utf-8;'});
res.end('<h1>Cluster Server!!</h1>');
setTimeout(() => {
process.exit(1);
}, 1000);
}).listen(8086);
console.log(`${process.pid} 번 워커 실행!`)
}
exit 이벤트리스너에 cluster.for()를 넣어주면 워커 프로세스가 종료되면 다시 새로 생성해준다. 하지만 오류 발생으로 종료가 되는 것이라면 좋지 못한 방법이다. 오류 자체의 원인을 찾아 해결해야한다. 그래도 예기치 못한 에러로 인해 서버가 종료되는 현상을 방지할 수 있어 클러스터링을 적용해두는 것이 좋다.
직접 클러스터 모듈로 클러스터링을 구현할 수도 있지만, 실무에서는 PM2 등의 모듈로 클러스터 기능을 사용하곤 한다.