Web 서비스를 하나 만든다라고 생각을 해봤을 때 Client와 Server는 HTTP로 서로 통신을 할 것이다. 만일 RESTFul APi 로 구성을 했다라고 하면 Server는 JSON 형식의 데이터를 보낼것이고 Client는 그 JSON형식을 데이터를 통해선 화면을 렌더링 할것이다. 그렇다면 Server와 Data가 있는 DB는 어떻게 통신을 할까? SpringBoot 프로젝트를 몇가지 진행을 하면서 무지성으로 HikariCP를 써왔는데 이번 글에서는 HikariCP가 관리하는 DBCP란 무엇인지 살펴보도록 하자.
Server와 DB는 어떻게 통신을 하는가?
기본적으로 WAS와 DB는 DB 드라이버를 거쳐 서로 TCP 통신을 하게 된다. TCP의 장점은 연결 지향적이고 packet의 순서의 신뢰를 보장하는 등 다양한 장점이 있지만 기본적으로 한번 연결을 구성하기 위한 3way handshake의 비용이 너무 크다. 오죽하면 HTTP/3 에서는 이러한 TCP를 버리고 UDP로 구성을 했을까.
Java의 경우 JDBC를 활용하여 SQL 문구 하나를 보낼 때 마다 다음과 같이 Connection 객체를 생성을 해서 DB에 보내야한다. 이렇게 되면 Connection 객체를 만드는것도 비용이고 DB와 연결하기 위해 3way hanshake를 하는 것도 비용이 된다.
밑에 링크는 MySql에서 insert문을 실행할 때 드는 비용을 나타낸 것이다.
https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcExample {
public static void main(String[] args) {
// 데이터베이스 연결 정보를 설정합니다.
String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase"; // DB URL
String username = "root"; // DB 사용자 이름
String password = "password"; // DB 비밀번호
// 데이터베이스 연결을 위한 변수 선언
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 1. 데이터베이스 연결 생성
connection = DriverManager.getConnection(jdbcUrl, username, password);
System.out.println("데이터베이스에 성공적으로 연결되었습니다!");
// 2. Statement 객체 생성
statement = connection.createStatement();
// 3. SQL 쿼리 실행
String sql = "SELECT id, name, email FROM users"; // 예시 쿼리
resultSet = statement.executeQuery(sql);
// 4. 결과 처리
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
}
} catch (Exception e) {
e.printStackTrace(); // 예외 처리
} finally {
// 5. 리소스 해제
try {
if (resultSet != null) resultSet.close();
if (statement != null) statement.close();
if (connection != null) connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
DBCP(DataBase Connection Pool)
Connection 객체를 만드는것도 비용이고 3way hanshake를 하는것도 비용이라면 어떻게 해야할까? 이 모든 것을 WAS가 DB에 보내기전 미리 생성을 하고 연결을 해놓으면 된다. 이것이 바로 DBCP의 개념이다. 그리고 Springboot에서 dbcp를 관리해주는 라이브러리가 HikariCP다. 우리 개발자들은 이렇게 힘써주신 선배개발자 덕에 편하게 개발을 할 수 있게 됐다.
이렇게 처음 WAS가 실행 될때 여러개의 Connection을 만들어 놓게 되면 훨씬 더 빠르게 DB에 접근을 할 수 있게 된다.
사실 부트캠프에서는 딱 이정도 수준에서까지만 배움을 마무리 했지만, 실무라고 생각을 해보자.
DBCP의 크기를 얼마만큼해야 좋을 것이며 DB입장에서는 Connection을 몇개까지 허용을 해야 좋을것이며... 실무적으로 봤을 때 생각할것이 굉장히 많아진다.
DBCP 중요 파라미터
아직 실무를 경험을 해보진 않았지만, WAS와 DB 입장에서 DBCP 관련 중요 파라미터가 어떤것들이 있는지 GPT를 활용해서 살펴보자
1. DB(Database) 입장에서 중요한 파라미터
1.1 Max Connections (최대 커넥션 수)
- 설명: 데이터베이스가 동시에 허용할 수 있는 최대 커넥션 수입니다. 이 수치를 초과하는 연결 시도는 대기하거나 실패합니다.
- 중요성: 너무 적으면 애플리케이션이 필요할 때 충분한 연결을 받지 못하고, 너무 많으면 데이터베이스가 과부하에 걸릴 수 있습니다.
- 최적화 포인트: 데이터베이스 서버의 하드웨어 리소스(CPU, 메모리)에 맞춰 설정해야 하며, 애플리케이션의 요청 패턴을 분석하여 적정 수치를 설정합니다.
1.2 Idle Timeout (유휴 시간)
- 설명: 일정 시간 동안 사용되지 않는 커넥션을 데이터베이스에서 끊는 시간 설정입니다.
- 중요성: 커넥션이 너무 오래 유휴 상태로 유지되면, 데이터베이스 자원을 불필요하게 점유할 수 있습니다.
- 최적화 포인트: 적절한 유휴 시간을 설정하여 데이터베이스 연결을 적시에 반환하고, 불필요한 커넥션을 해제하여 자원을 최적화합니다.
1.3 Connection Lifetime (커넥션 수명)
- 설명: 특정 시간 이상 경과된 커넥션을 강제로 닫고, 새 커넥션으로 교체합니다.
- 중요성: 장시간 유지된 연결이 네트워크 문제나 DB 서버의 재시작 후에도 남아있는 경우를 방지합니다.
- 최적화 포인트: 커넥션이 너무 자주 끊기지 않도록 적절한 시간 설정이 필요합니다.
2. WAS(Web Application Server) 입장에서 중요한 파라미터
2.1 Initial Size (초기 커넥션 수)
- 설명: WAS가 시작할 때 초기화하는 커넥션의 수입니다.
- 중요성: 초기 요청에 대한 대응 속도에 영향을 줍니다. 적절한 초기 커넥션 수를 설정해야 애플리케이션 부하를 감당할 수 있습니다.
- 최적화 포인트: 예상되는 초기 트래픽에 맞춰 적정 수를 설정하되, 너무 많이 설정하면 불필요한 자원을 차지할 수 있습니다.
2.2 Max Total (최대 커넥션 풀 크기)
- 설명: 애플리케이션에서 동시에 열 수 있는 커넥션의 최대 수입니다.
- 중요성: 요청이 급증할 때 WAS가 얼마나 많은 커넥션을 관리할 수 있는지 결정합니다. 이 값을 너무 낮게 설정하면 애플리케이션이 커넥션을 기다리는 시간이 길어질 수 있습니다.
- 최적화 포인트: WAS 서버의 메모리와 CPU 성능을 고려하여 적절한 값을 설정하고, 데이터베이스가 처리할 수 있는 최대 연결 수와 맞춰야 합니다.
2.3 Max Idle (최대 유휴 커넥션 수)
- 설명: 풀에 남겨질 수 있는 최대 유휴 커넥션의 수입니다. 이 수를 초과하면 유휴 커넥션은 풀에서 제거됩니다.
- 중요성: 사용하지 않는 커넥션이 너무 많으면 리소스 낭비가 발생할 수 있습니다. 반면, 적절한 유휴 커넥션 수를 유지하면 성능 향상에 기여합니다.
- 최적화 포인트: 적절한 수준의 유휴 커넥션을 유지하여 자원 낭비를 방지하고, 필요할 때 커넥션을 빠르게 재사용할 수 있게 합니다.
2.4 Min Idle (최소 유휴 커넥션 수)
- 설명: 풀에서 유지할 최소 유휴 커넥션의 수입니다. 이 수만큼은 항상 커넥션을 유지하고 있어야 합니다.
- 중요성: 갑작스런 요청 증가에 대비하기 위한 최소 커넥션 수를 설정합니다. 너무 적으면 새로운 커넥션을 만드느라 시간이 걸릴 수 있습니다.
- 최적화 포인트: WAS가 효율적으로 새로운 커넥션을 생성할 수 있도록, 예상되는 요청량에 맞춰 적정 수를 설정합니다.
2.5 Connection Timeout (커넥션 타임아웃)
- 설명: 애플리케이션에서 커넥션을 요청할 때, 사용 가능한 커넥션을 얻기까지 대기하는 최대 시간입니다.
- 중요성: 커넥션을 얻는 데 너무 오래 걸리면 요청 처리에 지연이 발생하고, 성능 저하로 이어질 수 있습니다.
- 최적화 포인트: 커넥션을 얻지 못했을 때 빠르게 대처할 수 있도록 적절한 시간 설정이 필요합니다.
느낌점
사실 이렇게 파라미터를 정리 했지만 실제로 서비스를 운영하면서 대용량 트래픽을 느껴보지 않으면 와닿지가 않는다. 내가 만일 실무를 한다라고 하면 nGrinder 등 다양한 부하 테스트 툴을 이용을 해서 상황에 적절한 답을 찾아야 할것같다.
'CS > DB' 카테고리의 다른 글
저장 프로시저(Stored Procedure) (0) | 2024.08.12 |
---|---|
트랜잭션(Transaction) (0) | 2024.08.05 |
DB 용어 정리 (0) | 2024.08.01 |