파티셔닝을 활용한 Node 앱 응답성 향상
Source: Dev.to
문제 설명
우리는 데이터베이스에서 문서를 가져와 변환하고 결과를 반환하는 단일 GET 엔드포인트를 가지고 있습니다. 일부 클라이언트에 대해 많은 양의 문서를 가져와야 하는데, 이 과정이 Node의 이벤트‑루프 스레드를 차단합니다. 이벤트 루프가 차단되면:
- 애플리케이션이 새로운 요청에 응답하지 않게 됩니다.
- Liveness 프로브가 실패하고 Kubernetes가 파드를 재시작합니다.
- 작고 빠른 요청도 예측할 수 없는 지연을 겪습니다.
재시작이 매우 빈번해졌으며, 페이지네이션을 추가하고 이 레거시 엔드포인트를 폐기하는 것은 간단히 할 수 없습니다. 최소한의 코드 변경으로 재시작을 방지하고 애플리케이션 응답성을 개선할 수 있는 단기 해결책이 필요합니다.
해결책
Node.js는 파티셔닝(partitioning) 이라는 기법을 제공합니다. 큰 동기식 처리를 작은 작업으로 나누고 각 작업 사이에 이벤트 루프에 양보(yield)하도록 함으로써 다른 요청을 처리할 수 있게 합니다.
// Return a Promise that resolves on the next tick, letting the event loop process other work.
function yieldToEventLoop(): Promise {
return new Promise((resolve) => setImmediate(resolve));
}
for (let i = 0; i < docs.length; i += smallBatchSize) {
const batch = docs.slice(i, i + smallBatchSize);
// Process the current batch
output.push(...processBatch(batch));
// Yield to the event loop before processing the next batch
await yieldToEventLoop();
}
각 배치 후에 await yieldToEventLoop() 를 삽입하면 이벤트 루프가 다른 요청을 처리할 수 있어, 하나의 무거운 요청이 전체 프로세스를 굶주리게 하는 상황을 방지합니다.
핵심 요점
- 이 방법은 처리 속도를 빠르게 하거나 CPU 사용량을 줄이는 것이 아닙니다.
- 애플리케이션의 응답성을 향상시킵니다.
- 작업을 청크로 나누고 이벤트 루프에 양보하면 프로세스가 살아남고 일시적인 완화를 제공합니다.
서버가 무거운 계산을 수행한다면 Node.js가 적합한 선택인지 고민해 보세요. Node는 I/O‑바운드 워크로드에 강점이 있지만, 비용이 많이 드는 CPU‑바운드 작업은 다른 환경에서 처리하는 것이 좋을 수 있습니다. 자세한 내용은 Node.js 문서의 파티셔닝 섹션을 참고하십시오.