dbcp 분석
DBCP 는 주로 jdbc 에 연결 풀 서 비 스 를 제공 합 니 다.
2. 실현
2.1 Jakarta Commons Pool
DBCP 는 연결 풀 관 리 를 위해 자카르타 커 먼 즈 풀 을 활용 했다.Commons Pool 의 기본 개념 을 살 펴 보 겠 습 니 다.
Poolable Object Factory: 풀 화 된 대상 의 생 성, 활성화, 걸 기, 검사 와 소각 을 관리 하 는 데 사 용 됩 니 다.ObjectPool: 풀 화 될 대상 의 대출 과 반환 을 관리 하고 Poolable Object Factory 에 해당 하 는 작업 을 완성 하 라 고 통지 합 니 다.
사용 과정:
1. 사용 할 Poolable Object Factory 클래스 의 인 스 턴 스 생 성
PoolableObjectFactory factory = new PoolableObjectFactorySample();
2. 이 Poolable ObjectFactory 인 스 턴 스 를 매개 변수 로 ObjectPool 인 터 페 이 스 를 실현 하 는 클래스 (예 를 들 어 Stack ObjectPool) 의 인 스 턴 스 를 생 성하 여 대상 풀 로 합 니 다.
ObjectPool pool = new StackObjectPool(factory);
3. 대상 풀 에서 대상 을 꺼 내야 할 때 대상 풀 의 Object borrowObject () 방법 을 호출 합 니 다.
obj = pool.borrowObject();
4. 대상 을 대상 풀 에 다시 넣 어야 할 때 이 대상 풀 의 void returnObject (Object obj) 방법 을 호출 합 니 다.
pool.returnObject(obj);
5. , void close() , 。
pool.close();
Poolable Object Factory 의 예 를 들 어 보 겠 습 니 다.
public class PoolableObjectFactorySample implements PoolableObjectFactory {
public Object makeObject() throws Exception {
return new Object();
}
public void activateObject(Object obj) throws Exception {
System.err.println("Activating Object " + obj);
}
public void passivateObject(Object obj) throws Exception {
System.err.println("Passivating Object " + obj);
}
public boolean validateObject(Object obj) {
return true;
}
public void destroyObject(Object obj) throws Exception {
System.err.println("Destroying Object " + obj);
}
}
이상 의 내용 을 통 해 comon pool 의 기본 용법 을 알 게 되 었 을 것 이 라 고 믿 습 니 다.
2.2 DBCP
일반적인 jdbc 연결 은 대개 다음 과 같 습 니 다.
public static Connection getConn() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@10.20.143.12:1521:crmp?args[applicationEncoding=UTF-8,databaseEncoding=UTF-8]","eve", "ca");
return conn;
}
그리고 지 화 를 고려 하면 우리 가 생각 할 수 있 는 첫 번 째 단 계 는 getConn () 을 방금 Poolable Object Factory 의 MakeObject 에 넣 는 것 이다.
dbcp 는 사실 이 일보 다 조금 더 많이 했 습 니 다. 먼저 다음 그림 을 보 겠 습 니 다.
datasource 와 connection 은 모두 decorator 로 포장 되 었 습 니 다.이것 도 decorator 의 전형 적 인 용법 이다.
가장 중요 한 것 은 Poolable Connection 이 ObjectPool 의 인용 을 가지 고 있어 야 connection 이 사 용 된 후에 언제든지 풀 에 넣 을 수 있 고 conn 의 사용 자 는 ObjectPool 에 관심 을 가 질 필요 가 없다 는 것 이다.
주요 createDatasource 과정 은 다음 과 같 습 니 다.
protected synchronized DataSource createDataSource()
throws SQLException {
if (closed) {
throw new SQLException("Data source is closed");
}
// Return the pool if we have already created it
if (dataSource != null) {
return (dataSource);
}
// create factory which returns raw physical connections
ConnectionFactory driverConnectionFactory = createConnectionFactory();
// create a pool for our connections
createConnectionPool();
// Set up statement pool, if desired
GenericKeyedObjectPoolFactory statementPoolFactory = null;
if (isPoolPreparedStatements()) {
statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
-1, // unlimited maxActive (per key)
GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
0, // maxWait
1, // maxIdle (per key)
maxOpenPreparedStatements);
}
// Set up the poolable connection factory
createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
// Create and return the pooling data source to manage the connections
createDataSourceInstance();
try {
for (int i = 0 ; i < initialSize ; i++) {
connectionPool.addObject();
}
} catch (Exception e) {
throw new SQLNestedException("Error preloading the connection pool", e);
}
return dataSource;
}
연결 풀 (datasource) 을 만 드 는 과정 은 상기 코드 를 통 해 잘 알 수 있 습 니 다.
연결 이 실 효 될 때의 처 리 를 추가 합 니 다.
public synchronized void close() throws SQLException {
boolean isClosed = false;
try {
isClosed = isClosed();
} catch (SQLException e) {
try {
_pool.invalidateObject(this);
} catch (Exception ie) {
// DO NOTHING the original exception will be rethrown
}
throw new SQLNestedException("Cannot close connection (isClosed check failed)", e);
}
if (isClosed) {
throw new SQLException("Already closed.");
} else {
try {
_pool.returnObject(this);
} catch(SQLException e) {
throw e;
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new SQLNestedException("Cannot close connection (return to pool failed)", e);
}
}
}
2.3 연결 풀 상용 설정
자주 사용 하 는 설정 을 먼저 붙 입 니 다:
사실 대부분의 설정 은 common. pool 의 설정 입 니 다. 풀 이 라 고 하면 최대 활동, 최대 여가, 최소 여가, 여가 시간 등 개념 을 생각 합 니 다.여기 서 주로 설명: max Active, max Idle 두 매개 변수
if(_maxActive < 0 || _numActive < _maxActive) {
// allow new object to be created
} else {
// the pool is exhausted
switch(_whenExhaustedAction) {
case WHEN_EXHAUSTED_GROW:
// allow new object to be created
break;
....
default:
throw new IllegalArgumentException("WhenExhaustedAction property " + _whenExhaustedAction + " not recognized.");
}
}
}
_numActive++;
여기 서 볼 수 있 습 니 다. 매번 대상 을 만 들 때마다numActive +, 만 든 대상 > = 최대 값 일 때 새 대상 은 줄 을 서서 기 다 려 야 합 니 다.기본 시간 (설정 중의 maxWait) 을 초과 하면 다시 던 집 니 다. throw new NoSuchElementException("Timeout waiting for idle object");우리 가 흔히 볼 수 있 는 연결 이 되 지 않 는 상황 이 발생 한다.
if (decrementNumActive) {
_numActive--;
}
if((_maxIdle >= 0) && (_pool.size() >= _maxIdle)) {
shouldDestroy = true;
} else if(success) {
_pool.addLast(new ObjectTimestampPair(obj));
}
notifyAll(); // _numActive has changed
if(shouldDestroy) {
try {
_factory.destroyObject(obj);
} catch(Exception e) {
// ignored
}
}
return 과정 에서 우 리 는 볼 수 있 습 니 다. 만약pool.size() >= _maxIdle, 연결 이 직접 소 모 됩 니 다. dbcp 의 기본 설정 에서 이곳 의 값 은 8 이 고 maxative 는 28 입 니 다. 이러한 가장 큰 문 제 는 높 은 동시 다발 로 비 추 는 상황 에서 일부 연결 이 반환 할 때 소각 되 고 곧 동시 다발 로 올 라 올 때 생 성 될 수 있 습 니 다. 생 성 은 자원 을 소모 하 는 일 입 니 다.또한 Public synchronized Object borrowObject () 는 동기 화 방법 이기 때문에 높 은 동시 다발 시 대량의 스 레 드 block 이 나타 납 니 다. 다음은 20 동시 다발 조회 의 테스트 결과 입 니 다 (sql 자 체 를 조회 하 는 데 시간 이 많이 걸 리 지 않 습 니 다).
위 는 maxive = 28, maxidle = 8 의 경우 응답 시간 과 tps 는 말 할 필요 가 없습니다.조정 후의 스 레 드 가 어느 정도 막 힌 상황 은 ibatis, ibatis 를 사 용 했 기 때 문 입 니 다. 상세 한 것 은 부록 [1] 을 참조 하 십시오.
쫓 아 내 는 대략적인 원 리 는 백 스테이지 timer 가 시간 간격 으로 BetweenEvictionRuns Millis 에서 스 레 드 를 만 들 고 연못 의 return Math. min (numTestsPerEvictionRun, _pool.size());연결
if ((_minEvictableIdleTimeMillis > 0) && (idleTimeMilis > _minEvictableIdleTimeMillis)) {
removeObject = true;
}
하면, 만약, 만약...minEvictable IdleTimeMillis (기본 값 은 30 분, 같은 설정 가능) 를 소각 합 니 다.test While Idle 이 설정 되 어 있 으 면 이 연결 이 사용 가능 한 지, 사용 할 수 없 는 지, 마찬가지 로 삭 제 됩 니 다.한 번 에 numTests PerEvictionRun 연결 만 처리 하고 한 번 에 다 처리 하지 않 습 니 다.
0 으로 추천 하 는 이 유 는:
public void run() {
try {
evict();
} catch(Exception e) {
// ignored
}
try {
ensureMinIdle();
} catch(Exception e) {
// ignored
}
}
evict () 는 대상 의 남 은 시간 을 검사 하고 사용 하지 않 는 대상 을 삭제 한 다음 ensureMinIdle () 은 풀 에 minIdle 개 이상 의 대상 이 있 는 지 확인 하고 없 으 면 대상 을 만 듭 니 다.이 는 응용 이 한가 할 때 모든 대상 을 삭제 한 다음 에 두 개의 대상 을 다시 만 들 고 나중에 삭제 하 는 디 더 링 상황 을 초래 할 수 있 습 니 다.현재 설정 은 30 분 마다 쫓 겨 나 는 것 으로 30 분 마다 한 번 더 소모 된다.
2 로 배 치 된 장점 은 응용 이 비교적 한가 할 때 적어도 요청 할 때마다 연결 을 다시 만 들 지 않 는 다 는 것 이다.
부록:
[1] ibatis 로 인 한 스 레 드 차단 문제
1. 위의 차단 에 대해 서 는 Dump 스 레 드 를 통 해 ibatis 가 결 과 를 처리 할 때 나타 난 것 을 발견 하 였 습 니 다.
at com.ibatis.common.beans.ClassInfo.getInstance(ClassInfo.java:362)
- locked <0x00002aaaae2c9b60> (a java.lang.Class for java.util.HashMap)
at com.ibatis.common.beans.ComplexBeanProbe.setProperty(ComplexBeanProbe.java:328)
….
ClassInfo. getInstance 에 대응 하 는 코드 는:
if (cacheEnabled) {
synchronized (clazz) {
ClassInfo cache = (ClassInfo) CLASS_INFO_MAP.get(clazz);
if (cache == null) {
cache = new ClassInfo(clazz);
CLASS_INFO_MAP.put(clazz, cache);
}
return cache;
}
위의 이 코드 의 목적 은 무엇 입 니까?ibatis 는 조회 결 과 를 얻 은 후 driver 가 되 돌아 오 는 object [] 를 resultMap 에서 지정 한 대상 (set * 방법 을 통 해) 에 반사 적 으로 설정 해 야 합 니 다.성능 을 고려 하여 (getMethod 를 반사 적 으로 호출 하 는 데 상대 적 으로 많은 시간 이 걸 립 니 다) ibatis 는 class 를 key 로 사용 하여 사용 하 는 set 방법 을 map 에 캐 시 하여 반사 적 으로 호출 할 수 있 습 니 다.여러 번 초기 화 되 지 않도록 동기 화 를 사용 했다.그러나 높 은 병발 상황 에서 (그리고 우리 의 테스트 는 같은 대상 의 데 이 터 를 얻 는 것) 이 동기 화 는 차단 을 초래 합 니 다. 즉, 테스트 보고서 에 스 레 드 block 을 새로 설정 한 곳 입 니 다.
위의 모든 문 제 를 설명 한 후에 또 하나의 의문 이 있 습 니 다. 첫 번 째 호출 을 제외 하고 매번 이 함 수 를 호출 할 때마다 조작 만 합 니 다.
ClassInfo cache = (ClassInfo) CLASS_INFO_MAP.get(clazz)
이 방법 은 비록 동기 화 되 었 지만, 실행 은 매우 빠 른 데, 왜 여러 개의 라인 이 막 힐 수 있 습 니까?
조사 연구 에 따 르 면 이 방법 은 모든 속성 을 설정 할 때 한 번 호출 되 기 때 문 입 니 다. 하나의 조회 가 20 개의 기록 을 되 돌려 준다 고 가정 하고 하나의 기록 이 10 개의 속성 이 있다 고 가정 하면 하나의 결과 조합 은 적어도 200 번 호출 됩 니 다. 자 물 쇠 를 풀 때 메모리 구 조 를 수정 할 뿐 스 레 드 를 전환 하지 않 습 니 다 (자바 에서 block 의 스 레 드 는 Liux 에서 sleep 상태 이 고 대기 열 에 있 습 니 다).따라서 일반적인 상황 에서 현재 자 물 쇠 를 가 진 스 레 드 는 이 자 물 쇠 를 반복 적 으로 가지 고 200 번 연속 으로 호출 한 다음 에 다른 스 레 드 가 다시 경쟁 할 때 한 스 레 드 만 자물쇠 에 경쟁 합 니 다. 그러면 운 이 가장 나 쁜 스 레 드 는 (19 * 200) 번 의 조작 을 기다 릴 것 입 니 다. 매번 시간 이 짧 지만 합 쳐 도 일정한 차단 상황 이 있 습 니 다.
참고 문헌: 자카르타 Commons Pool 처리 대상 지 화 사용:http://www.ibm.com/developerworks/cn/java/l-common-pool/index.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[Cache]Mysql(JPA)과 Redis를 함께 사용해보자안녕하세요 오늘은 Redis와 Mysql(JPA)과 이용하는 방법에 대해 설명해보도록 하겠습니다! DB의 부하를 줄이기 위해, 혹은 select 를 빠르게 하기 위해 사용될 때도 있습니다 위 그림과 같이 캐시 서버에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.