두 시점을 비교하라 — Differential Flamegraph가 필요한 이유
단일 플레임그래프(Flamegraph)는 애플리케이션이 어느 메서드에서 얼마나 시간을 소비하는지 직관적으로 보여준다. 그러나 실무에서 맞닥뜨리는 질문은 대부분 비교 형태다. "배포 이후 응답 속도가 왜 느려졌는가?", "리팩토링 전후 CPU 사용이 실제로 줄었는가?", "GC 튜닝이 할당량에 영향을 미쳤는가?" 이런 물음에 단일 스냅샷 하나로 답하기는 어렵다.
Differential Flamegraph는 두 개의 JVM 녹화(recording)를 입력으로 받아, 두 시점 사이에 무엇이 증가하고 무엇이 감소했는지를 색상과 너비 차이로 표현한다. 변경 전(baseline)과 변경 후(candidate)를 나란히 분석하는 대신, 차이(diff) 자체를 하나의 그래프로 렌더링하기 때문에 병목이 이동하거나 새롭게 생긴 지점을 즉시 식별할 수 있다.
Jeffrey Microscope에서 Differential Flamegraph 활용하기
Jeffrey Microscope는 두 개의 JFR(Java Flight Recorder) 파일을 업로드하면 자동으로 차분 분석을 수행한다. 결과 그래프에서 빨간색으로 강조된 프레임은 candidate 녹화에서 샘플 비중이 늘어난 구간이고, 파란색 프레임은 반대로 줄어든 구간이다. 색이 진할수록 변화폭이 크다는 의미다.
실무 워크플로를 예로 들면 다음과 같다.
- 배포 전후 비교: 신규 배포 직전과 직후 각각 5분간 JFR을 수집하고 두 파일을 비교한다.
- 부하 구간 고립: 특정 트래픽 스파이크 구간만 녹화해 평상시 프로파일과 비교하면 스파이크 원인 메서드를 바로 찾아낼 수 있다.
- 튜닝 효과 검증: JVM 옵션 변경이나 커넥션 풀 조정 후 할당(allocation) 변형 diff를 확인하면 메모리 압력이 실제로 줄었는지 수치로 확인할 수 있다.
# JFR 수집 예시 (OpenJDK 11+)
jcmd <pid> JFR.start duration=300s filename=before.jfr
# 변경 적용 후
jcmd <pid> JFR.start duration=300s filename=after.jfr
두 파일을 Jeffrey Microscope에 업로드하면, 단순 비교로는 놓치기 쉬운 콜스택 깊숙한 변화도 시각적으로 드러난다.
단일 플레임그래프와의 차이 — 언제 Diff를 써야 하는가
단일 플레임그래프는 "지금 어디가 느린가"를 파악할 때 유효하다. 반면 Differential Flamegraph는 "무엇 때문에 달라졌는가"라는 원인 추적에 특화되어 있다. 특히 다음 상황에서 위력을 발휘한다.
- 코드 변경 없이 트래픽 패턴만 바뀐 경우: 같은 빌드라도 요청 분포가 달라지면 핫스팟이 이동한다. Diff로 어떤 엔드포인트 처리 경로가 부각됐는지 확인할 수 있다.
- 라이브러리 버전 업그레이드: 내부 구현이 바뀐 서드파티 의존성이 성능에 미치는 영향을 정량적으로 파악하기 어렵지만, Differential Flamegraph는 변경된 콜스택 경로를 색상으로 직접 보여준다.
- 점진적 성능 저하 추적: 일주일 전 녹화와 오늘 녹화를 비교하면 특정 배치 잡이나 캐시 만료 로직이 점차 무거워지고 있는지 조기에 포착할 수 있다.
// 예: 직렬화 라이브러리 교체 전후 할당량이 의심될 때
// JFR allocation profiling 활성화
-XX:StartFlightRecording=settings=profile,filename=candidate.jfr
중요한 것은 두 녹화의 수집 조건을 최대한 동일하게 유지하는 것이다. 녹화 시간, 부하 수준, JVM 워밍업 상태가 다르면 diff 결과에 노이즈가 섞여 잘못된 결론을 내릴 수 있다.
정리
- Differential Flamegraph는 두 JFR 녹화를 비교해 성능 변화의 원인 메서드를 색상과 너비 차이로 즉시 시각화한다.
- 배포 전후, 튜닝 전후, 트래픽 이상 구간 등 비교 맥락이 명확한 상황에서 단일 플레임그래프보다 훨씬 효과적이다.
- 정확한 분석을 위해 두 녹화의 수집 조건(시간, 부하, 워밍업)을 일치시키는 것이 선행 조건이다.