개발일기장
Connection 을 왜 더 이상 끌어오지 못하는 걸까 (GenericObjectPool) 본문
연휴라서 시간이 남는다.
이것저것 하느라 바빠서 이제서야 고민해볼 시간이 생긴것 같다..
아직도 의문인게 왜 회사에서 직접 프레임워크를 만들어쓰는지다. 뭐 특별한게 있으면 모르겠는데 몇몇 부분 빼면 죄다 Springboot에서 구현이 가능함
Application에서 DB접속 관련해서도 라이브러리를 그냥 사용하지 않고 상속받아서 커스텀을 한다. 의미있는지는 모르겠는데 모니터링 용도로 그렇게 만든 것 같다.
DataSource를 상속받아서 직접 만들고, Apache Common Pool을 가져다가 GenericObjectPool을 이용해서 커스텀이 되어있는 상태다.
회사소스를 가지고 올 수 없기 때문에 대충 Copilot한태 만들라고 했다.
Custom GenericObjectPool 구현
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.sql.Connection;
public class CustomConnectionPool extends GenericObjectPool<Connection> {
public CustomConnectionPool(ConnectionFactory factory, GenericObjectPoolConfig<Connection> config) {
super(factory, config);
}
@Override
public Connection borrowObject() throws Exception {
Object obj = super.borrowObject();
if (obj instanceof Connection) {
conn = (Connection) obj;
// CustomDataSource로 변환하여 특정 작업
}
return obj;
}
@Override
public void returnObject(Connection conn) {
// CustomDataSource로 변환하여 특정 작업 수행
super.returnObject(conn);
}
}
일단 의심되는 부분에 대해서 물어보자.
1. Custom 한 영역에서 경합이나 Exception 처리를 제대로 하지 못해서 문제가 발생한 것일까?
2. Connection을 획득하는 시점에서 DeadLock이 걸릴 수 있을까?
1. Custom 한 영역에서 Exception 처리를 제대로 하지 못해서 문제가 발생한 것일까?
커스텀 영역에서 문제가 발생했을 때 문제가 되지 않는지에 대해서 물어보니깐 예외처리 코드를 만들어준다.
예외 처리 예시
import org.apache.commons.pool2.impl.GenericObjectPool;
import java.sql.Connection;
public class CustomConnectionPool extends GenericObjectPool<Connection> {
public CustomConnectionPool(ConnectionFactory factory, GenericObjectPoolConfig<Connection> config) {
super(factory, config);
}
@Override
public Connection borrowObject() throws Exception {
Connection conn = null;
try {
Object obj = super.borrowObject();
if (obj instanceof Connection) {
conn = (Connection) obj;
// CustomDataSource로 변환하여 특정 작업 수행
initializeConnection(conn);
}
return conn;
} catch (Exception e) {
if (conn != null) {
super.returnObject(conn); // 예외 발생 시 연결 반환
}
System.err.println("Failed to borrow a connection: " + e.getMessage());
throw e;
}
}
@Override
public void returnObject(Connection conn) {
try {
// CustomDataSource로 변환하여 특정 작업 수행
cleanupConnection(conn);
super.returnObject(conn);
} catch (Exception e) {
System.err.println("Failed to return a connection: " + e.getMessage());
try {
super.invalidateObject(conn); // 예외 발생 시 연결 무효화
} catch (Exception ex) {
System.err.println("Failed to invalidate the connection: " + ex.getMessage());
}
}
}
private void initializeConnection(Connection conn) {
// 커넥션 초기화 로직
}
private void cleanupConnection(Connection conn) {
// 커넥션 정리 로직
}
}
커스텀 영역에서 Exception 발생 시 예외처리를 할 때
1-1. borrowObject에서 Exception 발생 시 그냥 obejct를 return 해준다.
1-2. returnObject에서는 Exception 발생 시 connection 을 정리는 해준다.
경합에 대해서 물어보니깐 아래되 같은 답변을 해준다.
>> GenericObjectPool 자체가 스레드 안전성을 제공하지만, 커스텀 로직을 추가할 때는 동기화를 통해 경합을 방지할 수 있습니다.
그러면서 borrowObject와 returnObject에 synchronized를 붙여서 안전하게 사용하라고 한다. 나도 요부분이 문제같긴 한대 이거는 직접 로그 찍어서 확인을 하지 않으면 확신 할 수 없을 것 같다.
1에 대한 결론
> 일단 try - catch 달고 borrow해오는 connection의 hash값에 로그를 찍어서 문제지점을 확인해보자
> 이후에 예외처리로직 넣고
> 문제가 없으면 동시성 문제도 해결하자.
2. Connection을 획득하는 시점에서 DeadLock이 걸릴 수 있을까?
이부분에 대해서 물어보니깐 이렇게 답변을 해준다.
예시
borrowObject와 returnObject 메서드에서 경합 처리를 하지 않으면, 다음과 같은 상황이 발생할 수 있습니다:
- 스레드 A가 borrowObject를 호출하여 커넥션을 빌리고, 특정 작업을 수행하는 동안 스레드 B가 returnObject를 호출하여 커넥션을 반환하려고 합니다.
- 스레드 A가 작업을 완료하지 못하고 예외가 발생하면, 스레드 B는 커넥션을 반환하지 못하고 대기 상태에 빠질 수 있습니다.
- 이 상태가 지속되면, 다른 스레드들도 동일한 리소스를 기다리게 되어 데드락이 발생할 수 있습니다.
해결 방법
- 동기화: synchronized 키워드를 사용하여 메서드나 블록을 동기화합니다.
- 타임아웃: 특정 시간 내에 작업이 완료되지 않으면 예외를 발생시켜 데드락을 방지합니다.
- 데드락 회피 알고리즘: 리소스 할당 그래프를 사용하여 데드락을 회피하는 알고리즘을 구현합니다.
예시만 들어보면 그럴듯한대 이게 또 생성형AI가 환각? 뭐시기랍시고 또 지들이 모르면 이것저것 헛소리 한다고 들어서 신뢰하기가 힘들지만 뭐 방법이 있나? 내가 부족하니 이런거라도 믿고 테스트해봐야지.
결론
Quartz를 이용해서 동시에 여러개의 Transaction이 생성되고 Connection을 획득 / 반환하는 시점에 문제가 발생할것이라고 예상은 하고 있는데 직접 로그를 찍어서 확인하지 않으면 안될 것 같다.
그리고 GenericObjectPool에 구현되어있는 borrow / return 로직에 대해서 한번 더 확인을 해봐야할 것 같다. 당연히 예외처리는 되어 있겠지만 그걸 super로 호출해서 그대로 사용하는거니깐 문제 발생하면 바로 위에까지 터지는게 맞지
해결이 되었으면 좋겠다!
'JAVA' 카테고리의 다른 글
SQLSessionManager.newInstance()에서 어떤 순서로 Connection을 가지고 오고 반환하는가. (1) | 2024.09.16 |
---|---|
CGLIB proxy ... (1) | 2023.11.26 |
Proxy ... (1) | 2023.11.26 |
Reflection ... (0) | 2023.11.26 |
Java 데이터 접근 기술 - transaction & exception(Check,UnCheck) (3) (0) | 2023.02.08 |