1. docker stats로 CPU 보는 법
- docker stats 치면 컨테이너별 CPU%, 메모리, 네트워크 등 실시간 리소스 나옴
- 여기서 CPU%는 호스트 기준임
- 예: 4코어 서버라면 CPU 400%까지가 최대치
- 컨테이너가 120% 찍혀 있으면 → 1.2 코어 먹는 중이라는 뜻임
- docker는 cgroup으로 CPU 제한 걸지 않으면 컨테이너가 여러 코어 쓸 수 있음
- 즉, CPU%가 100% 넘는다고 “오류”는 아님. 코어 여러 개 사용 가능해서 그럼
2. Node.js는 싱글스레드라 코어 하나밖에 못쓰는 거 아님?
- Node의 JavaScript 실행부(V8)는 싱글스레드 맞음
- 근데 운영 환경에서는 다음들 때문에 CPU가 100% 넘어가는 듯 보일 수 있음
- libuv thread pool (파일 IO 등은 thread pool에서 돌아감 → CPU% 추가됨)
- Node 프로세스가 여러 워커를 만들었을 경우 (cluster, PM2 cluster mode)
- 컨테이너가 다른 작업까지 함께 잡아먹는 경우
- 하지만 핵심 JS 이벤트루프 자체는 코어 하나만 전담함
그래서 중요한 기준
Node.js JS 스레드는 CPU 한 코어를 100% 가까이 먹기 시작하면 사실상 병목 의심 단계임
docker에서 CPU가 180% 찍히더라도
그 중 JS 스레드가 100%를 쓰고 있는 순간 병목이 나타날 수 있음.
3. CPU 100% 이상이면 병목이라는 말의 의미
- Node는 JS 실행이 메인스레드 1개라서
그 스레드가 100% 경계에 닿으면 이벤트루프가 밀림 → 응답 지연 발생 - docker stats의 CPU는 총합이므로 “100% 넘는 것 자체”는 문제 아님
🔥 병목 판단 기준
- 이벤트루프 지연(Event loop delay)이 50ms 이상 꾸준하면 병목 가능성 매우 높음
- docker stats에서 100% 근처에서 계속 흔들리면 JS 메인스레드가 바쁠 확률 높음
- 요청 처리 중 지연(log, socket emit, API 호출 등)이 자주 생기면 CPU 병목 의심
4. 이벤트루프 딜레이 측정하는 법
node -e "setInterval(()=>{const d=Date.now();setImmediate(()=>console.log('Delay:',Date.now()-d,'ms'))},1000)"
- 이 코드는 ‘기존 Node 프로세스의 딜레이’를 보는 게 아니라
새로운 Node 프로세스를 띄워서 이벤트루프 지연 측정하는 도구임
즉:
- 실제 서버의 event loop delay를 보는게 아니라
측정용 Node 인스턴스를 띄워서 CPU 여유를 보는 것에 가까움 - 컨테이너 전체 부하가 높으면 이것도 delay가 커짐
→ 환경 부하 측정용으로는 의미 있음
5. “기존 실행 중인 Node 프로세스의 event loop delay는 어떻게 보나?”
이미 실행 중인 서버에서 event loop delay를 직접 보는 방법들은 다음임:
1) 직접 프로파일링: clinic doctor
npm install -g clinic clinic doctor -- node server.js
- CPU 프로파일, block되는 부분, heavy 함수 등을 보여줌
- 단점: 실행 중인 프로세스에 attach 불가 → 재실행해야 함
2) Node.js 내에서 event loop delay 측정
server.js에 추가:
const { monitorEventLoopDelay } = require('perf_hooks'); const h = monitorEventLoopDelay(); h.enable(); setInterval(() => { console.log('Loop delay', h.mean / 1e6, 'ms'); }, 1000);
이러면 현재 서버의 실제 이벤트루프가 얼마나 밀리는지 바로 나옴
6. CPU 병목이 실제로 발생하면 증상
- Socket 이벤트 응답 느려짐
- ping/pong 타임아웃 자주 발생
- API 응답 딜레이 증가
- Redis 응답은 정상인데 Node만 느려짐
- 컨테이너 재배포·재시작 시 빨라짐 (일시적인 GC + 이벤트루프 해소)
7. 결론
docker stats CPU%는 호스트 전체 기준이라 100% 넘어도 괜찮음
- Node.js는 JS 메인스레드가 100% 부근 도달하면 병목 가능성 매우 높음
- 병목 판단은 이벤트루프 딜레이를 기준으로 보는 게 정답
- delay 50~100ms 이상 지속 시 → 코드 최적화 or 스케일아웃 필요
'TIL' 카테고리의 다른 글
| 마이그레이션 제대로 한 후기 (0) | 2025.12.18 |
|---|---|
| Redis String vs Set (0) | 2025.12.18 |
| NAT(Network Address Translation) 네트워크란? (0) | 2025.12.02 |
| 컨테이너 포트를 host 포트로 못 쓰면??? (0) | 2025.11.28 |
| 컨테이너 Exit 원인 명령어 정리 (0) | 2025.11.28 |