성능 장애는 계층별 지표를 함께 봐야 근본 원인을 찾을 수 있다
성능 문제는 애플리케이션 레이어 하나만 봐서는 원인을 찾기 어렵다. CPU가 여유 있는데 응답이 느리면 DB에 문제가 있을 수 있고, DB 쿼리는 빠른데 지연이 생기면 JVM GC가 원인일 수 있다. 계층별로 지표를 함께 보는 이유가 여기 있다.
기본적으로 챙겨야 할 지표들
- 시스템 레벨: CPU 코어별 사용률, 메모리 힙 상태 + GC 패턴, 디스크 I/O
- 네트워크: 응답 시간, 처리량
- 애플리케이션: TPS, 에러율, 응답 시간 분포
이 중 하나라도 이상 신호가 보이면 그 계층부터 깊게 파고 들어간다.
실전에서 자주 마주친 상황들
DB 쿼리가 느릴 때
SELECT * 처럼 불필요한 컬럼까지 가져오는 쿼리, 인덱스를 타지 못하는 조건, 적절한 LIMIT 없이 전체를 스캔하는 쿼리가 주범인 경우가 많다.
-- 느린 쿼리: 불필요한 컬럼 전체 조회, LIMIT 없음
SELECT * FROM orders o
JOIN order_items oi ON o.id = oi.order_id
WHERE o.created_at > '2023-01-01';
-- 개선: 필요한 컬럼만, 조건 추가, LIMIT 설정
SELECT o.id, o.status, oi.product_id
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
WHERE o.created_at > '2023-01-01'
AND o.status = 'COMPLETED'
LIMIT 1000;JVM GC 튜닝이 필요할 때
Full GC가 자주 발생하거나 GC 시간이 길면 응답 지연의 직접적인 원인이 된다. G1GC로 전환하고 GC 로그를 남겨 패턴을 분석하는 게 출발점이다.
-XX:+UseG1GC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/var/log/gc.log대용량 배치 처리가 느릴 때
건당 처리에서 병렬 처리로 전환하면 처리량을 크게 높일 수 있다. 단, 스레드 풀 크기는 서버 리소스에 맞게 설정해야 한다.
@Scheduled(fixedRate = 1000)
public void processBatch() {
List<Data> dataList = repository.findLimit(1000);
ExecutorService executor = Executors.newFixedThreadPool(5);
for (Data data : dataList) {
executor.submit(() -> processData(data));
}
executor.shutdown();
}캐시가 필요할 때
조회 빈도가 높고 변경이 드문 데이터라면 캐시를 도입한다. Spring의 @Cacheable을 활용하면 DB 부하를 줄이면서 응답 속도를 개선할 수 있다.
@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new ProductNotFoundException(id));
}모니터링 체계 구성
Prometheus + Grafana 조합이 현재 가장 많이 쓰이는 방법이다. Spring Actuator와 연동하면 JVM, DB 커넥션 풀, HTTP 요청 지표를 한 곳에서 확인할 수 있다.
scrape_configs:
- job_name: 'spring-actuator'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']성능 장애를 맞닥뜨렸을 때 가장 위험한 건 특정 계층만 보고 결론을 내리는 것이다. “DB 느리네, 쿼리 튜닝하면 되겠다”로 시작했다가 실제 원인이 GC 정지였던 경우도 있다. 지표를 계층별로 같이 보는 습관이 그 방황을 줄여준다.
연결 (이유)
- JVM 메모리 구조를 이해해야 성능 문제의 원인을 찾을 수 있다 — JVM 힙·GC 모니터링이 성능 계층 분석의 핵심 구성 요소이며, GC 로그 분석이 메모리 병목 진단의 시작점
- WAS 환경에서는 세션-쿠키 설정과 JVM 메모리 튜닝이 안정성을 좌우한다 — WAS 튜닝은 모니터링 과정에서 찾은 병목을 실제로 해결하는 방법론
- DB 통신 횟수를 줄이는 것이 성능 개선의 핵심이다 — DB 계층 병목이 성능 문제의 가장 흔한 원인이며, 쿼리 분석이 계층별 진단의 실천적 사례
출처(참고문헌)
- 네이버 클라우드. “대규모 서비스 모니터링 노하우.” D2
- 당근마켓. “당근마켓 서버 OS 모니터링-Memory.” 당근마켓 블로그