Node.js 이벤트 루프 설명

Node.js는 싱글 스레드를 사용합니다. 어떻게 수천 개의 요청을 동시에 처리할 수 있는지 궁금할 수 있습니다.

그 비밀은 바로 이벤트 루프(Event Loop)에 있습니다.

Node.js는 작업이 완료될 때까지 기다리는 대신, 시간이 오래 걸리는 작업을 운영체제(OS)로 보냅니다. 그리고 곧바로 다음 작업으로 넘어갑니다. 덕분에 애플리케이션은 빠르고 반응성이 좋아집니다.

블로킹 vs 논블로킹 (Blocking vs Non-blocking)

readFileSync와 같은 동기(sync) 함수를 사용하면 서버가 멈춥니다. 파일 읽기가 완료될 때까지 기다리기 때문입니다. 이 과정에서 다른 사용자는 응답을 받을 수 없으며, 이는 성능을 크게 저하시킵니다.

fs.readFile을 사용하면 서버는 계속 실행됩니다. 파일이 백그라운드에서 읽히는 동안 다른 요청들을 처리할 수 있습니다.

이벤트 루프의 작동 방식

루프는 다음과 같은 여러 단계를 거칩니다:

• Timers: setTimeoutsetInterval을 처리합니다. • Pending Callbacks: 시스템 수준의 에러를 처리합니다. • Poll: 새로운 연결을 수신하고 데이터베이스 쿼리와 같은 I/O를 처리합니다. • Check: setImmediate를 처리합니다. • Close Callbacks: 소켓 종료를 처리합니다.

우선순위

모든 작업의 우선순위가 같지는 않습니다. Node.js는 두 가지 큐(queue)를 사용합니다:

  1. Microtask Queue: Promise를 담습니다.
  2. Callback Queue: setTimeout 및 I/O를 담습니다.

Microtask Queue가 항상 먼저 실행됩니다. 만약 Promise와 setTimeout이 있다면, 타이머보다 Promise가 먼저 완료됩니다.

Call Stack과 큐

Call Stack은 현재 어떤 코드가 실행 중인지 추적합니다. 작업이 완료되면 해당 콜백은 큐에 들어갑니다. 이벤트 루프는 Call Stack이 비워질 때까지 기다린 후 큐에서 작업을 가져옵니다.

다음 실수들을 피하세요:

• 무한 루프를 사용하지 마세요. 앱 전체가 멈출 수 있습니다. • 운영 환경(production)에서 동기식 파일 메서드를 사용하지 마세요. • 메인 스레드에서 무거운 수학 연산이나 비디오 프로세싱을 실행하지 마세요.

무거운 작업에는 Worker Threads나 백그라운드 작업을 사용하세요.

요약

Node.js가 빠른 이유는 기다리지 않기 때문입니다. I/O 작업을 위임하고 이벤트 루프를 사용하여 결과를 관리합니다. 이러한 구조 덕분에 하나의 스레드로도 많은 사용자를 처리할 수 있습니다.

이벤트 루프의 어떤 부분이 가장 배우기 어려웠나요? 댓글로 알려주세요.

출처: https://dev.to/synfinity-dynamics-pvt-ltd/nodejs-event-loop-explained-how-nodejs-handles-thousands-of-concurrent-requests-1heo