비상 비상 문제가 발생했다
대량의 내역을 집계하기 위한 처리를 하던중, 서버의 메모리가 급격하게 찼고 몇번의 재시작을 해야하는 이슈가 발생했다.
원인 : Query Plan Cache
heap dump 파일을 생성해 분석해보니 몇몇의 메모리가 가득찬 친구들이 보였다.
- org.hibernate.internal.SessionFactoryImpl
- org.hibernate.engine.query.spi.QueryPlanCache
- org.hibernate.engine.query.spi.HQLQueryPlan
- BoundedConcurrentHashMap
- ...
참조하고있는 것들을 모두 보면 공통적으로 나오는것 QueryPlanCache 이었다.
뭐하는 놈인데에엑
JPQL/HQL을 실행할땐 생각보다 비용이 크다.
HQL 문자열
-> 렉싱
-> 파싱
-> AST 트리 생성
-> 시맨틱 분석
-> SQL 생성
-> 파라미터 메타 데이터 추출
-> 실행
문자열을 추출, 정보를 습득, SQL로 생성하는 이 과정이 생각보다 길어 캐싱이 필수가 되는데
IN절의 파라미터 수가 달라질때 메모리 문제가 발생할 수 있다.
- ... WHERE id IN (?, ?) → 캐시 키 A
- ... WHERE id IN (?, ?, ?) → 캐시 키 B
- ... WHERE id IN (?, ?, ?, ?) → 캐시 키 C
이렇게 파라미터 수에 따라 캐시가 잡히기 때문에 IN 파라미터가 만약 1000개라면? 1000개의 캐시가 생성되는것이다.
무거운 쿼리라면 이게 폭발해서 메모리가 폭발하고 나도 폭발하고 서버도 폭발하는 사태가 폭발폭발열매먹은 미스터파이브가 되버린다.
심지어 캐싱으로 강한 참조가 엮여있기 때문에 Old 영역에서도 퇴출이 어렵다.
그럼 어떻게 해결해 다스케떼요오
해결방법은 의외로 간단하다. 이름하야
hibernate.query.in_clause_parameter_padding 설정
spring:
jpa:
properties:
hibernate:
query:
in_clause_parameter_padding: true
이렇게 설정하면 된다.
padding 이라는 말에서 알 수 있는데 IN 절의 파라미터 개수를 2제곱 값(2, 4, 8, 16, 32 ...)으로 맞춰서
마지막 값으로 복제해서 채워주는 설정이다.
예를 들면
WHERE id IN (1, 2, 3); 쿼리를
WHERE id IN (1, 2, 3, 3); 으로 변신!
추가로 plan_cache_max_size 설정도 있다.
이는 쿼리플랜캐싱 최대개수를 설정하는 값인데 디폴트는 2048이다.
하지만 보통 그전에 메모리가 미스터파이브가 되버리니 이또한 낮춰주는게 좋아보인다.
결과 : 해결해부았쓰요
실제로 간단한 설정이지만 효과는 톡톡히 봤다.
메모리가 90퍼센트 넘게 개선이 되었으며, 처리 시간또한 70% 낮아지는 놀라운 효과였다
'Spring' 카테고리의 다른 글
| ZGC 왜 좋은데 (4) | 2026.05.02 |
|---|---|
| JPA 비관적 락 (Pessimistic Lock) (1) | 2024.10.03 |
| Spring Controller 중복 호출되는 이슈 (0) | 2024.07.28 |
| Spring JPA @Id 복합키 설정 (0) | 2022.10.24 |
| Maven Jar 빌드 외부 dependency 추가 (0) | 2022.09.27 |