성능 테스트를 통해 더 나은 환경을 구성해 보자

무지성개발자·2024년 1월 8일

성능 테스트를 해보자

서론

부끄럽지만 현업에서 성능 테스트를 해본적이 없다. 때문이 이 테스트 과정이 매끄럽지 않게 느껴질 수 있을 것이다.
성능 테스트를 배워가는 과정이라고 생각해주시고 봐주시면 감사하겠습니다.

힙, 스레드 덤프를 적용한 테스트 였다면 더 좋은 테스트가 되었을 테지만 그건 다음 숙제로 생각 해봐야겠다.

목표

성능 테스트를 직접 해본 경험이 없어 어떤 값을 목표로 하는지에 대한 감이 없어 50명의 유저가 동시성문제가 가장 많은 작업을 동시에 10초 정도 작업해도 문제가 없을 정도로 기준을 잡았다.

테스트 조건

  • app 서버성능 제한
    • cpu : 1개
    • 메모리 : 512M ~ 1G
    • Tommcat Thread : max 50개
  • 테스트 시나리오
    • 로그인
    • 내 정보 확인
    • 재화 충전
    • 동물 예약(재화 소진 및 로그작성)

테스트 시나리오는 데이터의 정합성이 가장 중요한 재화와 이동 및 유저와 1:1 관계로 예약 되어야하는 동물 예약을 선택했다.

사용 툴 : Jmeter

Jmeter와 ngrinder와 무엇을 사용할지 고민했지만 Jmeter를 선택했다.

이유를 꼽자면 ngrinder의 경우 컨트롤러, agent를 각각 설치해야하는 반면 Jmeter는 설치가 간단하여 시작하기 아주 쉽다는 점이 었다. 비교적 GUI가 좋지 않고, 추가로 보고 싶은 그래프는 Plugin 설치가 필요하다는 단점도 존재했지만 시작하기가 간단하다는 점, 결과값을 HTML로 제공해 준다는 점에서 충분히 사용할 만하다고 느꼈기 때문이다.

서버 1대 DB 1대


NCP와 Jenckins를 이용한 CI/CD

결과

서버 1대와 DB 1대로 테스트하니 접근을 못하는 요청이 실패한 것을 볼수 있다.

Tomcat Thead가 50개로 제한되었는데 1초당 50명씩 늘어가는 유저를 테스트를 하다보니 커낵션을 기다리던 요청들이 대기시간이 만료되어 실패했다고 생각이 되었고 서버를 2대로 늘려보기로 결정했다.

서버 2대 DB 1대


Nginx로 로드벨런싱하기
Redis를 사용하여 다중서버 환경에서 session 유지하기

결과


서버를 2대로 늘렸지만 달라진게 없다. 계속 테스트 후 내린 결론은 다음과 같다.

  • HikariCP의 Connection pool을 따로 설정을 하지 않아 default : 10으로 설정 되어있음.
  • Tomcat Thead가 50개씩 들어와도 실제로 DB작업은 10개씩 처리가 됨.
    때문에 HikariCP의 Connection pool을 늘려서 다시 테스트 해봤다.

결과(Connection pool : 100개)


Connection pool을 늘리니 MySQL의 커넥션이 다 차서 이용되는걸 확인 할 수 있었다.

실패율이 한 자리 수로 줄긴했지만 여전히 연결에 실패한 요청이 있었다. Connection pool을 늘리는 것 만으로는 드라마틱한 결과는 얻을 수 없었으니 이번엔 Replica DB를 구성해 Read/Write DB에 가해지는 부하를 나눠보기로 했다.

서버 2대 DB 2대


DB 이중화 구성 후 요청 분산(feat.Mybatis)
쿼리 캐싱을 위한 Server PrepareStatement

결과


연결이 실패한 요청이 5%로 줄었지만 여전히 목표하는 50명의 유저가 동시성문제가 가장 많은 작업을 동시에 10초 정도 작업해도 문제가 없을 정도에는 만족스럽지 못한 결과다.

이번엔 MySQL + HikariCP에서 기본적으로 사용하지 않는 쿼리 캐싱 기능을 켜서보기로 했다.

결과(쿼리 캐싱 : true)

dataSource:
  hikari: 
    cachePrepStmts: true           
    prepStmtCacheSize: 250        
    prepStmtCacheSqlLimit: 2048      
    useServerPrepStmts: true    
    useLocalSessionState: true   
    rewriteBatchedStatements: true
    cacheResultSetMetadata: true  
    cacheServerConfiguration: true
    elideSetAutoCommits: true
    maintainTimeStats: false

위 설정은 HikariCP + MySQL의 권장옵션이라고 한다.

드디어 설정한 목표에 도달한 결과를 얻었다.

첫 번째 그래프는 Transactions Per Second이며 대부분 150ms에 처리되어 크게 느리다고 생각되지 않는다.
두 번째 그래프는 Response Time이며 1초에 가까운 시간까지 걸리는 걸 확인했다.
세 번째 그래프는 Through put에 관한 그래프인데 초록색 그래프가 처리량에 관한 부분인데 서버의 처리량에 비해 평균 작업량의 차이가 많이 나는걸 확인 할 수 있다.

실제 50명의 유저가 동시에 현재 테스트 시나리오를 10초 동안 할 리는 없지만, 이벤트 같이 사람이 몰리는 상황이라고 가정한다면 1초의 응답시간은 괜찮다고 생각하지만 그렇지 않다면 유저의 입장에선 약 1초정도의 기다리는 경험은 썩 유쾌 하지 않을 텐데 아쉬운 부분이다.

개인 피드백

제일 마지막 이미지는 서버의 처리량(Through put)에 관한 그래프인데 처리량과 평균값을 대조해보면 많이 차이가 나는 걸 보니, 서버의 성능에 비해 DB쪽 처리가 따라가질 못한다고 생각된다. 따라서 DB작업을 좀 더 개선할 방향을 생각 해봐야할 것 같다.

또한 Jmeter에서 제공해주는 그래프만으로 결과값과 개선방향을 생각하고 서버와 DB를 늘려봤는데, 테스트를 하고 나니 엑츄에이터를 좀 공부해서 Thread Dump, Heap Dump도 확인하고 개선방향을 잡았다면 더 좋지 않았을까? 하는 아쉬움이 있다.


한 줄평 : 테스트를 어떤 방식으로 진행하고 개선해 나갈지 나름의 방법으로 적용하고 시도해봤지만, 경험 부족으로 인한 매끄럽지 않은 진행이 아쉬웠다.

profile
no-intelli 개발자 입니다. 그래도 intellij는 씁니다.

0개의 댓글