비교할 문제
stream backpressure에서 확인할 질문은 Node.js에서 buffer 전체 처리와 stream 처리의 비용을 어떻게 비교할까입니다. 같은 byte와 오류를 처리하고 backpressure, abort와 결과 순서를 동일하게 구현합니다. 결과값, 순서, 오류 처리와 부수 효과가 다르면 같은 성능 비교가 아닙니다. 먼저 두 후보가 같은 일을 하는지 작은 입력으로 확인합니다.
원인 분석과 재현
Writable이 false를 반환하면 producer는 drain을 기다려야 하며 pipeline은 error propagation과 cleanup을 함께 처리합니다.
payload 1KB·1MB·100MB, 동시 요청 1·50·500에서 throughput, p99, event loop delay, heap·external·RSS를 기록합니다. runtime version, 운영체제, CPU와 memory 제한도 결과와 함께 기록합니다.
비교 질문은 Node.js에서 buffer 전체 처리와 stream 처리의 비용을 어떻게 비교할까입니다.
| 후보 | 유리한 조건 | 함께 치르는 비용 |
|---|---|---|
| 전체 buffer/readFile | 작고 상한이 분명한 payload | 동시 대용량 입력에서 peak memory가 곱해짐 |
| stream pipeline | 큰 데이터와 일정한 memory 사용 | chunk 경계, backpressure와 오류 전달을 구현 |
import { createReadStream } from 'node:fs';
import { createHash } from 'node:crypto';
import { pipeline } from 'node:stream/promises';
import { Writable } from 'node:stream';
const hash = createHash('sha256');
let bytes = 0;
const sink = new Writable({
write(chunk, _encoding, callback) { bytes += chunk.length; hash.update(chunk); callback(); },
});
await pipeline(createReadStream('large.bin', { highWaterMark: 64 * 1024 }), sink);
console.log({ bytes, digest: hash.digest('hex'), rss: process.memoryUsage().rss });
해결 방안과 판정
warm-up과 측정 구간을 나누고 여러 번 반복합니다. 서비스 지연은 median과 p95를, 처리량 비교는 단위 시간당 완료 수와 오류율을 함께 기록합니다. CPU time, allocation, RSS·heap, GC, I/O 중 이 작업에 직접 관련된 지표만 선택합니다. stream은 무조건 더 빠른 것이 아니라 peak memory와 첫 byte 시간을 관리하는 도구입니다. 처리량뿐 아니라 writable backpressure와 취소 뒤 descriptor 정리를 확인합니다.
차이가 반복 실행의 흔들림보다 작다면 더 단순하고 읽기 쉬운 구현을 선택합니다. 차이가 충분히 크더라도 실제 요청 전체의 지연과 자원 사용이 개선되는지 확인한 뒤 적용합니다.
공식 문서와 적용 범위
문서의 기본값과 동작은 version에 따라 달라질 수 있습니다. 현재 runtime·framework version, 실제 입력과 요청 흐름에서 다시 확인합니다.