[4장] 서버 만들기 (cluster)

2022. 5. 3. 19:49책/Node.js 교과서

4. cluster

싱글 프로세스로 동작하는 노드가 CPU 코어를 모두 사용할 수 있게 해주는 모듈. 포트를 공유하는 노드 프로세스를 여러 개 둘 수 있어서 요청이 많이 들어와도 병렬로 실행된 서버의 개수만큼 요청이 분산되게 할 수 있다.

worker_threads와 비슷하게 생겼으나 스레드가 아니라 프로세스임

예를 들어 코어가 4개라고 치자. 노드는 보통 코어 하나만 활용하지만 cluster 모듈을 설정하면 코어 하나당 노드 프로세스 하나가 돌아가게끔 할 수 있다. 즉 같은 역할을 하는 서버를 4개 만큼 독립되게 열어두는 것. 성능이 꼭 4배가 되는건 아니더라도 코어를 하나만 쓸 때와 비교하면 성능이 개선된다. 물론 메모리를 공유하지 못하는 단점도 존재.

 

1) 클러스터링 해보기

더보기
const cluster = require('cluster');
const http = require('http');

// 지금 쓰고있는 노트북의 코어는 4개
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    console.log(`마스터 프로세스 아이디: ${process.pid}`);
    for (let i=0; i < numCPUs; i +=1 ) {
        cluster.fork(); // 4개의 독립된 워커프로세스 생성
    }

    // 만약 워커프로세스가 종료되면('exit') 동작할 이벤트리스너
    // process.pid - 프로세스 식별자(Process identifier)
    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.write('<h1>Hello Node</h1>');
        res.end('<p>Hello Cluster!</p>');

        // 요청이 오면 강제로 1초 뒤에 종료되도록 만들었다.
        // 워커프로세스가 종료되면 마스터 프로세스의
        // cluster.on('exit', listener)가 실행될 것이다.
        setTimeout(() => {
            process.exit(1);
        }, 1000);
    })
    .listen(8086)
    
    console.log(`${process.pid}번 워커 실행`);
}

콘솔
마스터 프로세스 아이디: 10156
21896번 워커 실행
12252번 워커 실행
16856번 워커 실행
13984번 워커 실행

13984번 워커가 종료되었음 <-- localhost/8086접속 후 1초 뒤...
code 1 signal null
16856번 워커가 종료되었음 <-- localhost/8086접속 후 1초 뒤...
code 1 signal null
12252번 워커가 종료되었음 <-- localhost/8086접속 후 1초 뒤...
code 1 signal null
21896번 워커가 종료되었음 <-- localhost/8086접속 후 1초 뒤...
code 1 signal null            여기까지 요청을 보내고나면 더이상 구동중인 서버가 없어서
                              localhost/8086으로 접속이 불가능해진다

 

2) 클러스터링 응용

위에서 4개의 워커 프로세스로 서버를 구동시켰다. 그리고 강제로 종료시키긴 했지만 4번까진 localhost/8086으로 서버 요청을 보낼 수 있었다. 이를 달리 말하면 만약 오류가 발생해서 서버가 강제종료 되더라도 4번 까지는 서버가 정상 작동할 수 있다는 뜻이다.

 

이 점에 착안해서 만약 워커 프로세스가 하나 종료되면 추가로 하나의 워커 프로세스가 구동되도록 코드를 작성할 수 있다. 물론 이런 식으로 에러 처리를 하는 방식은 좋지 않으나 예기치 못한 에러로 인해 서버가 완전히 죽어버리는 현상은 방지할 수 있어 의의가 있다.

 

if (cluster.isMaster) {
    ...
    // 워커 프로세스가 종료된게 인지되면
    // 워커 프로세스를 하나 추가로 열어준다
    cluster.on('exit', (worker, code, signal) => {
        cluster.fork();
    })

    ...

클러스터링을 구현할 땐 직접 cluster 모듈을 사용해도 되지만, 실무에선 pm2 등의 모듈로 대체하곤 한다. 이는 15장에서 자세히 알아보기로 하자.

 

나아가 지금까지 노드의 http 모듈을 사용해 서버를 만들었지만 이 모듈만으로는 코드가 지저분해지고, 쿠키나 세션을 추가하면 더 길고 복잡해진다. 따라서 6장에서 Express 프레임워크를 통해 서버를 만들어보기로 하자. 

 

※ 참고자료

 

' > Node.js 교과서' 카테고리의 다른 글

[6장] Express  (0) 2022.05.05
[5장] npm 패키지 매니저  (0) 2022.05.04
[4장] 서버 만들기(쿠키와 세션)  (0) 2022.05.03
[4장] 서버 만들기 (REST & Routing)  (0) 2022.05.03
[4장] 서버 만들기 (http모듈)  (0) 2022.05.01