개인 프로젝트 및 팀프로젝트를 하던 중 백엔드 서버와 DB 서버가 연결이 끊기거나 타임 아웃이 나는 경우가 종종 생겼다.
머리 한편으로는 커넥션풀의 문제겠거니하고 설정들에서 풀을 늘려주거나 시간을 늘리거나 하는등 임시방편으로 해결을 하였는데, 이번 기회로 커넥션풀의 개념과 설정 방법까지 정리해 보려고 한다.
해당 게시물을 유튜브 쉬운코드 님의 영상을 보고 정리한 글입니다.
들어가기 앞서
백엔드 서버와 DB의 통신은 네트워크를 공부해본 개발자라면 알고있는 TCP 연결을 기반으로 하고있다.
커넥션 open(연결)시에는 3-way handshaking이 일어나고, close(끊음)시엔 4-way handshaking을 한다.
즉 커넥션을 맺고, 끊는 과정에서 복잡한 일이 일어나고 비용도 크다는 의미이다. 이말은 서비스 성능에 좋짛 않다는 의미이다.
DBCP (Database Connection Pool)
그래서 매 요청마다 TCP 커넥션을 열고 닫는 비용을 절감하기 위해 나온게 DB 커넥션 풀이다.
DBCP는 말그대로 커넥션을 미리 연결지어놓고 pool에다가 보관을 하고 있는 다는 말인데, 직접 커넥션을 열고 닫는게 아니라 필요할때 pool에서 빌려쓰고 반환을 하는 방식이다.
DB 서버 & 백엔드 서버(DBCP)에서 중요 파라미터 (설정값)
DBCP의 파라미터, 즉 설정값은 백엔드 서버단에서 HicakiCP를 통해서도 할 수 있고, DB서버 (해당 글에선 MySQL)에서도 할 수 있다.
1. DB 서버 (MySQL)
✔️ max_connections : 클라이언트와 맺을 수 있는 최대 connection
- 해당 파라미터 값을 충분히 늘려두면, 나중에 서버 스케일 아웃시에도 수용이 가능하다. (해당 값이 60이라면, 서버를 1대부터 n대까지 늘려가며 적절한 값을 분배하여 서버를 설정할 수 있다.)
✔️ wait_timeout : 커넥션이 inactive (놀고 있을 때) 할 때 다시 요청이 오기까지 얼마의 시간을 기다린 뒤에 close 할것 인지
- DB 서버 입장에서 적절한 시점에 커넥션을 닫을 필요가 있다. 왜냐하면 무한정 대기할 수 없기 때문이다.
- DB 서버에서는 열려있따고 간주하고 하염없이 기다릴수도 있기 때문이다.
- 백엔드 서버단에서 비정상적 종료 / 네트워크 문제 등으로 반환을 못할 수 있기 때문에 설정해주어야한다.
2. 백엔드 서버 DBCP (HikariCP)
✔️ minimumIdle : pool에서 유지하는 최소한의 놀고있는, 커넥션 연결은 되어있지만 아직 작업 대기중인 커넥션 수
✔️ maxmumPoolSize : pool이 가질 수 있는 최대 커넥션 수 / idle과 active(in-use) 커넥션이 합쳐서 최대 수
1. 현재 idle 커넥션 <= minimumIdle
2. 전체 커넥션수 <= maximumPoolSize
EX.
minimumIdle = 2, maximumPoolSize = 4인 경우
active connection = 1, idle connection = 1라면 ?
1, 2의 조건을 만족하므로 connection++
active connection = 2, idle connection = 1라면 ?
1, 2의 조건을 만족하므로 connection++
active connection = 3, idle connection = 1라면 ?
1은 만족하지만 2는 만족하지 않으므로 더 이상 늘리지 않는다.
디폴트는 minimumIdle = 10, maximumPoolSize = 10로 설정되어 있다고 한다 👉 고정 pool size 권장'
✔️ maxLifetime : pool에서 커넥션의 최대 수명
✔️ connectionTimeout : 클라이언트가 pool에서 커넥션을 받기 위한 최대 대기 시간
커넥션풀 설정시 유의 사항
커넥션 풀을 크게 설정하면 메모리 소모가 크다. 하지만 많은 사용자가 대기 시간이 줄어든다.
커넥션 풀을 작게 설정하면 그 만큼 대기시간이 늘어난다. 하지만 적은 메모리를 사용한다.
Connection의 주체는 Thread이기 때문에 Thread와 함께 고려해야한다.
- Thread Pool 크기 < Connection Pool 크기
- Thread Pool에서 트랜잭션을 처리하는 Thread가 사용하는 Connection 외에 남는 Connection은 실질적으로 메모리 공간만 차지한다.
- Thread Pool 크기와 Connection Pool 모두 크기 증가
- Thread 증가로 인해 더 많은 Context Switching이 발생한다.
따라서 사용량에 따라 적정량의 커넥션 객체를 생성해 두어야 한다.
즉 자신의 서비스의 동시 접속자 수부터 서버 부하에 따라 크기를 조정해야 할 것이다.
적절한 커넥션 수를 찾기 위한 과정
- 우선 눈으로 지표를 확인할 수 있는 모니터링 환경을 구축하자 (서버 리소스, 서버 스레드 수, DBCP 등등)
- 백엔드 시스템에 부하 테스트를 진행하자 (Ngrinder, Jmeter 등등)
- 2번 과정에서 Request Per Second(단위 초당 몇 개의 요청 처리) / Avg Response Time(요청에 대한 처리의 평균 응답 시간) 지표를 확인 후, 병목 지점의 시간을 모니터링 환경으로 확인하자.
- 백엔드 서버, DB서버의, CPU, Memory등등 리소스 사용률을 확인한다.
- 백엔드 서버의 리소스(CPU) 사용률이 높아진다면 백엔드 서버를 스케일 아웃해보자
- 백엔드 서버는 괜찮은데, DB 서버의 리소스 사용률이 높아진다면 DB 서버에 Secondary / Cache Layer / Sharding 등을 고려하자.
- Thread per Requset(요청마다 스레드를 할당) 모델이라면 active thread 수를 확인하고 조절하자.
- 마지막으로 DBCP의 active connection 수를 확인하자.
- 사용할 백엔드 서버수를 고려하여 DBCP의 Max Pool Size를 결정하자.
모든 것은 부하/성능 테스트 등을 진행하여 병목이 시작되는 지점을 찾고, 그 지점을 모니터링 툴로 확인하자. 그리고 설정값들을 조금씩 바꿔서 반복해서 테스트해보자.
'DB' 카테고리의 다른 글
SQL 1. 데이터 정의어(DDL) (1) | 2023.02.04 |
---|---|
정규화(Normalization)!!!!!!!!!!!!!!!!!!!!! (1) | 2023.02.04 |
관계 데이터 모델의 기본 개념 (0) | 2023.02.04 |
데이터 베이스(DB) 설계 - 개념적 데이터 모델링 (0) | 2023.02.04 |
데이터 모델링을 ARABOZA (0) | 2023.02.04 |