Tomcat의 스레드 수에 따른 성능 테스트를 Apache Jmeter로 확인해보자.
@RestController
public class JdbcController {
@Autowired
private JdbcRepository jdbcRepository;
@GetMapping("/jdbc")
public String test() throws Exception {
jdbcRepository.executeSleepQuery();
return "test";
}
}
@Repository
public class JdbcRepository {
private JdbcTemplate jdbcTemplate;
@Autowired
public JdbcRepository(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void executeSleepQuery() throws Exception {
jdbcTemplate.execute("SELECT SLEEP(1)");
}
}
1초 Sleep 쿼리 실행 후 문자열을 반환하는 컨트롤러를 1개 구성하였다.
Hikari CP 커넥션 관련 설정은 다음과 같이 설정하였다.
# Connection 최대 갯수 (30개)
spring.datasource.hikari.maximum-pool-size=30
# Connection 점유 대기 최대 시간 (30초)
spring.datasource.hikari.connection-timeout=30000
스레드 갯수: 200개
스레드 갯수: 500개
스레드 갯수: 1,000개
스레드 갯수가 500개인 환경에 비해 처리량이 낮고 27.4%의 에러가 발생한 것을 확인할 수 있다.
부하 테스트 실행 후 약 30초뒤에 콘솔에서 위와 같은 에러 메시지가 반복적으로 기록되고 있었는데, 이러한 결과가 발생한 이유는 다음과 같다.
1. Connection pool 사이즈를 늘린다.
더 많은 Connection pool 사이즈를 갖게되면 스레드의 대기시간이 줄어들게 되고 connection timeout이 발생하기 전에 커넥션을 획득할 수 있으므로 문제를 해결할 수 있다.
다만 너무 크게 설정하면 그만큼 커넥션을 미리 생성해서 갖고 있으므로 리소스 낭비가 될 수 있으며, 트래픽이 증가한다면 커넥션 고갈현상이 동일하게 발생하므로 무조건적인 해결방법은 아니라고 볼 수 있다.
2. Connection timeout 시간을 늘린다.
Connection timeout 시간을 늘리면 이전보다 대기하는 시간이 길어지게 되므로 timeout이 발생하기 전에 커넥션을 획득하게 되면서 문제를 해결할 수 있다.
하지만 그만큼 대기시간이 증가하게 되어 응답시간이 늦어지는 단점이 있다.
3. Tomcat 스레드 수를 환경에 맞게 적절하게 설정한다.
Tomcat 스레드 수를 너무 적게 설정하면 다중 사용자 환경에서 처리시간이 늦어질 것이고
위 예제처럼 너무 많이 설정하면 잦은 Context Switching이 발생하며, SQLTransientConnectionException 발생 확률이 높아지기 때문에 애플리케이션의 상황에 따라
적절하게 설정하는 것이 중요하다.