개발/Spring

[Spring] gc overhead limit exceeded 원인 찾기

hojak99 2020. 10. 12. 12:48

서버에서 gc overhead limit exceeded 라는 에러를 내뿜었다.

검색해보니 우선 해당 에러는 CPU 사용량중 98%이상이 GC가 작동되는 경우 gc overhead limit exceeded 가 발생이 된다고 한다.

이런 상황은 처음이라서 굉장히 당황했고 나 혼자 서비스 개발을 하니 주변 사람에게 물어볼 수도 없었다. 
우선 그래서 ec2 인스턴스에 접속해서 힙덤프를 떴고 MAT 이란 memory analyzer 를 이용해서 확인을 해 보았다.

 

분석기

 

hibernate 의 SessionFactoryImpl 이라는 오브젝트가 무려 589MB 나 했다. 

도큐먼트에 나와있는 SessionFactoryImpl 에 대한 설명이다.

Concrete implementation of the SessionFactory interface. Has the following responsibilites
- caches configuration settings (immutably)
- caches "compiled" mappings ie. EntityPersisters and CollectionPersisters (immutable)
- caches "compiled" queries (memory sensitive cache)
- manages PreparedStatements
- delegates JDBC Connection management to the ConnectionProvider
- factory for instances of SessionImpl

 

docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/impl/SessionFactoryImpl.html

 

SessionFactoryImpl (Hibernate JavaDocs)

 Session openSession(Connection connection, boolean flushBeforeCompletionEnabled, boolean autoCloseSessionEnabled, ConnectionReleaseMode connectionReleaseMode)           Open a session conforming to the given parameters.

docs.jboss.org

 

이걸 보면서 서버 내에서 영속화 된 엔티티가 많아서 그런게 아닐까? 라는 생각을 가지게 되었고, 내가 만든 기능들 중에 이런 기능들이 있는지 확인 해 보았다. 

우리 서비스 내에 이런 기능이 있다.

각각의 문제 데이터마다 유사한 문제 1~5개 씩을 뽑아야 하는데 이 때 문제 데이터 900개마다 5개 씩 유사한 문제를 뽑아달라는 요청을 약 1초마다 서버에 요청할 수 있었다.

쿼리도 가벼운 쿼리가 아니였고 몇 개의 테이블을 조인해야 하는 쿼리였으며 거의 1초에 한 번 씩 이런 요청들을 날리게 된다면 이렇게 영속화된 몇 백~몇 천개의 오브젝트를 gc 하는 과정에서 위와 같이 에러가 발생한 것 같다는 생각을 했다.

그리고 각 문제마다 5개씩 가져오는 쿼리를 매번 DB 에 요청하지 않고 db 에 한 번에 요청해서 서버에서 group by, filter 등을 이용해서 구현하기 때문에 성능 상 문제가 발생할 요지가 충분했다.

 

우선 클라이언트에서 각각의 문제들을 선택해 유사 문제를 뽑았을 때 결과값이 100문제가 초과 된다면 클라이언트에서 더 이상 문제 선택을 하지 못하도록해서 해결을 하도록 한다. 서버에서도 물론 예외처리를 해 놓으려고 한다. 


 

어쨌든 해당 기능에 대해서 이런 문제점이 있을지 생각을 했어야 했는데 급하게 개발만 하다보니 요런 부분은 신경을 못 썼다.
코드 레벨에 대해서만 성능을 생각하고 gc 이런건 생각을 하지 않아서 이런 일이 생긴 것 같으며, 이번 기회를 통해 한 번 서버 전체적으로 확인을 해 봐야 할 것 같다.

끝~

반응형