JAN's History
Node.js 멀티프로세스 vs 싱글프로세스와 throng 라이브러리 활용법 본문
개발하는 프로젝트가 멀티프로세스로 떠있는데, Node.js는 싱글 프로세스인데 어떻게 멀티프로세스로 떠있다는거지..? 라는
의문이 생겨서 정리해보았습니다.
먼저 멀티 프로세스와 싱글 프로세스의 개념을 알아보겠습니다.
싱글프로세스
- 하나의 프로세스에서 모든 작업을 처리합니다.
- Node.js는 기본적으로 싱글스레드 이벤트 루프 기반이므로, 기본 서버는 싱글프로세스입니다.
- CPU 코어가 여러 개라도, 기본 싱글프로세스는 한 코어만 사용 가능 → CPU 자원 활용이 제한적입니다.
멀티프로세스
- CPU 코어 수만큼(또는 지정한 수만큼) 프로세스를 띄워 병렬로 작업 처리합니다.
- Node.js에서는 cluster 모듈이나 throng 같은 라이브러리를 사용해 구현할 수 있습니다.
- 각 프로세스는 독립적인 메모리 공간을 가지므로 메모리 사용량 증가할 수 있습니다.
- CPU 자원을 여러 코어에 걸쳐 최대한 활용 가능 → 처리량 증가됩니다.
멀티프로세스와 싱글프로세스 메모리 차이
구분 | 싱글 프로세스 | 멀티 프로세스 |
프로세스 수 | 1 | CPU 코어 수만큼 (ex. 4~8) |
메모리 사용량 | 상대적으로 적음 | 각 프로세스가 메모리를 독립적으로 소모 → 전체 메모리 증가 |
CPU 활용도 | 한 코어만 사용 | 여러 코어 활용 → 높은 CPU 사용률 |
장애 영향 | 프로세스 다운 시 전체 영향 | 일부 프로세스 다운 시 나머지 프로세스는 정상 작동 |
throng 라이브러리란
저희 프로젝트에서는 throng 이라는 라이브러리를 사용하여 멀티 프로세스를 사용하는데요!
이 라이브러리는 사실 저도 처음 들어봤습니다.. (공부하면서 이번기회에 알게됨)
throng은 Node.js용 프로세스 매니저 라이브러리인데요.
CPU 코어 수에 맞춰서 워커 프로세스를 자동으로 fork하고 관리하는 라이브러리입니다.
그러면 어떤식으로 사용하는지 예시 코드를 함께 보겠습니다.
import throng from 'throng';
import Koa from 'koa';
const WORKER_COUNT = process.env.WEB_CONCURRENCY
? parseInt(process.env.WEB_CONCURRENCY, 10)
: require('os').cpus().length;
async function start() {
const app = new Koa();
app.use(async (ctx) => {
ctx.body = `Hello from process ${process.pid}`;
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server started on port ${port} by process ${process.pid}`);
});
}
throng({
workers: WORKER_COUNT,
lifetime: Infinity,
start,
});
동작 방식
- throng가 워커 프로세스 개수만큼 Node.js 프로세스를 fork합니다.
- 각 워커 프로세스가 독립적으로 Koa 서버를 실행할 수 있습니다. (모두 같은 포트에 listen 가능)
- OS의 SO_REUSEPORT 기능 덕분에 여러 프로세스가 동일 포트에서 연결 수신 가능해요.
- SO_REUSEPORT란?
- 운영체제(OS)의 소켓 옵션(socket option) 중 하나로,
- 여러 프로세스가 동일한 IP 주소와 포트 번호를 동시에 바인딩(bind)할 수 있도록 허용해주는 기능
- SO_REUSEPORT란?
- 들어오는 요청이 여러 프로세스에 분배되어 CPU 자원을 최대한 활용합니다.
동작방식을 조금 더 이해하기 쉽게 예시를 들어보자면,
3000번 포트는 1개, 그 안에 여러 프로세스가 listen하고 있다고 해보겠습니다.
- 클라이언트 입장에선 서버 IP:3000 하나로 접속합니다.
- 내부적으로는 여러 개의 워커 프로세스가 그 3000번 포트에 동시에 바인딩해서 요청을 처리합니다.
- OS의 SO_REUSEPORT 기능 덕분에 여러 프로세스가 같은 포트를 쓸 수 있어.
- start() 함수는 워커 프로세스별로 각각 실행됩니다.
- 멀티프로세스로 워커 여러 개를 띄우면,
- 각 워커 프로세스는 독립적으로 start() 함수를 실행해 서버를 띄움.
- TCP 단계에서 트래픽 분배됩니다.
- OS(운영체제) 커널의 TCP 스택이 들어오는 연결 요청(TCP handshake)을 감지해서
- 동일 포트를 listen 하는 여러 프로세스 중 하나로 요청을 분배(load balancing) 해 줌.
- 이 과정은 TCP 계층(OSI 4계층)에서 이뤄지며, 애플리케이션 레벨(HTTP) 이전임.
3000번 포트 입구는 1개고, 들어오는 손님들을 OS가 여러 워커 프로세스에게 골고루 배분해 주는 셈이라고 이해하면 쉽더라고요!
마스터 프로세스와 워커 프로세스 관계
멀티 프로세스로 돌리기위해 워커만 잔뜩 실행시키면, 멀티프로세스니까 워커 프로세스 각각이 독립적으로 실행되므로
마스터 역할로 하려던 작업(초기화, 백업 등)이 워커 수만큼 중복 실행될 수 있습니다.
그래서 이런 작업은 마스터 프로세스에서만 실행하는 게 중요한데요!
- 마스터 프로세스는 전체 애플리케이션의 ‘중앙 관리자’ 같은 역할입니다.
한 번만 실행해서 초기화 작업, 설정, 백업, 마이그레이션 검사 등을 수행해요. - 워커 프로세스들은 실제 클라이언트 요청을 처리하는 프로세스들이고,
CPU 코어 수만큼 여러 개가 떠서 병렬로 일하는 것입니다.
딱 한번만 실행되면 좋겠는 함수들은 마스터 프로세스에 담아두면 좋겠죠?
싱글프로세스 vs 멀티프로세스 선택 기준
상황 | 추천 |
CPU 코어가 적고 트래픽이 낮은 서비스 | 싱글프로세스 |
CPU 코어가 여러 개이고, 높은 처리량이 필요한 서비스 | 멀티프로세스 (cluster/throng 활용) |
메모리 제한이 엄격한 환경 | 싱글프로세스 고려 |
안정성과 장애 대응이 중요한 서비스 | 멀티프로세스 (프로세스별 독립 실행) |
후기
멀티프로세스는 CPU 코어를 최대한 활용할 수 있는 좋은 방법이지만, 메모리 사용량이 늘어나고 프로세스 관리가 필요하죠..
throng 같은 라이브러리를 사용하면 간단히 멀티프로세스를 구현하고,
쿠버네티스 같은 환경에서도 효율적인 자원 활용이 가능해서 유용할 것 같네요 ㅎㅎ
'Node.js' 카테고리의 다른 글
Node.js에서 파일관리하기 (0) | 2024.04.15 |
---|---|
Node의 모듈 (0) | 2024.04.14 |
JavaScript의 비동기 처리방식 (0) | 2024.04.13 |