비교할 문제
대형 JSON 병목에서 확인할 질문은 JSON.stringify 자체 비용과 실제 요청의 event loop delay·응답 p99를 어떻게 분리해 측정할까입니다. 동일한 field와 JSON byte를 반환하고 오류·timeout 계약을 유지합니다. 결과값, 순서, 오류 처리와 부수 효과가 다르면 같은 성능 비교가 아닙니다. 먼저 두 후보가 같은 일을 하는지 작은 입력으로 확인합니다.
원인 분석과 재현
JSON.parse와 JSON.stringify는 큰 payload에서 event loop를 막고 한꺼번에 memory를 할당할 수 있습니다.
payload 1KB·1MB·50MB, 동시 요청 1·100에서 stringify 시간, output byte, event loop p99, heap·external·RSS를 봅니다. runtime version, 운영체제, CPU와 memory 제한도 결과와 함께 기록합니다.
비교 질문은 JSON.stringify 자체 비용과 실제 요청의 event loop delay·응답 p99를 어떻게 분리해 측정할까입니다.
| 후보 | 유리한 조건 | 함께 치르는 비용 |
|---|---|---|
| main thread stringify | 작고 제한된 payload | 큰 입력은 event loop를 동기적으로 점유 |
| 응답 field·page 축소 | consumer가 전체 data를 쓰지 않음 | API와 cache 계약 변경 |
| worker/streaming format | 충분히 큰 CPU 비용·첫 byte 개선 | transfer, framing과 backpressure 복잡성 |
import { performance } from 'node:perf_hooks';
const payload = Array.from({ length: 100_000 }, (_, id) => ({ id, name: `item-${id}` }));
for (let i = 0; i < 10; i += 1) JSON.stringify(payload); // warm-up
const samples = []; let bytes = 0;
for (let run = 0; run < 30; run += 1) {
const start = performance.now(); const body = JSON.stringify(payload);
samples.push(performance.now() - start); bytes ^= body.length;
}
samples.sort((a, b) => a - b);
console.log({ median: samples[15], p95: samples[28], bytes });
// event-loop delay와 응답 p99는 별도의 HTTP 부하 테스트에서 동시에 수집합니다.
해결 방안과 판정
warm-up과 측정 구간을 나누고 여러 번 반복합니다. 서비스 지연은 median과 p95를, 처리량 비교는 단위 시간당 완료 수와 오류율을 함께 기록합니다. CPU time, allocation, RSS·heap, GC, I/O 중 이 작업에 직접 관련된 지표만 선택합니다. 이 코드는 stringify 시간만 잽니다. event loop delay와 응답 p99는 HTTP 부하 테스트에서 별도로 수집하고, DB 조회·network 전송과 구분해 해석합니다.
차이가 반복 실행의 흔들림보다 작다면 더 단순하고 읽기 쉬운 구현을 선택합니다. 차이가 충분히 크더라도 실제 요청 전체의 지연과 자원 사용이 개선되는지 확인한 뒤 적용합니다.
공식 문서와 적용 범위
문서의 기본값과 동작은 version에 따라 달라질 수 있습니다. 현재 runtime·framework version, 실제 입력과 요청 흐름에서 다시 확인합니다.