BLUEGYU

Node.js 비동기 I/O와 libuv 이해하기

2025-09-10

최근 면접을 다녀온 뒤 부족한 CS 지식과 함께 NestJS를 공부하고 있었습니다. 그러다 NestJS 공식 문서의 비동기 관련 내용을 보던 중, 문득 "내가 이해한 Node.js의 비동기 작업이 맞는 걸까?" 하는 의문이 들었습니다. 이를 확인하고, 그 과정에서 잘못 알았던 점과 새롭게 알게 된 점을 정리하기 위해 이 글을 작성했습니다.

내가 잘못 알고 있었던 점

제가 잘못 이해했던 내용은 **"Node.js의 모든 비동기 작업은 libuv에서 처리된다"**는 것이었습니다. 이전에 Node.js를 공부할 때는 코드 작성 방법에 집중하느라 동작 원리를 깊게 살펴보지 않았기 때문에 생긴 오해였습니다.

Node.js의 비동기 작업은 어디서 처리될까?

책과 인터넷에서 찾아본 바에 따르면 Node.js의 비동기 작업은 백그라운드에서 처리된다고 합니다. 여기서 백그라운드는 작업 종류에 따라 커널일 수도 있고 libuv 스레드 풀일 수도 있습니다.

  • 대부분의 네트워크 I/O는 커널에서 처리되며, Node.js는 완료 이벤트를 받습니다. (예: 네트워크 소켓, DB 클라이언트, HTTP 요청)
  • CPU 연산이 필요한 작업이나 커널이 직접 지원하지 않는 작업은 libuv 스레드 풀에서 실행됩니다. (예: 암호화, 파일 I/O, 압축 등)

libuv에 대한 이해

libuv는 크로스 플랫폼 비동기 I/O를 위한 백엔드 라이브러리입니다. 운영체제마다 다른 I/O 처리 방식을 공통 인터페이스로 추상화하여 제공하기 때문에 Node.js는 별도의 OS 설정 없이 동일한 방식으로 비동기 작업을 수행할 수 있습니다.

비동기 작업에서 libuv는 어떤 역할을 할까요? libuv는 백그라운드(커널 또는 내부 스레드 풀)에서 전달 받은 완료 신호를 기반으로 작업의 콜백을 큐에 등록하고, 이벤트 루프로서 큐에 등록된 콜백을 스택으로 옮기는 전반적인 Node.js의 비동기 작업 흐름을 관리합니다.

또한, 이벤트 루프에서 동작하는 I/O 외 기능(타이머, idle, 시그널 등)도 libuv가 관리합니다.

Node.js 비동기 작업 흐름

Node.js의 비동기 작업 흐름은 단계별로 이해하면 더 명확합니다. 각 단계에서 궁금했던 점과 답변도 함께 포함했습니다.

  1. 스택에 비동기 작업이 호출됨

    함수 호출이 스택에 쌓입니다.

  2. 비동기 작업이 백그라운드로 이동

    CPU 연산이 필요한 작업은 libuv 스레드 풀로, 네트워크/커널 I/O는 OS로 전달됩니다.

  3. 작업 완료 후 큐로 이동

    백그라운드에서 작업이 완료되면, libuv가 해당 작업의 콜백을 큐에 등록합니다.

    • 궁금점: Microtask와 Macrotask 중 어떤 것이 먼저 실행될까?

    • 답변: 큐에는 Microtask(Promise.then, process.nextTick)와 Macrotask(setTimeout, setInterval, I/O 콜백)가 존재합니다. 이벤트 루프는 매 반복마다 Microtask 큐를 먼저 비우고, 그 다음 Macrotask를 처리합니다. 따라서 같은 시점에 완료된 작업이 있어도 Microtask가 먼저 실행됩니다.

  4. 큐에서 스택으로 이동

    이벤트 루프가 큐에 등록된 콜백을 스택으로 옮겨 실행합니다.

    • 궁금점: 비동기 작업이 백그라운드로 이동하면 기존 코드는 스택에서 사라지는데, 어떻게 이어서 실행될 수 있을까?

    • 답변: 비동기 작업을 포함한 함수 호출 시, 관련 스코프와 변수 참조는 메모리에 남아 있습니다. GC(Garbage Collector)는 더 이상 참조되지 않는 메모리만 정리하므로, 비동기 작업과 이후 코드가 필요한 정보는 안전하게 유지됩니다. 결과적으로, 비동기 작업이 완료되면 이전 코드의 컨텍스트를 그대로 활용해 이어서 실행할 수 있습니다.

  5. 스택에서 pop

    콜백 실행이 끝나면 스택에서 제거되고, 다음 작업이 진행됩니다.

정리하며

이번에 Node.js의 비동기 작업 원리를 다시 살펴보면서, 그동안 잘못 알고 있던 부분과 새롭게 알게 된 점을 정리할 수 있었습니다. libuv가 단순한 라이브러리가 아니라 Node.js 전체 비동기 흐름을 관리하는 핵심이라는 것을 알게 되었고, 비동기 작업에도 우선순위가 있다는 점도 깨달았습니다.

그동안은 기술 스택을 어떻게 쓰는지에만 집중하다 보니 동작 원리를 깊게 이해하지 못했지만, 이제는 비동기 작업이 스택, 큐, 이벤트 루프, 백그라운드에서 어떻게 이어지는지 알게 되었기 때문에 같은 코드를 작성해도 더 효율적이고 안전하게 적용할 수 있을 것 같습니다.

앞으로는 단순히 기능을 사용하는 것에 그치지 않고, 기본 동작 원리를 이해하며 기술 스택을 올바르게 활용하는 개발자가 되어야겠다는 생각을 하게 되었습니다.

추천 포스트

  • 3편: GitHub Actions로 블로그 자동 배포 파이프라인 구축하기 썸네일

    3편: GitHub Actions로 블로그 자동 배포 파이프라인 구축하기

    GitHub Actions로 블로그 CD 파이프라인을 구축한 경험을 정리한 글입니다. 썸네일 자동 생성, 태그·dispatch 기반 배포, PR 자동화까지 다룹니다.

    Read More
  • 2편: 블로그 SEO 적용과 사이트 성능 최적화 썸네일

    2편: 블로그 SEO 적용과 사이트 성능 최적화

    블로그에 SEO를 적용하고 사이트 성능을 최적화한 과정을 정리한 글로, 메타데이터, 링크 미리보기, 사이트맵, JSON-LD, LightHouse 성능 점검과 최적화 경험을 다룹니다.

    Read More
  • 1편: Gatsby 블로그 프로젝트 구조 설계로 시작하기 썸네일

    1편: Gatsby 블로그 프로젝트 구조 설계로 시작하기

    개인 블로그를 구축하며 소스와 컨텐츠 분리, SEO 친화적 정적 사이트 설계, CI/CD 자동화 등 개발자로서 브랜딩과 효율적 운영을 목표로 한 프로젝트 과정을 정리한 글입니다.

    Read More

Built withGatsby

© 2025 blueGyu. All rights reserved.