숏컷 코드
import { performance, PerformanceObserver } from "node:perf_hooks";
const observer = new PerformanceObserver((items) => {
for (const entry of items.getEntries()) {
console.log(entry.name, entry.duration);
}
});
observer.observe({ entryTypes: ["measure"] });
performance.mark("load:start");
await loadConfig();
performance.mark("load:end");
performance.measure("load config", "load:start", "load:end");| 목적 | 먼저 볼 API |
|---|---|
| 짧은 구간 수동 측정 | performance.mark() + performance.measure() |
| 단순 시간 차 계산 | performance.now() |
| 측정 결과 수집 | PerformanceObserver |
| 함수 호출 시간 측정 | performance.timerify(fn) |
측정 단위
performance.now()는 프로세스 안에서 단조 증가하는 고해상도 시간을 제공합니다. 벽시계 시간인 Date.now()와 달리 시스템 시간이 바뀌는 문제를 덜 받으므로 짧은 구간 성능 측정에는 performance.now()가 더 적합합니다.
const startedAt = performance.now();
await runJob();
const durationMs = performance.now() - startedAt;반복 측정과 관측성 연결이 필요하면 mark와 measure가 낫습니다. 시작점과 종료점을 이름으로 남기고, 측정 결과를 observer나 로깅 계층에서 처리할 수 있습니다.
performance.mark("query:start");
await queryDatabase();
performance.mark("query:end");
performance.measure("db query", "query:start", "query:end");언제 쓸까
부팅 단계, 설정 로딩, DB query wrapper, 외부 API 호출 wrapper처럼 병목 후보가 명확한 곳에 먼저 넣습니다. 모든 함수에 무작정 측정을 넣기보다 "느린 요청의 어느 단계가 느린가"를 분리할 수 있는 경계에 붙이는 편이 효과적입니다.
async function timed(name, task) {
const startedAt = performance.now();
try {
return await task();
} finally {
console.log(name, performance.now() - startedAt);
}
}관측성 시스템과 연결하려면 PerformanceObserver에서 entry를 모아 로그, metric, diagnostics channel로 넘길 수 있습니다. 측정 코드는 비즈니스 로직의 반환값을 바꾸지 않아야 합니다.
timerify
performance.timerify(fn)은 함수 호출 시간을 performance entry로 남깁니다. 이미 함수 경계가 분명하고 observer 기반으로 수집하고 싶을 때 적합합니다.
import { performance, PerformanceObserver } from "node:perf_hooks";
const observer = new PerformanceObserver((items) => {
console.log(items.getEntries());
});
observer.observe({ entryTypes: ["function"] });
const measured = performance.timerify(async function loadUser(id) {
return findUser(id);
});
await measured("u1");단순한 한두 구간은 performance.now()가 더 읽기 쉽습니다. 반복적인 계측과 통합 수집이 필요할 때 mark, measure, observer 쪽으로 확장합니다.
주의할 점
성능 측정 코드는 비용이 0이 아닙니다. hot path에 과도하게 mark를 남기면 측정 자체가 지연과 메모리 사용을 만들 수 있습니다. 샘플링, 경계 축소, observer 정리를 함께 설계하십시오.
측정값은 원인 그 자체가 아니라 단서입니다. CPU 바운드 지연, event loop 지연, 네트워크 대기, DB 대기 시간이 같은 숫자로 보일 수 있으므로 구간 이름을 구체적으로 나누고, 필요한 경우 event loop delay나 외부 metric과 함께 봐야 합니다.
참고 링크
1 sources