프로젝트를 마치고 어떻게하면 좀 더 보완을 할까 하던 도중 서버 모니터링에 대해서 공부하게 되었다. 모니터링을 접하고 나서는, 이 수치들이 역동적으로 변한 것을 보고 싶어서 서버 성능 테스트에 대해서 자연스레 검색하게 되었다. 서버 성능 테스트는 곧 서버 성능 향상으로 날 이끌었고 여기에는 서버늘리기, 캐시데이터 사용등 많은 방법이 있지만 기초적인 부분부터 시작하기로 하였다.
부하 테스트는 성능 테스트 중 하나로, 임계치에 도달할 때까지 시스템의 부하를 지속적으로 증가시키면서 시스템을 확인하는 테스트이다. 부하 테스트는 테스트 중인 애플리케이션이 견딜 수 있는 부하의 양을 확인하기 위해 수행되며, 제대로된 부하 테스트는 지정된 테스트 케이스가 할당된 시간동안 오류없이 수행된 경우이다.
서버의 성능 향상 및 응답의 안정화
서버의 어떤 요청을 테스트할지 생각하다가 전에 포스팅한 숙소 예약부분은 낙관적 락 설정을 했기 때문에 부하 테스트와 어울리지 않다고 판단하여서, 우리 프로젝트의 요청이 가장 많을 것으로 예상되는 홈 화면을 테스트하기로 결정하였다.
부하 테스트이기에 루프 카운트는 20, 쓰레드 수는 200, Ramp-up은 1으로 설정했다. 이렇게 한다면 200개의 쓰레드를 1초에 나눠서 실행하게 된다.
Jmeter
그라파나
EC2
RDS
-> Thread Pool과 DBCP의 적정값을 찾으면, 테스트 시간은 감소되고 TPS는 증가될 가능성이 높다.
본 포스트는 HikariCP 기준으로 작성됩니다.
DBCP가 없다면 우리는 백엔드 서버가 Database서버로 쿼리를 요청을 할 때마다, 연결을 새로해야 하는데 이때 중요한 점은 이 연결은 TCP 기반으로 동작한다는 점이다. TCP 프로토콜은 연결지향적인 특징이 있기 때문에 연결을 시작하는 3-way handshake 요청, 연결을 닫는 4-way hanshake 요청이 있다. 근데 이 과정은 몇번의 요청이 오고가기 때문에 매 connection마다 이 과정을 수행한다면 적지 않은 비용이 및 시간이 소모될 것이고 이는 서버 성능의 저하로 이어지게 된다.
DBCP를 설정한다면 미리 DB서버와 설정한 만큼의 connection을 맺게 된다. 클라이언트로부터 요청이 왔을 때 보다 빠른 서비스를 위해서이다. 요청이 끝난 다음에 또 다른 클라이언트로부터 요청이 올 수 있기 때문에 바로 connection을 닫는게 아니라, minimum-idle, max-lifetime 같은 설정에 따라 닫게 된다.
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초로 해주었다.
스레드는 동일한 메모리 영역에서 생성 및 관리가 이루어지지만, 생성하거나 수거할 때 커널 오브젝트를 동반하는 리소스이므로 생성 비용이 크게 발생한다. 스레드 풀은 작업처리에 사용되는 스레드를 제한된 개수만큼 정해놓고 작업 큐에 들어오는 작업들을 하나씩 스레드가 맡아 처리한다. 스레드는 많으면 너무 많은 스레드가 cpu의 자원을 두고 경합하게 되므로 처리속도가 느려질 수 있고, 적으면 cpu자원을 최적으로 활용하지 못해 마찬가지로 처리속도가 느려질 수 있다. 그렇기에 스레드는 적절한 수로 유지되는 것이 가장 좋다.
스프링부트를 사용하기 때문에 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 수가 커야 하는 이유
1차 때와 동일한 설정이므로 바로 결과 확인.
23.08.11 - 15:42
전과 같은 조건
JMeter
그라파나
EC2
RDS