웅글웅글
article thumbnail

들어가면서 이번 글에서는 저번에 조회 성능 개선을 진행한 API의 TPS를 더 개선하기 위해 HikariCP 설정을 서버에 맞게 최적화해보도록 하겠습니다.

HikariCP란?

HikariCP는 가벼운 용량과 빠른 속도로를 가진 JDBC 커넥션 풀 프레임워크입니다.

스프링에서는 직접 커넥션을 관리할 필요 없이 자동화된 기법들을 제공하는데 SpringBoot2.0 이전에는 tomcat-jdbc를 사용하다가 2.0 이후부터는 HikariCP를 기본 옵션으로 사용하고 있습니다.

커넥션 풀은 데이터 베이스와 연결된 커넥션을 미리 만들어 두고 이를 pool로 관리합니다.

 

커넥션 풀은 위 사진처럼 동작합니다. 만약 커넥션 풀의 크기가 작아 대기 상태인 스레드가 많은 상황이라면 커넥션 풀의 크기를 늘려서 해결할 수 있습니다.

적절한 커넥션 풀 설정하기

위에 내용을 보면 커넥션 풀이 부족해지면 크기를 늘려 해결할 수 있다고 했는데 그렇다면 무조건 커넥션 풀을 크게 잡으면 되지 않을까요? 결론은 틀렸습니다. 왜냐하면 스레드의 수보다 커넥션 풀의 크기가 크다면 사용하지 않는 커넥션들이 존재하기 때문에 메모리 낭비가 발생할 수 있습니다. 그렇다면 어떻게 설정해야 할까요?

HikariCP의 공식문서

HikariCP에서 데드락을 방지하기 위한 커넥션 풀 공식을 알려줍니다.

  • PoolSize = Tn x (Cm - 1) + 1
    • Tn : 전체 스레드 수
    • Cm : 하나의 Task에서 동시에 필요한 커넥션 수

예를 들면, 세 개의 스레드(Tn = 3)가 존재하고, 각 스레드는 일부 작업(Cm = 4)를 하기 위해 4개의 연결이 필요합니다. 공식을 적용하여 계산하면 아래와 같은 결과가 나옵니다.

 

Pool Size = 3 x (4 - 1) + 1 = 10

 

커넥션 풀의 사이즈를 10으로 지정하면 데드락을 방지할 수 있습니다. 그럼 이제 실제 프로젝트에 적용해 보도록 하겠습니다.

Mysql 공식문서에는 600명의 사용자를 대응하는데 15개의 20개의 커넥션 풀이 필요하다고 합니다.

부하 테스트로 적절한 설정 찾기

실제 프로젝트에서는 직접 부하 테스트를 진행하여 병목이 생기는 지점을 찾고 커넥션 풀의 사이즈를 조절해가며 적절한 커넥션 풀 사이즈를 찾도록 하겠습니다.

 

기본 커넥션 풀 사이즈(10) 상태에서 VUser 300으로 부하 테스트를 진행했을 때 TPS 400에서 대기 시간이 길어졌습니다.

 

TPS 400에서의 대기 시간 (ms)

이제 커넥션 풀 사이즈를 다양하게 조정한 후 부하 테스트를 진행해보겠습니다.

  • DBCP = 5 : TPS 366
  • DBCP = 10 : TPS 433
  • DBCP = 12 : TPS 506
  • DBCP = 15 : TPS 473

 

커넥션 풀 사이즈를 12로 설정했을 때

이렇게 데이버 베이스의 커넥션 풀 사이즈만 조정했을 뿐인데 TPS가 천차만별 차이입니다. 커넥셔 풀의 사이즈를 크게 잡았을 때 오히려 TPS가 낮아지기도 하는 것을 알 수 있습니다.

 

따라서 현재 상황에 맞는 커넥션 풀 사이즈를 설정하는 것이 중요합니다.

타임 아웃 설정하기

커넥션 풀 사이즈와 별개로 커넥션에 타임 아웃을 따로 설정할 수 있습니다. 기본 값으로 30초입니다. 이는 만약 커넥션을 가져오지 못하는 상황일 때 30초를 응답 없이 기다려야 에러 메세지를 확인할 수 있습니다. 하지만 그렇다고 타임 아웃을 너무 짧게 설정하면 커넥션을 가져올 수 있는 상황에서도 못 가져올 수 있는 상황이 발생할 수 있습니다.

 

그렇기 때문에 타임 아웃 또한 적절한 시간을 설정해 주는 것이 중요합니다. 오래 걸리는 작업도 존재할 수 있기 때문에 필자는 5 ~ 10초 사이로 설정해 주었습니다.

마무리

이번에 HikariCP 설정을 최적화해보면서 많은 것을 느꼈습니다. 가장 크게 느낀 것은 문제를 해결하기 위해 새로운 기술을 도입하는 것보다는 먼저 근본적인 문제를 해결하는 것입니다. 단순 TPS를 올리기 위해 바로 캐시를 적용하는 것이 맞을까요?

그렇지 않습니다. 캐시를 적용하기 전에 먼저 쿼리의 속도를 개선해 보거나 혹은 커넥션 풀 사이즈를 조절할 수 있습니다. 그럼에도 목표 TPS 도달하지 못했으면 또 다른 방법을 시도해 보고 캐시 도입도 고려해 보는 것입니다. 쉽게 말해 적은 비용으로 큰 성과를 만들어 내는 것이 중요한 것 같습니다.