programing

Oracle Data Source와Oracle UCP Pool Data Source

showcode 2023. 3. 11. 09:38
반응형

Oracle Data Source와Oracle UCP Pool Data Source

JDBC Oracle Connection Pooling 항목을 조사하던 중 Universal Connection Pool(UCP)이라는 새로운 Oracle Pool 구현을 발견했습니다.이제 연결 풀링에는 [캐시 옵션이 활성화된 상태에서] OracleDataSource가 아닌 새로운 클래스인 PoolDataSource가 사용됩니다.이 새로운 실장으로의 이행에 대해 고민하고 있습니다만, 어떤 수정/업그레이드가 필요한지에 대한 적절한 문서를 찾을 수 없습니다.둘 다 해본 사람?장점/단점?감사해요.

최신 Oracle jdbc 드라이버(11.2.0.1.0)는 Oracle Implicit Connection 캐시(OracleDataSource를 사용하는 것)가 사용되지 않음을 명시합니다.

Oracle JDBC 드라이버 릴리스 11.2.0.1.0 운영 Readme.txt

이 릴리스의 신기능

범용 연결 풀 이 릴리스에서는 Oracle 암묵적 연결 캐시 기능이 사용되지 않습니다.대신 새로운 Universal Connection Pool을 사용하는 것이 좋습니다.UCP는 ICC의 모든 기능과 더불어 더 많은 기능을 갖추고 있습니다.UCP는 별도의 jar 파일 ucp.jar로 사용할 수 있습니다.

그래서 UCP를 사용하는 것이 좋다고 생각합니다만, 문서는 그다지 좋지 않습니다.예를 들어 봄에는 UCP를 사용할 방법을 찾지 못했습니다.

업데이트: 올바른 스프링 구성을 찾았습니다.OK 올바른 구성을 찾은 것 같습니다.

<bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceFactory" factory-method="getPoolDataSource">
    <property name="URL" value="jdbc:oracle:thin:@myserver:1521:mysid" />
    <property name="user" value="myuser" />
    <property name="password" value="mypassword" />
    <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
    <property name="connectionPoolName" value="ANAG_POOL" />
    <property name="minPoolSize" value="5" />
    <property name="maxPoolSize" value="10" />
    <property name="initialPoolSize" value="5" />
    <property name="inactiveConnectionTimeout" value="120" />
    <property name="validateConnectionOnBorrow" value="true" />
    <property name="maxStatements" value="10" />
</bean>

중요한 것은 올바른 공장 클래스와 올바른 공장 방법을 지정하는 것입니다.

PDS는 MySQL과 같은 비 Oracle 데이터베이스에 대해 ODS와 동일한 수준의 풀링 기능을 제공하기 때문에 '범용'입니다.

Oracle 웹 사이트 및 UCP 전환 가이드 문서 UCP Dev Guide를 참조하십시오.

ODS에서 UCP(PDS)로 이행하는 것이 당장 얻을 수 있는 이점은 없다고 생각합니다만, 향후 Oracle은 ODS의 기능 중 일부를 폐지할 가능성이 있습니다.잠시 ODS를 사용했는데, 당분간은 만족스럽지만 새로 시작하면 PDS로 하겠습니다.

UCP에 대한 광범위한 평가를 실시하여 UCP를 사용하지 않기로 결정하였습니다.자세한 내용은 투고를 참조해 주십시오.

저는 UCP를 테스트하여 Spring JMS 리스너 컨테이너를 사용한 Spring 3.0.5 Hibernate 앱과 @Transactional 주석을 사용한 Spring 관리 세션 및 트랜잭션에 도입했습니다.동일한 레코드를 업데이트하려고 하는 개별 수신기 스레드로 인해 데이터가 SQL 제약 오류의 원인이 될 수 있습니다.이 경우 예외는 @Transactional에 의해 주석이 붙은 어떤 메서드에 의해 느려지고 오류는 @Transactional에 의해 주석이 달린 다른 메서드에 의해 데이터베이스에 기록됩니다.어떤 이유로든 이 프로세스로 인해 커서 누수가 발생하고 결과적으로 ORA-01000 Open Cursor limit exceeded 오류가 발생하여 스레드의 처리가 정지됩니다.

동일한 코드로 실행되는 Oracle Data Source는 커서가 누출되지 않는 것 같기 때문에 이 문제는 발생하지 않습니다.

이것은 매우 이상한 시나리오입니다만, 이러한 구조를 가진 어플리케이션에서 UCP를 사용하는 것은 시기상조입니다.

저도 UCP를 테스트하고 있는데 스레드 풀 기반 애플리케이션에서 성능 문제가 발생하고 있습니다.처음에 Oracle Data Source를 사용해 보았지만 배치 처리를 위한 구성에 문제가 있습니다.Null Pointer가 계속 나온다.접속의 예외로 인해 일종의 접속 누수가 발생하고 있다고 생각됩니다만, 일부 어플리케이션에서만 Oracle Data Source가 정상적으로 동작하는 배치 프로세스 지향적이지 않은 다른 어플리케이션이 있습니다.

이 투고와 이 주제를 조사하면서 발견한 몇 가지 내용을 바탕으로 UCP를 시도했습니다.충분히 조정하면 닫힌 접속/Null Pointer를 제거할 수 있다는 것을 알게 되었습니다.연결 스타일 오류에 대한 예외가 발생했지만 가비지 컬렉션이 타격을 입었습니다.장기 GC는 빠르게 채워지고 응용 프로그램 실행이 완료될 때까지 해방되지 않습니다.이 작업은 부하가 매우 높은 경우 하루 또는 그 이상 걸릴 수 있습니다.데이터 처리에도 시간이 더 걸리는 것도 알 수 있습니다.현재 감가상각된 OracleCacheImpl 클래스('그냥 작동'하기 때문에 현재 운영 환경에서 사용)와 비교해 보겠습니다.이 클래스는 UCP가 사용하는 GC 메모리의 3분의 1을 사용하여 파일을 훨씬 빠르게 처리합니다.다른 모든 어플리케이션에서는 UCP는 정상적으로 동작하고 있는 것 같으며, 제가 사용하는 거의 모든 것을 처리합니다.그러나 스레드 풀 어플리케이션은 주요 어플리케이션이기 때문에 프로덕션에서 GC 예외의 위험을 감수할 수 없습니다.

암묵적인 접속 캐싱은 접속 검증을 사용하는 경우 UCP보다 훨씬 뛰어난 성능을 발휘합니다.이는 버그 16723836에 대응하고 있으며 12.1.0.2에서 수정이 스케줄 되어 있습니다.

동시 부하가 증가함에 따라 UCP 풀링의 접속 취득/복귀 비용이 점점 높아집니다.이 테스트에서는 oracle 암묵적 연결 캐시, Tomcat 풀링 및 UCP를 비교합니다. 3개 모두 최대 200개의 연결, 최소 20개의 연결 및 2개의 초기 크기를 허용하도록 구성되어 있습니다.3개 모두 풀에서 삭제될 때 연결을 검증하도록 설정됩니다.Tomcat 풀은 검증에 "select sysdate from dual" 문을 사용합니다.

이는 64개의 논리 코어(물리 32개)와 128GB RAM을 갖춘 64비트 RedHat 노드에서 발생합니다.

동시 스레드가 5개인 경우 UCP가 가장 느리지만 총 연결 관리 시간(get 및 close)은 평균 1ms 미만입니다.동시성이 높아짐에 따라 UCP는 다른 솔루션보다 점점 뒤쳐집니다.

25 Threads:
Implicit: 0.58ms
Tomcat: 0.92ms
UCP: 1.50ms

50 Threads:
Implicit: 0.92ms
Tomcat: 1.60ms
UCP: 6.80ms

100 Threads:
Implicit: 2.60ms
Tomcat: 3.20ms
UCP: 21.40ms

180 Threads:
Implicit: 13.86ms
Tomcat: 15.34ms
UCP: 40.70ms

Spring Bean.xml에서 UCP를 사용하는 방법은 두 가지가 있습니다.

파일에 의해 설정된 db.properties의 경우 다음 중 하나를 사용합니다.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

    <property name="location">
        <value>classpath:resources/db.properties</value>
    </property>
</bean>

첫 번째는 oracle.ucp.jdbc 입니다.Pool Data Source Impl :-

<bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceImpl">

    <property name="URL" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />

    <property name="validateConnectionOnBorrow" value="true"/>

    <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
    <property name="connectionPoolName" value="TEST_POOL" />
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="20" />
    <property name="initialPoolSize" value="12" />
</bean>

두 번째는 oracle.ucp.jdbc입니다Pool Data Source Factory :-

 <bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceFactory"  
     factory-method="getPoolDataSource">        
    <property name="URL" value="${jdbc.url}" />
    <property name="user" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />

    <property name="validateConnectionOnBorrow" value="true"/>

    <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
    <property name="connectionPoolName" value="TEST_POOL" />
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="20" />
    <property name="initialPoolSize" value="12" />
</bean>

이상입니다:) 자세한 내용은 https://docs.oracle.com/cd/E11882_01/java.112/e12265/connect.htm#CHDDCICA 를 참조하십시오.

ucp를 해봤는데 퍼포먼스가 더 좋더라고요.열쇠가 이것을 사용하고 있을 가능성이 있다.

oracle.ucp.jdbc.PoolDataSource ds = (oracle.ucp.jdbc.PoolDataSource)envContext.lookup(url_r);
MyConnectionLabelingCallback callback = new MyConnectionLabelingCallback();
ds.registerConnectionLabelingCallback( callback );


Properties label = new Properties();
label.setProperty(pname, KEY);
conn = ds.getConnection(label);

이렇게 하면 연결을 빌리고 닫지 않습니다.그래서 퍼포먼스도 좋고

콜백 클래스의 코드는 다음과 같습니다.

public class MyConnectionLabelingCallback
implements ConnectionLabelingCallback {

      public MyConnectionLabelingCallback()
      {
      }

      public int cost(Properties reqLabels, Properties currentLabels)
      {

        // Case 1: exact match
        if (reqLabels.equals(currentLabels))
        {
          System.out.println("## Exact match found!! ##");
          return 0;
        }

        // Case 2: some labels match with no unmatched labels
        String iso1 = (String) reqLabels.get("TRANSACTION_ISOLATION");
        String iso2 = (String) currentLabels.get("TRANSACTION_ISOLATION");
        boolean match =
          (iso1 != null && iso2 != null && iso1.equalsIgnoreCase(iso2));
        Set rKeys = reqLabels.keySet();
        Set cKeys = currentLabels.keySet();
        if (match && rKeys.containsAll(cKeys))
        {
          System.out.println("## Partial match found!! ##");
          return 10;
        }

        // No label matches to application's preference.
        // Do not choose this connection.
        System.out.println("## No match found!! ##");
        return Integer.MAX_VALUE;
      }

      public boolean configure(Properties reqLabels, Object conn)
      {

          System.out.println("Configure################");
        try
        {
          String isoStr = (String) reqLabels.get("TRANSACTION_ISOLATION");
          ((Connection)conn).setTransactionIsolation(Integer.valueOf(isoStr));
          LabelableConnection lconn = (LabelableConnection) conn;

          // Find the unmatched labels on this connection
          Properties unmatchedLabels =
           lconn.getUnmatchedConnectionLabels(reqLabels);

          // Apply each label <key,value> in unmatchedLabels to conn
          for (Map.Entry<Object, Object> label : unmatchedLabels.entrySet())
          {
            String key = (String) label.getKey();
            String value = (String) label.getValue();
            lconn.applyConnectionLabel(key, value);
          }
        }
        catch (Exception exc)
        {

          return false;
        }
        return true;
      }
    }

언급URL : https://stackoverflow.com/questions/1427890/oracledatasource-vs-oracle-ucp-pooldatasource

반응형