노드 클러스터 cluster
cluster
기본적으로 싱글 스레드인 노드가 CPU 코어를 모두 사용할 수 있게 해주는 모듈이다.
- 포트를 공유하는 노드 프로세스를 여러 개 둘 수 있음
- 요청이 많이 들어왔을 때 병렬로 실행된 서버의 개수만큼 요청이 분산된다.
- 서버에 무리가 덜 간다.
- 코어가 8개인 서버가 있을 때 : 보통은 코어 하나만 활용
- cluster로 코어 하나당 노드 프로세스 하나를 배정 가능하다.
- 성능이 8배가 되는 것은 아니지만 개선된다.
- 단덤 : 컴퓨터 자원(메모리, 세션 등) 을 공유하지 못한다.
- Redis 등 별도 서버로 해결한다.
//cluster.js
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`마스터 프로세스 아이디: ${process.pid}`);
// CPU 개수만큼 워커를 생산
for (let i = 0; i < numCPUs; i += 1) {
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.write('<h1>Hello Node!</h1>');
res.end('<p>Hello Cluster!</p>');
setTimeout(() => { // 워커 존재를 확인하기 위해 1초마다 강제 종료
process.exit(1);
}, 1000);
}).listen(8086);
console.log(`${process.pid}번 워커 실행`);
}
어떻게 보면 worker_threads 활용 코드랑 많이 비슷하다.
다만 worker_threads 는 스레드를 여러개 만드는 거지만 cluster는 프로세스를 여러 개 만드는 것이다.
CPU의 개수만큼 클러스터 프로세스를 생성하고(워커 프로세스)
else 부분에서 워커 프로세스에서 서버를 8086번 포트에 띄우는 것을 볼 수 있다.
본인의 컴퓨터의 코어 개수만큼 서버의 개수도 늘어나고 그것들이 모두 8086번 포트에서 동작하게 된다.
*서버는 각각 프로세스 하나를 차지한다고 했고 그 프로세스들은 각각 포트 하나를 차지한다고 했다.
그런데 이렇게 clustering을 하면 한 포트에 여러개의 서버를 묶어 놓을 수 있다.
즉, 하나의 포트에서 본인의 CPU 개수만큼의 서버를 동작 시킬 수 있다.
이렇게 하면 8086번 포트에 서버가 여러개 있게 되는데 요청이 들어오면 각각의 서버에 라운드 로빈 알고리즘에 따라서 요청의 분배가 이루어지게 된다.
실제로 CPU 코어의 개수만큼 프로세스가 생성이 되는지 확인해보면 다음과 같다
본인의 CPU 코어의 개수는 16개이다. 따라서 16개의 워커 프로세스가 8086번 포트에 생성된 것을 볼 수 있다.
클라이언트에서 실행이 될 때마다 프로세스가 하나씩 종료되는데 웹 브라우저에서 새로고침을 통해 16번의 요청을 보내면 모든 프로세스가 종료되어 더 이상 접속되지 않는 것을 볼 수 있다.
//cluster.fork() 이 부분에 주석이 되어 있는데 주석을 풀면 프로세스가 종료가 될 때마다 새로운 프로세스를 만들어 아무리 많은 요청이 와도 서버가 다운이 되지 않게끔 할 수 있다.