성능테스트와 Thread Pool & DBCP설정

이호석·2023년 8월 15일
1

서버 성능 향상

목록 보기
1/2

프로젝트를 마치고 어떻게하면 좀 더 보완을 할까 하던 도중 서버 모니터링에 대해서 공부하게 되었다. 모니터링을 접하고 나서는, 이 수치들이 역동적으로 변한 것을 보고 싶어서 서버 성능 테스트에 대해서 자연스레 검색하게 되었다. 서버 성능 테스트는 곧 서버 성능 향상으로 날 이끌었고 여기에는 서버늘리기, 캐시데이터 사용등 많은 방법이 있지만 기초적인 부분부터 시작하기로 하였다.

성능 테스트

부하 테스트는 성능 테스트 중 하나로, 임계치에 도달할 때까지 시스템의 부하를 지속적으로 증가시키면서 시스템을 확인하는 테스트이다. 부하 테스트는 테스트 중인 애플리케이션이 견딜 수 있는 부하의 양을 확인하기 위해 수행되며, 제대로된 부하 테스트는 지정된 테스트 케이스가 할당된 시간동안 오류없이 수행된 경우이다.

테스트 시행

테스트 목적

서버의 성능 향상 및 응답의 안정화

시스템 스펙

  • EC2 : t3.micro(1vCPU, 1 GiB RAM)
  • RDS : db.t3.micro(2vCPU, 1 GiB RAM) MySQL
    - max_connections : 60 (RDS 메모리에 따라서 달라진다)

테스트 시나리오

서버의 어떤 요청을 테스트할지 생각하다가 전에 포스팅한 숙소 예약부분은 낙관적 락 설정을 했기 때문에 부하 테스트와 어울리지 않다고 판단하여서, 우리 프로젝트의 요청이 가장 많을 것으로 예상되는 홈 화면을 테스트하기로 결정하였다.

부하 테스트이기에 루프 카운트는 20, 쓰레드 수는 200, Ramp-up은 1으로 설정했다. 이렇게 한다면 200개의 쓰레드를 1초에 나눠서 실행하게 된다.

1차 테스트

테스트 결과

Jmeter

  • 요약 보고서

  • TPS 그래프

그라파나

  • CPU 사용률

  • Threads
  • DBCP Connection

EC2

  • CPU 사용률

RDS

  • CPU 사용률

테스트 결과 분석

  • CPU 사용량이 지속적으로 100%대를 유지한 결과가 보인다.
  • Thread Pool의 max size를 따로 설정하지 않아서, Thread개수가 계속 늘어나다가 장애상황을 맞이했다. 적절한 값으로 수정해야한다.
  • Ramp-up 시간을 1초로 했으니 정상적인 서버라면 20초만에 끝내야 하지만, 약 3배가 늘어난 1분만에 테스트를 완료했다.
  • DB의 CPU사용률은 현저히 낮고, 대기 connection이 증가했으므로 DBCP의 수를 늘려야한다.
  • TPS는 평균 65 정도로 확인되었다.

-> Thread Pool과 DBCP의 적정값을 찾으면, 테스트 시간은 감소되고 TPS는 증가될 가능성이 높다.

DBCP 설정

본 포스트는 HikariCP 기준으로 작성됩니다.

DBCP를 설정해야 하는 이유

DBCP가 없다면 우리는 백엔드 서버가 Database서버로 쿼리를 요청을 할 때마다, 연결을 새로해야 하는데 이때 중요한 점은 이 연결은 TCP 기반으로 동작한다는 점이다. TCP 프로토콜은 연결지향적인 특징이 있기 때문에 연결을 시작하는 3-way handshake 요청, 연결을 닫는 4-way hanshake 요청이 있다. 근데 이 과정은 몇번의 요청이 오고가기 때문에 매 connection마다 이 과정을 수행한다면 적지 않은 비용이 및 시간이 소모될 것이고 이는 서버 성능의 저하로 이어지게 된다.

DBCP를 설정한다면 미리 DB서버와 설정한 만큼의 connection을 맺게 된다. 클라이언트로부터 요청이 왔을 때 보다 빠른 서비스를 위해서이다. 요청이 끝난 다음에 또 다른 클라이언트로부터 요청이 올 수 있기 때문에 바로 connection을 닫는게 아니라, minimum-idle, max-lifetime 같은 설정에 따라 닫게 된다.

MySQL 설정

  • max_connections
    MySQL에는 클라이언트와 맺을 수 있는 최대 connection수인 max_connections이 있다. 이 값은 위에서 확인했을 때 60이었으므로, HikariCP의 connection poolsize를 늘려야한다.
  • wait_timeout
    connection이 inactive할 때 다시 요청이 오기까지 wait_timeout만큼 기다린 뒤에 close할 것인지 결정. DB입장에서 아무런 요청이 없어도 계속 연결을 유지하는 것은 리소스 낭비이기 때문에 이 옵션이 필요하다.

HikariCP 설정

  • maximumPoolSize (default: 10)
    HikariCP 가장 중요한 파라미터는 maximumPoolSize이다. 이 설정에 따라서 DB connection pool의 사이즈가 무진장 늘어날 수 있기 때문이다. maximumPoolSize은 idle(대기상태)과 active connection의 수를 합친 최대 수이다.

  • minimum-idle (default : maximum-pool-size)
    connection pool에서 최소로 유지하는 connection수 이다. HikariCP에서는 최대 성능을 위해서 maximumPoolSize과 같은 수를 유지하는 것이 좋다고 한다.

  • maxLifeTime(default : 1800000 - 30 minutes)
    pool에서 connection의 최대수명이다. maxLifeTime을 넘기면 idle일 경우 pool에서 바로 제거, active인 경우 pool로 반환된 후 제거된다. maxLifeTime은 MySQL의 wait_timeout보다 몇초 짧게 설정해야한다. 왜냐면 만약 maxLifeTime과 wait_timeout 둘다 60초라 했을 때, 59초 쯤 클라이언트에서 요청이 온다면 백엔드 서버는 요청을 받고 DB에 요청한다면, DB 서버에서 받을 때는 이미 60초가 지나있을 수 있기 때문이다.

  • 설정 코드

spring:
  datasource:
    hikari:
      maximumPoolSize: 30	#최대 connection size
      maxLifetime: 295000	#ms 단위 295초
      poolName: Hikari		

RDS 파라미터 그룹에서 wait_timeout을 300초로 해주었다.

Thread Pool 설정

Thread Pool이란

스레드는 동일한 메모리 영역에서 생성 및 관리가 이루어지지만, 생성하거나 수거할 때 커널 오브젝트를 동반하는 리소스이므로 생성 비용이 크게 발생한다. 스레드 풀은 작업처리에 사용되는 스레드를 제한된 개수만큼 정해놓고 작업 큐에 들어오는 작업들을 하나씩 스레드가 맡아 처리한다. 스레드는 많으면 너무 많은 스레드가 cpu의 자원을 두고 경합하게 되므로 처리속도가 느려질 수 있고, 적으면 cpu자원을 최적으로 활용하지 못해 마찬가지로 처리속도가 느려질 수 있다. 그렇기에 스레드는 적절한 수로 유지되는 것이 가장 좋다.

Tomcat Thread Pool설정

스프링부트를 사용하기 때문에 Tomcat Thread Pool을 설정하려면 단순히 application.yml만 설정해주면 된다. Thread Pool Size 보다 DBCP connection 수가 커야 하기 때문에 2개 작게 설정해주었다.

server:
  tomcat:
    threads:
      max: 28			#최대 스레드 개수
      min-spare: 28		#최소 액티브 상태인 스레드 개수
    accept-count: 200	#스레드가 전부 사용중일 때 대기 큐에 넣을 수 있는 요청 개수

Thread Pool Size 보다 DBCP connection 수가 커야 하는 이유

2차 테스트

1차 때와 동일한 설정이므로 바로 결과 확인.

테스트 결과

23.08.11 - 15:42

전과 같은 조건

JMeter

  • 요약 보고서

  • TPS 그래프

그라파나

  • CPU 사용률

  • DBCP

  • Threads

EC2

  • CPU

RDS

  • CPU

테스트 결과 분석

  • 이전과 다르게 로그의 끊김 현상이 발견됐다. DBCP와 스레드 조절이 예상한 만큼 효과적이지 않았다.
  • Jmeter의 Ramp-up이 1초여서 그런지 CPU 100%는 감수해야 할 듯하다. JVM에 할당된 CPU사용량이 아쉬울 뿐이다.
  • 테스트 시간은 34초로 1차 테스트보다 반 정도 줄어들었다.
  • TPS는 117로 확인되었다.
  • DBCP와 Thread Pool 조정으로 엄청나게 좋아졌다고 볼 수는 없어서, 다른 사람들처럼 Redis 같은 NoSQL을 사용해볼까 하다가, 현재 인프랩 CTO이신 이동욱님이 유튜브에서 '서버 환경 개선도 좋지만 쿼리 튜닝도 매우 좋은 경험이다'라고 하셔서 쿼리 튜닝을 하기로 결정하였다.

쿼리 튜닝

0개의 댓글