NestJS 비동기 처리: 이벤트 루프와 libuv 분석 (2편)
AI Store에서 AI코딩으로 만들어진 앱을 만나보세요!
지금 바로 방문하기

[NestJS] 비동기의 핵심, 이벤트 루프 + libuv 파헤치기 (2편)

카테고리

프로그래밍/소프트웨어 개발

서브카테고리

개발 툴

대상자

Node.js 및 NestJS를 사용하는 백엔드 개발자, 성능 최적화에 관심 있는 개발자

난이도: 중급 ~ 고급 (이벤트 루프, libuv, 병렬 처리 이해 필요)

핵심 요약

  • *Node.js의 싱글 스레드 구조는 I/O 작업에 강하지만 CPU 집약 작업에 약하다.**
  • libuv는 비동기/논블로킹 I/O 처리를 담당하는 핵심 라이브러리로, 운영체제 최적화 API(IOCP, epoll, kqueue)를 활용한다.
  • Worker Threads는 순수 CPU 연산(암호화, 이미지 처리 등)을 병렬 처리하고, PM2 클러스터 모드는 멀티코어를 활용해 부하 분산 가능.
  • Thread Pool은 I/O 작업 처리에 사용되며, UV_THREADPOOL_SIZE 환경 변수로 크기 조절 가능.

섹션별 세부 요약

  1. 왜 CPU 집약 작업에 약할까?
  • Node.js는 싱글 스레드 + 이벤트 루프 구조로, CPU 집약 작업은 메인 스레드를 블로킹해 응답 지연을 유발.
  • 예: for (let i = 0; i < 1e9; i++) { Math.sqrt(i); } 같은 반복문은 이벤트 루프를 멈추게 함.
  • 해결 방법: Worker Threads 또는 PM2 클러스터 모드 활용.
  1. 왜 I/O 작업은 장점일까?
  • libuv가 OS 최적화 API를 사용해 I/O 작업을 비동기 처리.
  • 예: 파일 읽기, 네트워크 요청, DNS 조회 등은 libuv가 시스템 API로 처리해 블로킹 방지.
  • Node.js의 이벤트 루프는 libuv의 구현체로, JavaScript 로직은 V8 엔진을 통해 처리.
  1. libuv란 무엇인가?
  • C 기반 라이브러리로, Node.js의 비동기 처리 핵심 엔진.
  • 기능: 네트워크, 파일 I/O, 타이머, DNS 등 모든 비동기 작업 처리.
  • OS 최적화 API 사용:

- Windows: IOCP

- Linux: epoll

- macOS: kqueue

  • Spring과의 차이: Spring은 select 사용 vs libuv는 더 효율적인 epoll 사용.
  1. libuv의 내부 동작 원리
  • uv_run() 함수가 이벤트 루프를 실행하며, UV_RUN_DEFAULT 모드로 지속적으로 처리.
  • 비동기 작업 처리 흐름:
  1. JavaScript 코드 실행 →
  2. libuv 호출 →
  3. 작업 분류(비동기/동기) →
  4. 시스템 API 또는 Thread Pool 위임 →
  5. 콜백 등록 →
  6. 이벤트 루프가 콜백 실행.
  1. Thread Pool의 이해
  • 기본적으로 4개의 워커 스레드가 존재, UV_THREADPOOL_SIZE로 조절 가능.
  • 처리 가능한 작업:

- crypto.pbkdf2, 파일 시스템 I/O, zlib 압축, DNS 조회 등.

  • 처리 불가능한 작업: 순수 JavaScript 연산(예: Math.sqrt 반복).
  • 작업 처리 방식: FIFO 큐 기반, 스레드 완료 시 대기 중 작업 처리.

결론

  • *NestJS에서 성능 최적화 전략:**

- CPU 집약 작업: Worker Threads 또는 PM2 -i max 클러스터 모드 사용.

- I/O 작업: UV_THREADPOOL_SIZE 값을 늘려 효율적으로 처리.

  • *핵심 팁:** libuv의 OS 최적화 API와 Thread Pool을 이해하면 Node.js의 비동기 메커니즘을 효과적으로 설계 및 최적화할 수 있다.