시작하기
Node.js 는 작은 작업이 빠르게 실행된다는 아이디어를 중심으로 태어났다.
오늘은 Promise Pool 패턴을 사용해서 Node.js의 특성을 더 잘 사용하는 방법에 대해 살펴본다.
일반적인 패턴
일반적으로 Node.js 에서 N개의 레코드를 동시에 처리하기위해 Promise.all
을 사용하여 처리한다.
const foo = async () => {
await bar(...);
};
await Promise.all([foo(), foo(), foo(), ...]);
여기서 일어나는 일을 상상해본다면, Promise.all 을 통해 foo 함수는 비동기를 통해 병렬로 실행되며, 타임라인은 아래와 같다.
(각 foo는 실행되는 속도가 동일하지 않다고 가정한다.)
Promise.all()
로 동시에 실행된 여러 함수 중 가장 늦게 끝나는 foo2 가 끝나야 비로소 Promise.all
의 실행이 종료된다. 따라서 메인 스레드는 기본적으로 아무것도 하지 않고 가장 느린 요청이 완료되기를 기다리게 된다.
Promise Pool 이란 뭘까?
Promise Pool 이란 아이디어는 Node.js 의 메인 스레드를 최대한 활용하는 방법이다. 활용도를 높이려면 가장 느린 호출이 완료될 때 까지 기다리지 않고, 첫 번째 호출이 완료되면 즉시 다음 호출을 예약하도록하여 실행되는 함수의 순서를 조밀하게 압축한다.
그림으로 살펴보면 아래와 같다.
그렇다면 Promise Pool 로 어떤걸 할 수 있을까?
- Promise Pool 의 동시성을 설정하여 처리량을 제어할 수 있다.
- Promise Pool 의 동시성을 설정해서 다운스트림 서비스의 부하를 관리한다.
- 어플리케이션의 성능을 높이고, CPU 의 유후 시간을 줄인다.
반대로는
- Promise Pool 의 pool 개수가 많아질수록 Promise.all 와 성능은 비슷해진다.
- foo 의 실행 속도가 항상 균일하다면 큰 성능상 이점을 얻지 못한다.