EC2
서버에 배포한 스프링 부트 프로젝트가 오늘 아침까지는 잘 돌아가다가 저녁에 확인을 해보니 요청을 처리 못하고 있었다. 바로 EC2
서버를 확인해보니 인스턴스 상태 검사에서 CPU사용량 99.9% 때문에 오류를 경고하고 있었고, 서버가 죽어있었다. 서버를 다시 재부팅하고 스프링 부트 프로젝트의 로그를 확인해보니 글 아래에 첨부한 Thread Starvation
로그를 엄청 뿜어대고 있었다. 원인을 파악해보려고 상황을 분석했다. Thread Starvation
의 발생 시간과 CPU 사용량이 99.9%로 증가시간이 일치하였다. 스프링 부트 프로젝트의 Thread Starvation
현상 때문에 EC2
서버가 죽은 것으로 보였다.
Spring Boot
공식 문서 링크Hikari
공식 링크위 링크의 블로그에서 Thread
와 Connection
관계, 스레드풀 작동방식, Spring Boot
공식 문서에서의 Default min-spare Thread의 수(10개), max Thread의수 (200개), Hikari
의 Default maximumPoolSize(10개)를 확인하고 나니 오류의 원인을 깨달았다. 상황을 정리하면 아래와 같다.
Thread
들이 올라가서 작업을 하게 되고, 그러다 한 Thread
내의 별도 Transaction
에서 추가적인 SQL문 실행이 필요해지면서Thread
가 Connection
을 더 필요로 하는 상황이 생겼다. 우리 스프링 부트 프로젝트에서 Thread
가 Connection
이 더 필요한 이유는 다음과 같다.Service
의 메소드가 사용될 때 Service
의 트랜잭션이 시작하고, Service
의 메소드에서 Repository
를 사용할 때 Repository
의 트랜잭션이 시작했다. 김영한님의 자바 ORM 표준 JPA 프로그래밍
따르면 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 사용한다고 한다. 즉, 우리는 요청을 처리하는 한 개의 Thread
에서 Service
의 트랜잭션과 Repository
의 트랜잭션 때문에 2개의 영속성 컨텍스트
가 생겼고 2개의 영속성 컨텍스트
를 위한 엔티티 매니저
도 2개가 생겼으므로, Connection
이 2개가 필요한 상황인 것이다.Connection
이 없는 상황이 발생해서 Thread
는 작업을 끝내지도 못했고, Thread
가 데드락에 걸렸다.Thread
가 없어 NIO Connector
가 계속 Thread
를 생성했다.Connection
이 없어서 Thread Starvation
상황으로 이어졌다. Thread
가 추가로 생성되어야 해결되는게 아니라 Connection
의 수를 늘려야 해결되는 상황이었다. 그래서 요청 작업이 발생하면 남은 Thread
가 없고 NIO connector
가 요청 작업을 위한 Thread
를 계속 생성하는 상황이 반복하게 되었다. Thread
가 작업을 못 끝내고 계속 CPU를 사용하고, 새로운 Thread
들이 최대 개수까지 생성하게 되면서 스프링 부트 프로젝트의 CPU 사용량이 극단적으로 99.9%까지 올라가게 된 것이다.Thread
들이 Connection
을 할당받지 못했으므로 스프링 부트 프로젝트는 아래에 첨부한 Thread Starvation
로그를 계속 출력하고, EC2
서버는 CPU 99.9% 사용량으로 인해 인스턴스 상태 검사를 통과하지 못하고 죽어버린 것이다.해결 방법으로는 HikarilCP
에서 제공하는 최적의 Maximum Pool Size를 구하는 공식을 사용했다.
우리 스프링 프로젝트의 Thread
수는 10개이다. 한 Thread
가 작업을 하면서 필요로 하는 Connection
의 수는 2개이다. 위 공식에 대입하면 우리 프로젝트의 최적 pool size
는 10*(2-1)+1
로 11개이다. 11개 이상의 Connection
을 제공하면 오류가 해결될 것이다.
spring.datasource.hikari.maximum-pool-size=20
위의 코드를 application.properties
에 추가해서 Connection
의 개수를 20개로 늘렸다.
[HikariPool-1 housekeeper] WARN com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=5m30s164ms615µs200ns)
Connection
이 부족하게 된 원인을 잘못 파악했다. 아래의 링크에 원인을 다시 파악하고 정정했다. 아래의 링크를 확인하면 된다.
잘보았습니당