Floney

[플로니] 서버야 왜 자꾸 죽니

딤섬뮨 2023. 10. 3. 15:44
728x90

최근 플로니 앱의 론칭을 앞두고 베타테스트에 들어갔다.
그래서 그런지..AWS 프리티어를 사용하는 서버가 자꾸 터진다.
 
여러 원인이 있겠지만 로그는 다음과 같이 찍힌다


결국 같은 백엔드 팀원과 비상 회의가 열렸다.
 
(1) 추측 1 - HIkari pool이 모자란걸 보아, 한 번의 요청에 여러 Pool이 쓰이나?

근데 난 Hikari Pool이 뭔지부터 알아야했다.

1. 전통적인 WAS 와 DB 연결 방법
회사에서 레거시 시스템을 담당하는 중이라 아주 잘 안다 ㅎㅎ..
보통 드라이버를 로드 하고, conntection을 열어서 query를 직접 날린다
근데, 매 쿼리마다 이렇게 하면 비용이 많이 든다. DB나 웹서버나 서로서로 TCP 커넥션을 생성해야 함
 
2. Connection Pool

Hikari Pool : DB랑 연결해주는 Connection Pool 오픈 소스 
Connection Pool은 미리 WAS 가 시행될 때 DB 연결을 위해 객체를  만들어서 POOL에 담아뒀다가 하나씩 꺼내 쓴다.
 
(1) 서버의 부하를 줄여준다.
(2) 한정적인 서버 자원 관리가 된다
 
3. 그럼 무작정 크게 만들면 좋은가?
자원 사용 효율적 X  : 사용하지 않고 남는 Connection은 작업을 하지 못하고 놀게 되어, 메모리만 차지한다. 
DISK 측면 : DB에서는 HDD 하나당 하나의 I/O를 처리하기에 Blocking이 발생, 병렬 처리가 아니니깐.. 앞에 끝날 때까지 기다려야 함
DB 측면 : context switching에 오버헤드 발생
 
HikariCP Dead lock에서 벗어나기 (이론 편) | 우아한 형제들 기술블로그 (woowahan.com)

 

HikariCP Dead lock에서 벗어나기 (이론편) | 우아한형제들 기술블로그

{{item.name}} 안녕하세요! 공통시스템개발팀에서 메세지 플랫폼 개발을 하고 있는 이재훈입니다. 메세지 플랫폼 운영 장애를 바탕으로 HikariCP에서 Dead lock이 발생할 수 있는 case와 Dead lock을 회피할

techblog.woowahan.com

관련 블로그를 읽고 pool을 두번 쓰이는 곳이 있나..?라는 내 추측에 힘을 실어 코드를 다시 살펴보았다.


* 서비스 계층 메서드
* repository 계층 메서드
 
둘 다 @Transactional을 붙여놓은 게 있어서 혹시 이것 때문인가? 싶었다.
하지만, 팀원분의 말로는 우리의 프로젝트 트랜잭션은 한 개가 달려있어도 새로운 Transaction이 생기지 않는다고 알려주셨다. 창피하게도 이제야 알았다니!
 
@Transactional을 달면, 예상 동작 방식은 아마 이럴 것이다
 

public class UserService{
	public Long registerUser(User user){
    Connection connection = dataSource.getConnection();
    try(connection){
    	connection.setAutoCommit(false); //트랜잭션 auto 꺼놓았을 경우
        connection.ommit();
    }catch(Exception e){
    	connection.rollback()
    }

 
근데 내가 작성한 코드 위에 이런 코드를 얹기란 어려운 법이니깐, 스프링은 Proxy를 이용한다.
Proxy는 딱 DB의 connection 열고 닫기를 관여하고 나머지는 그 안에서 우리가 짠 코드에 역할을 위임한다.
이렇게 하면 Controller입장에서는 Service가 Proxy인지 Reals인지 알 수 없게 된다
 
이러한 원리로 만약 Proxy가 열리고 그 안에서 다른 @Transactional이 붙은 메서드를 만나면 Proxy가 열리지 않는다. 그러면 @Transactional을 두 번 써서 pool이 모잘랐다! => 이 가설은 틀렸다.
 
 
 2. 서버가 튕기는 시간 == 빌드할 때??

서버가 죽을 때는 다음과 같이 CPU 사용량이 90%까지 치솟는다..(왜 그래...)
아주 가아아아끔 해당 시간이랑 코드가 머지돼서 빌드할 때랑 동일할 때가 있었다.
그래서, 저 문제가 나타났던 시간에 머지되었던 코드를 Re-Build 해봤지만 너무 정상작동했고,,
머지될 시점뿐만 아니라 그냥 튕기는 날도 있어서 애매한 가설이라 탈락
 
3. 램 문제이다
 
EC2를 프리티어로 사용하고 있는 Floney의 서버는 치명적인 단점이 있다.
바로 작고 소중한 램.. AWS의 EC2는 30GB SSD와 1GB의 메모리를 가지고 있다.,..
현재 EC2의 메모리 사용량을 보니깐 약 53% 정도의 메모리를 사용하고 있는 것을 확인했지만 이 정도론 램에 문제가 없을 것 같다. + 메모리가 부족했다면 Out Of Memory를 뱉지 않았을까.?
 
4. 결론
근본적인 원인을 파악할 수 없었다. 어떤 특정 현상에서 재현이 되는 상황도 아니어서


(1) 우선 램 메모리 이슈는 잠재적인 문제이니, swap 메모리를 할당하여 메모리를 늘려준다
(2) 우선 지켜본다! 다행히 조치 이후에 서버는 잘 동작 중이다.(진짜 램 문제였을까?)
(3) 실제 배포할 때, 모니터링 서버를 구축하거나..(비용 측면 고려하여)하도록 하자

(이번 상황 같은 일을 대비하고자 2024.1월 기준 모니터링 서버를 구축했다 -

2024.01.05 - [Floney] - [플로니] 에러에 대비하는 서비스 만들기)


 


팀원이 어느날 원인을 알려주셨다(짝짝짝)
우리의 예상대로 github action을 통해 서버가 빌드 될때, 문제가 있었다.
 

Ruby가 실행하는 메모리가 엄청나다
끝난 뒤에 메모리 양을 보면 현재는 swap을 이용해 메모리를 확보해놔서 괜찮지만, 그 전에는 아주 메모리가 부족했을것이다.

 

728x90