libuv 내부: CPU 바운드와 I/O 바운드 작업 이해
Wenhao Wang
Dev Intern · Leapcell

소프트웨어 개발 및 시스템 설계에서 CPU 바운드 작업과 I/O 바운드 작업을 이해하는 것은 애플리케이션을 최적화하고 올바른 기술 스택을 선택하는 데 매우 중요합니다. 이러한 개념은 주로 애플리케이션 성능 병목 현상과 관련이 있으며 개발자가 효율적인 멀티스레딩 및 비동기 프로그램을 설계하는 데 도움이 될 수 있습니다.
시스템 모델
컴퓨터 시스템은 다음과 같이 추상화할 수 있습니다.
입력 (키보드) -> 처리 (CPU) -> 출력 (모니터)
입력 및 출력은 I/O 범주에 속하고, 계산은 CPU에서 처리합니다.
여러 메서드 또는 함수가 순차적 또는 병렬적으로 실행되는 단일 시스템 프로그램은 다음과 같이 추상화할 수 있습니다.
입력 매개변수 -> 계산 -> 반환 값
순차적 또는 병렬적으로 작동하는 여러 단일 시스템 서비스(클러스터)로 구성된 분산 서비스는 다음과 같이 추상화할 수 있습니다.
네트워크 요청 (입력 매개변수) -> 계산 -> 네트워크 응답 (반환 값)
요청과 응답은 I/O 범주에 속하고, 계산은 CPU에서 처리합니다.
하드웨어 및 소프트웨어 관점에서 시스템은 I/O 작업과 CPU 계산으로 구성됩니다.
CPU 바운드 작업
CPU 바운드 작업은 주로 중앙 처리 장치(CPU)의 처리 속도에 의해 제한됩니다. 이러한 작업은 광범위한 계산이 필요하며 디스크 I/O 또는 네트워크 통신과 같은 외부 리소스를 기다리는 대신 대부분의 시간을 CPU를 활용하는 데 소비합니다.
CPU 바운드 작업의 특징
- 높은 계산 수요: 이러한 작업은 비디오 인코딩/디코딩, 이미지 처리 및 과학적 계산과 같은 복잡한 수학적 연산을 포함하는 경우가 많습니다.
- 멀티스레딩 이점: 멀티 코어 CPU에서 병렬 처리는 워크로드를 여러 코어에 분산하여 CPU 바운드 작업의 실행 효율성을 크게 향상시킬 수 있습니다.
- 높은 리소스 소비: CPU 바운드 작업은 실행 중에 CPU 사용률을 100%에 가깝게 만드는 경향이 있습니다.
일반적인 예
- 데이터 분석 및 대규모 수치 계산.
- 그래픽 렌더링 또는 비디오 처리 소프트웨어.
- 암호화폐 채굴.
노트북 팬이 시끄럽게 작동하는 경우 CPU 집약적인 작업을 처리하고 있을 가능성이 높습니다.
CPU 바운드 작업의 최적화 전략
- 병렬화: 병렬 계산을 통해 성능을 향상시키기 위해 멀티 코어 프로세서를 활용합니다.
- 알고리즘 최적화: 불필요한 계산을 줄이기 위해 알고리즘을 개선합니다.
- 컴파일러 최적화: 고성능 최적화 기술을 갖춘 컴파일러를 활용합니다.
I/O 바운드 작업
I/O 바운드 작업은 주로 디스크 I/O 및 네트워크 통신을 포함한 입/출력(I/O) 작업에 의해 제한됩니다. 이러한 작업의 병목 현상은 계산 능력보다는 I/O 작업이 완료될 때까지 기다리는 데 있습니다.
I/O 바운드 작업의 특징
- 높은 I/O 수요: 이러한 작업은 파일을 자주 읽고 쓰거나 대량의 네트워크 요청을 처리합니다.
- 동시성 이점: I/O 바운드 작업은 Node.js의 비차단 I/O와 같은 이벤트 기반 및 비동기 프로그래밍 모델의 이점을 누립니다.
- 낮은 CPU 사용률: 대부분의 시간을 외부 작업을 기다리는 데 소비하므로 CPU 사용률은 일반적으로 낮습니다.
일반적인 예
- 수많은 네트워크 요청을 처리하는 웹 서버 및 데이터베이스 서버.
- 디스크를 자주 읽고 쓰는 파일 서버.
- 빈번한 네트워크 요청 및 데이터 검색이 필요한 이메일 클라이언트 및 소셜 미디어 앱과 같은 클라이언트 애플리케이션.
I/O 바운드 작업의 최적화 전략
- 캐싱: 메모리 내 캐싱을 사용하여 디스크 I/O 수요를 줄입니다.
- 비동기 프로그래밍: 차단을 피하고 응답성 및 처리량을 개선하기 위해 비동기 I/O 작업을 구현합니다.
- 리소스 관리 최적화: 불필요한 읽기 및 쓰기를 최소화하기 위해 I/O 작업을 효율적으로 예약합니다.
Node.js 및 비차단 I/O
Node.js는 이벤트 기반 아키텍처를 통해 단일 스레드가 수많은 동시 클라이언트 요청을 처리할 수 있도록 하는 비차단 I/O 모델의 잘 알려진 구현입니다.
비차단 I/O란 무엇입니까?
비차단 I/O는 프로그램이 완료될 때까지 기다리도록 강요하지 않는 입/출력 작업을 의미합니다. 이 접근 방식을 통해 프로그램은 I/O 작업이 완료되기를 기다리는 동안 다른 작업을 실행할 수 있습니다.
Node.js는 비차단 I/O를 어떻게 처리합니까?
Node.js는 V8 엔진에서 JavaScript를 실행하고 libuv 라이브러리를 활용하여 비차단 I/O 및 비동기 프로그래밍을 구현합니다. Node.js에서 비차단 I/O를 가능하게 하는 주요 구성 요소는 다음과 같습니다.
- 이벤트 루프: Node.js에서 비차단 I/O를 가능하게 하는 핵심 메커니즘입니다. 네트워크 통신, 파일 I/O, 사용자 인터페이스 작업 및 타이머 이벤트를 동시에 처리할 수 있습니다.
- 호출 스택: 모든 동기 작업(계산 또는 직접 데이터 처리와 같은 차단 작업)은 호출 스택에서 실행됩니다. 호출 스택에서 시간이 오래 걸리는 작업은 프로그램을 차단하여 "메인 스레드가 멈추는" 원인이 될 수 있습니다.
- 콜백 큐: 비동기 작업이 완료되면 해당 콜백 함수는 실행되기를 기다리는 큐에 배치됩니다. 이벤트 루프는 큐를 계속 확인하고 실행 가능한 콜백을 호출 스택으로 이동하여 실행합니다.
- 비차단 작업: 파일 시스템 작업의 경우 Node.js는 libuv 라이브러리를 활용하여 기본 POSIX 비차단 API 호출을 활용하여 비차단 기능을 활성화합니다. 네트워크 요청의 경우 Node.js는 비차단 네트워크 I/O를 구현합니다.
다음 예를 고려하십시오.
const fs = require('fs'); fs.readFile('./test.md', 'utf8', (err, data) => { if (err) { console.error('Error reading file:', err); return; } console.log('File content:', data); }); console.log('Next step');
이 예에서 fs.readFile
은 비동기적으로 실행됩니다. Node.js는 파일 읽기가 완료될 때까지 기다리지 않고 console.log('Next step')
을 계속 실행합니다. 파일 읽기가 완료되면 콜백 함수가 큐에 대기되고 결국 실행되어 파일 내용을 표시합니다.
이벤트 기반 콜백을 활용하여 단일 스레드는 여러 작업을 효율적으로 처리하여 I/O 바운드 작업을 처리할 때 성능 및 리소스 활용도를 크게 향상시킬 수 있습니다.
Node.js의 비차단 파일 시스템 작업
Node.js가 파일 시스템 작업(예: 파일 읽기)을 수행할 때 POSIX 파일 시스템 API를 직접 호출하는 대신 libuv를 사용합니다. Libuv는 이벤트 루프가 차단되는 것을 방지하면서 이러한 작업을 실행하는 가장 효율적인 방법을 결정합니다.
Libuv는 OS 수준 차단 I/O 작업을 비동기적으로 실행하기 위해 고정 크기 스레드 풀(기본값: 4개의 스레드)을 유지 관리합니다. 따라서 파일 I/O 작업은 기본 이벤트 루프를 차단하는 대신 이러한 백그라운드 스레드에서 실행됩니다.
Libuv는 생산자-소비자 모델을 따릅니다. 여기서:
- 메인 스레드는 작업(예: 파일 읽기 요청)을 작업 큐에 제출합니다.
- 스레드 풀은 큐에서 작업을 검색하여 실행합니다.
- 완료되면 작업자 스레드는 메인 스레드에 콜백 함수를 실행하도록 알립니다.
이를 통해 과도한 I/O 작업 중에도 메인 스레드는 가볍고 응답성을 유지합니다.
결론
애플리케이션 성능을 개선하려면 적절한 처리 방법과 기술 스택을 선택하는 것이 필수적입니다. 예를 들어 Node.js는 과도한 스레드 리소스 소비 없이 대량의 동시 네트워크 요청을 효율적으로 관리하는 비차단 I/O 모델로 인해 I/O 바운드 웹 애플리케이션 처리에 적합합니다. 반대로 CPU 바운드 작업의 경우 Java, C++ 또는 Go와 같은 멀티스레드 언어 및 플랫폼을 사용하여 멀티 코어 CPU 처리 기능을 활용하는 것이 더 효과적입니다.
Leapcell은 Node.js 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하세요.
무제한 프로젝트를 무료로 배포하세요
- 사용량에 대해서만 지불하세요. 요청도 없고, 요금도 없습니다.
탁월한 비용 효율성
- 사용한 만큼 지불하고 유휴 요금은 없습니다.
- 예: $25로 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
간편한 확장성 및 고성능
- 고도의 동시성을 쉽게 처리할 수 있도록 자동 확장합니다.
- 운영 오버헤드가 없어 구축에만 집중할 수 있습니다.
설명서에서 자세히 알아보세요!
X에서 팔로우하세요: @LeapcellHQ