보통의 경우, Logic 서버와 DB 서버의 통신은 TCP 기반으로 이루어 진다.
이 2 개의 서버 사이에서 쿼리를 던지고 전, 그리고 쿼리에 대해 응답을 한 후에는 각각 Connection(3-way)을 미리 맺고
쿼리 수행이 다 끝나게 되면, 그 Connection을 닫아 준다(4-way).
이러한 과정은 높은 데이터 신뢰성을 보장하는 반면에, 시간 비용이 많이 든다는 단점이 존재한다.
( Logic 서버는 계속해서 쿼리를 요청하게 될 것이고, API 마다 한 번의 쿼리가 아니라, 여러 번의 쿼리를 날리게 되는 경우
가 있다. 이러한 경우 시간 비용은 매우 매우 큰 단점이다.)
위와 같은 단점을 해결하기 위해 나온 것이 DBCP이다.
DBCP의 동작 방식
Logic 서버에서 API 요청을 하기 이전에, 미리 여러 개의 Connection을 맺어 놓는다.( 위 그림에서는 3개의 Connection을 미리 생성해 놓음 ). 이 여러 개의 Connection들을 하나의 Pool 안에 보관을 해 둔다.
이것을 Connection Pool(CP)라고 부른다.
CP가 만들어 지면, 이제 Logic 서버는 DB 서버에 API 요청을 하게 된다.
1. CP에서 놀고 있는 Connection을 조회한다( get Connection )
2., 1에서 획득한 Connection을 통하여 쿼리를 수행하고, DB 서버로부터 응답을 받는다.
3. close Connection을 통하여 사용하던 Connection을 CP에 반환을 한다.
( 이름이 close이지만, Connection을 해제하는 것이 아니라 Pool에 반환을 한다.)
4. API 요청에 대한 응답 완료!
-> Connectino을 재사용하여 Connectino을 열고 닫는 시간을 절약함으로써 시간 비용을 줄이는 효과!
DBCP 설정 방법 ( MySQL을 기준으로 설명!)
1. DB Side에서의 설정
DB 서버의 max_connectinos 변수에 대해 알아 보자.
만약 , Logic 서버에 트래픽이 4개이고, CP에 Connectino이 4개 있고, max_connections도 4개라고 가정을 해 보자!우선, 동작에는 문제가 없다.그러나 만약 트래픽이 100개 였다고 가정을 해보자.그렇게 되면, Logic 서버의 cpu, 메모리 사용량이 증가하며 과부하가 걸려, 원활한 서비스 제공이 불가능해진다.이때, 자체적인 회의를 거쳐 원활한 서비스를 제공하기 위하여 Logic 서버를 1대 증설하여 트래픽을 분산을 시킬려고 결정이 났다고 가정해보자.기존의 Logic 서버의 코드를 그대로 올린다고 하였을 때, Logic 서버는 트래픽에 응답을 하기 전에 DB 서버와 4개의 Connection을 맺으려고 할 것이다.그러나 문제가 여기서 발생을 한다.우리는 DB 서버에 Connection의 수를 max로 4개로 설정을 하였다. 그렇기에 새로 증설한 Logic 서버는 DB와 Connectino을 하나도 맺지 못하게 된다.-> 고로, DB 서버의 max_connections 변수는 적절하게 설정을 해줘야 한다. 그래야 Logic 서버를 증설을 한다고 해도 에러가 나지 않고 트래픽을 분산시킬 수가 있다.
이번에는 wait_timeout 변수에 대해 알아보자 이런 시나리오를 가정을 해보자.Logic 서버에서 하나의 Connectino을 get하여 쿼리 요청을 보냈고, DB 서버가 이 요청에 대해 응답을 보냈다고 하자!더 이상 그 Connection으로 보낼 요청이 없다면, Logic 서버는 close Connectino 요청을 하여, DB 서버가 Connectino을 반납을 하게 된다.그러나 만약 어떠한 이유로 close Connection 요청을 하지 않게 되면 DB 서버는 처리할 아무런 쿼리가 없는데도 불구하고 Connection을 쓸데 없이 가지고 있는 꼴(이러한 상태를 idle 상태라고 한다)이 되어 버린다. 이러한 것을 방지하기 위해서, Connectino에 일정 시간 요청이 없을 경우 자동으로 Connectino을 자동 반납하게 하는 변수설정이 wait_time 변수 설정이다. 만약 MySQL에서 wait_time을 60초라고 설정을 하였다고 하자.58초가 지날 무렵에 요청이 도착을 하게 되면 wait time을 다시 0으로 초기화하여 다시 60초까지를 counting하게 된다. ( IDLE 상태 : 아무 것도 하지를 않고 다음 요청이 올 떄까지 무한정 기다리고 있는 상태)
2. Logic 서버 Side의 설정(DBCP의 설정, Hicari CP를 기준으로 설명)
minimumIdle이 2개로 설정이 되어 있기 때문에, 초기에 Logic 서버가 실행이 되면, CP에는 2개만의 Connection이 생성이
된다. 이 이후에 트래픽이 1개 들어 왔다가 가정해보자.
Idle Connection 2개 중 1개가 사용되어서 Idle Conncetion은 총 1개만 남아 있다.
minimumIdle을 2개로 설정을 했기 때문에, pool에서 존재하는 idle Connectino은 최소 2개여야 한다.
고로, 아래의 그림과 같이 추가로 1개의 idle Connectino이 만들어 진다.
위 상황에서, 트래픽이 또 1개가 더 들어 왔다고 해보자.
이때에도 총 idle Connection이 1개가 되었으므로, hikari CP는 추가로 1개의 idle Connection이 만들어 지게 된다.
또 트래픽이 1개 더 들어 오게 되면 똑같은 이유로 idle Connection이 추가로 1개 생성되어 CP에는 총 4개의 Connection이
존재하게 된다.
이때에도 idle Conncetion이 1개이니깐 추가로 idle Connectino이 더 추가가 될까??
그렇지 않다.
우리는 maximumPoolSize를 4개로 설정을 하였기에, 비록 idle connectino이 현재 1개밖에 없다고 하더라도,
더이상 idle Conncetion을 생성하지 못한다.
이러한 이유로 [ maximumPoolSize의 우선순위가 minimum Idle보다 높다] 라고 표현을 한다.
기존의 트래픽이 모두 처리 완료되고, 더 이상의 트래픽이 들어 오지 않는다고 하면,
hikari CP는 idle Connection을 다시 2개로 줄인다.
Hikari CP 공식 메뉴얼에 따르면,
minumumIdle의 수와 maximumPoolSize의 수를 동일하게 설정을 하라 라고 권장을 한다.
이 말을 즉슨, CP 안의 존재하는 Connectino의 갯수가 트래픽의 여부와는 관게 없이 항상 일정하다 라는 것을 의미를 한
다.
위 예시와 같이 트래픽이 들어오고 나옴에 따라서 Connectino이 생성/해제가 되는 비용이 상당하기에 원할한 서비스 제공
을 못할 수도 있기 때문이다.
이번에는 maxLifetime 변수에 대해서 알아 보자.
여기서 주의해야 할 것은, active Connection인 경우에는 반드시 DB 서버가 Connection을 Pool로 반환을 해야지만 제거가
된다는 것이다.
에를 들어, 1개의 Connection이 쿼리를 처리하기 위하여 active 상태가 되었다고 하자!
이 Connection이 쿼리 수행을 마쳤는데, 코드 상의 어떠한 버그로 인해 Pool로 반환이 되고 있지 않다고 가정해 보자!
이때 maxLifetime을 60초라고 했을 때, 이 Connection은 60초가 넘었음에도 불구하고 Pool로 반환이 되지 않았기 때문에
원래라면 Pool로 반환이 되어 진작에 제거되었어야 할 Connectino이 60초를 넘어서도 계속해서 살아 있게 된다.
근데 위 예시에서는 DB 서버의 wait timeout을 60초라고 설정을 해으므로, 60초가 지난 시점에서 DB 서버는 강제적으로
Connection을 비로소 Pool에 반환을 하게 된다.
근데 이떄에 또 다른 쓰레드가 이 Connection을 통해서 수행해야 할 쿼리가 1개 남은 상황이였다면, 원래라면 실행되었어
야 할 그 쿼리가 실행되지 못하고 예외를 던지게 된다. ( 원래 쓰레드와 Connectino은 1:1 관계이지만, 여기서는 설명을 위
해 예외적으로 1개의 Connectino을 2개의 쓰레드가 사용한다고 가정을 하자! )
이래서, Connection을 Pool로 반환을 잘 시켜주는 것이 중요하다!!!
( poolSize가 고정되어 있어도, 제거가 된다. 그러나 빠른 속도로 다시 Conncetion이 생성이 된다.)
* maxLifeTime DB의 connection time limit보다 몇 초 짧게 설정해야!!!
maxLifettime = 60초, wait_timeout = 60초이므로, 각 서버는 하나의 Conncetion에 대해서 동시에 0초부터 카운팅을 시작하여 60초가 되면, Connection을 해제할 것이다.그런데 57초쯤에 트래픽이 하나가 들어와서 쿼리가 DB 서버로 전달이 되었다고 하자.Logic 서버 입장에서는 maxLifeTime 안에 도착한 트래픽이므로 정상적으로 쿼리를 요청할 것이다.그리고 그 쿼리가 만약에 61초에 DB 서버에 도착을 했다고 가정을 하자.이때는 이미 timeout 시간을 넘겼기 때문에, 쿼리가 DB에 도착했을 떄에는 Connection이 이미 반환된 상태이므로,
DB 입장에서는 이 요청을 수행할 Connectino이 존재하지 않는 것이다.
고로, maxLifeTime을 timeout보다 몇 초 짧게 설정하는 것이 중요하다.
이번에는 conncetionTimeout 변수에 대해 알아보자
CP의 Connection들이 이미 다 사용 중인 상태에서 새로운 트래픽이 들어 오게 되면, Connectino을 받기 위하여 대기를 해
야 한다. 그러나 이 Connection을 할당받자고 무한정 대기를 할 수 없으니, connectionTimeout을 설정하여 예를 들어, 30초
를 기다리면 그 트래픽에 대해 예외를 던져 주게 된다.
'CS 과목(CS科目) > 데이터 베이스(データベース)' 카테고리의 다른 글
ORM 프레임워크를 사용하는 이유(ex. JPA..) (0) | 2023.04.04 |
---|---|
28. NoSQL( MongoDB, Redis, etc ) (0) | 2023.03.09 |
Holder 기법!!!! (0) | 2023.02.18 |
26.partitioning ,sharding, replication (0) | 2022.12.17 |
25. DB INDEX (0) | 2022.12.16 |