실전 프로젝트 5주차. 오늘은 서비스 로직을 바꾸고 pinpoint로 병목현상이 어디서 발생하는지 분석했다.
코드와 로직 최적화를 계속 해봐도 딱히 개선점이 안나와서, Pinpoint를 APM으로 도입해서 병목현상이 어디서 발생하는지 알아내보려 했다.
calltree 메서드별 분석 결과 응답시간이 지나치게 길어지는 트랜잭션에서는 Hikari Datasource의 getConnection() 메서드에서 거의 대부분의 응답시간이 소요되는 것으로 나왔다.
getConnection()
: HikariCP에서 데이터베이스 연결을 가져오거나 생성하는 메서드. 일반적으로 데이터베이스 연결 풀에서 사용 가능한 연결을 가져오거나, 새로운 연결을 생성하여 반환한다. getConnection() 메서드를 사용하면 애플리케이션은 데이터베이스와 상호 작용할 수 있게 된다.
HikariCP
: java에서 가장 빠른 JDBC 커넥션 풀 라이브러리중 하나. JDBC 커넥션풀은 데이터베이스 연결을 관리하고, 미리 만들어진 연결 객체를 사용해 데이터베이스 연결을 최소화하고 성능을 향상시킨다.
기본 커넥션 풀 크기는 maximumPoolSize로 10개가 설정되어있다.
application.yaml 에서 아래와같이 커넥션풀 사이즈를 바꿀 수 있다.
spring:
datasource:
hikari:
maximumPoolSize: 100
pool size = Tn X (Cm -1) +1
Tn : 전체 쓰레드 수
Cm : 하나의 요청에서 필요한 커넥션 갯수
라는 공식이 있지만 본 프로젝트에서는 예매하기 로직에서 요청당 커넥션이 하나만 필요하기 때문에 이 공식은 맞지 않았다.
Pool Size = (cpu 코어 수 * 2) + DB 서버가 관리할 수 있는 동시 I/O 요청의 수
PostgreSQL에서 추천하는 커넥션 풀 사이즈 수인데
현재 2코어짜리 cpu를 2개쓰고있어 총 8~10정도가 나오는데 이는 기본 설정이라 패스했다.
공식으로 해결하지 못해 커넥션풀의 수를 조정해가면서 jmeter로 성능테스트를 진행했다.
커넥션풀 20개 : 7000ms 400tps
커넥션풀 50개 : 8000ms 380tps
커넥션풀 100개: 6319ms 519tps
커넥션풀 200개: 7329ms 458tps
커넥션풀 500개: 7471ms 474tps
tomcat으로 쓰레드풀을 바꾸니 오히려 성능이 저하되어 커넥션풀의 갯수만 바꿨다.
일단은 여러번의 테스트 결과 인스턴스 하나에서 커넥션풀 100개가 가장 성능이 좋았다.
그래서, main 환경에서 서버 2대로 진행해봤으나 성능에 큰 차이는 없었다.
hikari 커넥션 풀은 프로세스당 적용되는거니 서버가 2대가 되면 db에 연결되는 커넥션은 2배가 되는 것이 맞았다.
그리고 현재 사용하고있는 t3.small EC2에서 최대 66개의 동시 커넥션을 지원하는 것을 나중에 알게되어 오늘 테스트에는 반영하지 못했다. (<- 이 내용은 틀렸다. AWS 공식문서 읽어보니 그런 내용은 없다. gpt를 너무 믿지는 말자..)
이후로도 계속 추가 테스트를 진행해서 적절한 커넥션풀을 찾아보려 한다.