OracleDataSource против Oracle UCP PoolDataSource

Я исследовал некоторые элементы JDBC Oracle Connection Pooling и столкнулся с новой реализацией Oracle Pool под названием Universal Connection Pool (UCP). Теперь для пула соединений используется новый класс PoolDataSource, а не OracleDataSource [с включенной опцией кэширования]. Я спорю о том, стоит ли переходить на эту новую реализацию, но я не могу найти хорошую документацию о том, что (если таковые имеются) исправления / обновления это купило бы меня. У кого-нибудь есть опыт работы с обоими? Плюсы / минусы? Благодарю.

8 ответов

Решение

В последнем явном драйвере Oracle jdbc (11.2.0.1.0) указано, что кэш Oracle Implicit Connection (то есть тот, который использует OracleDataSource) устарел:

Драйверы Oracle JDBC выпускают версию 11.2.0.1.0 Readme.txt

Что нового в этой версии?

Универсальный пул соединений В этом выпуске функция Oracle Implicit Connection Cache устарела. Пользователям настоятельно рекомендуется использовать новый универсальный пул соединений. У UCP есть все функции ICC, а также многое другое. UCP доступен в отдельном файле jar, ucp.jar.

Поэтому я думаю, что лучше начать использовать UCP, но документация не так хороша. Например, я не нашел способ использовать UCP с пружиной...

ОБНОВЛЕНИЕ: Я нашел правильную конфигурацию пружины: ОК, я думаю, что нашел правильную конфигурацию:

<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 является "универсальным", поскольку обеспечивает тот же уровень функциональности пула, который вы получаете в ODS для баз данных, отличных от Oracle, например MySQL.

См. Руководство по разработке UCP, статью на веб-сайте Oracle и Руководство по переходу UCP

Я не вижу немедленной выгоды от перехода на UCP (PDS) с ODS, но, возможно, в будущем Oracle откажется от некоторых функций ODS. Некоторое время я использовал ODS, и на данный момент я вполне доволен этим, но если бы я начал с нуля, я бы пошел с PDS.

Я сделал обширную оценку UCP и решил НЕ использовать UCP - пожалуйста, посмотрите на этот пост для деталей.

Я протестировал UCP и развернул его в рабочей среде в приложении Spring 3.0.5 Hibernate, используя контейнеры прослушивателей Spring JMS, а также сеансы и транзакции, управляемые Spring, с помощью аннотации @Transactional. Иногда данные вызывают ошибки ограничения SQL из-за того, что отдельные потоки слушателей пытаются обновить одну и ту же запись. Когда это происходит, исключение выдается одним методом, аннотированным @Transactional, и ошибка регистрируется в базе данных, используя другой метод, аннотированный @Transactional. По какой-то причине этот процесс, по-видимому, приводит к утечке курсора, которая в конечном итоге складывается и вызывает ошибку превышения предела открытого курсора ORA-01000, в результате чего поток прекращает обработку чего-либо.

OracleDataSource, работающий в том же коде, похоже, не пропускает курсоры, поэтому не вызывает этой проблемы.

Это довольно странный сценарий, но он показывает мне, что пока слишком рано использовать UCP в приложении с такой структурой.

Я также тестирую UCP и обнаруживаю, что у меня проблемы с производительностью в приложении на основе пула потоков. Сначала я пробовал OracleDataSource, но у меня возникли проблемы с его настройкой для пакетной обработки. Я продолжаю получать исключения NullPointerException в соединениях, что наводит меня на мысль, что у меня какая-то утечка соединений, но только с некоторыми приложениями, которыми мы управляем, которые не ориентированы на пакетные процессы, и OracleDataSource работает хорошо.

Основываясь на этом посте и нескольких других исследованиях, которые я нашел, я попробовал UCP. Я обнаружил, что при достаточной настройке я могу избавиться от закрытых соединений /NullPointerException при ошибках стиля соединений, но сборщик мусора терпит поражение. Долгосрочный сборщик мусора быстро заполняется и, кажется, никогда не освобождается до тех пор, пока приложение не завершит работу. Иногда это может занять несколько дней, если нагрузка действительно большая. Я также заметил, что обработка данных занимает больше времени. Я сравниваю это с устаревшим классом OracleCacheImpl (который мы в настоящее время используем в производстве, потому что он все еще "просто работает"), где он использует треть памяти GC, которую UCP делает и обрабатывает файлы гораздо быстрее. Во всех других приложениях UCP, кажется, работает просто отлично и обрабатывает практически все, что я к нему добавляю, но приложение Thread Pool является основным приложением, и я не могу рисковать GC Exception в работе.

Неявное кэширование соединения работает немного лучше, чем UCP, если вы используете проверку соединения. Это соответствует ошибке 16723836, которую планируется исправить в 12.1.0.2.

Пул UCP становится все более дорогим для получения / возврата соединений по мере увеличения одновременной нагрузки. Тест сравнивает неявное кеширование соединения Oracle, пул Tomcat и UCP. Все 3 настроены так, чтобы разрешить максимум 200 подключений, минимум 20 подключений и начальный размер 2. Все 3 настроены для проверки соединений по мере их удаления из пула. В пуле tomcat для проверки используется оператор "выбрать sysdate from dual".

Эти результаты получены на 64-битном узле RedHat с 64 логическими ядрами (32 физических) и 128 ГБ оперативной памяти.

При 5 одновременных потоках UCP является самым медленным, но общее время управления соединением (получить и закрыть) в среднем составляет менее 1 мс. По мере увеличения параллелизма 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

Существует два возможных способа использования UCP в Spring Bean.xml.

Для db.properties, заданного некоторым файлом, затем загрузите его, затем используйте один из них:

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

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

Первый с oracle.ucp.jdbc.PoolDataSourceImpl:-

<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.PoolDataSourceFactory:-

 <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

Я пробовал 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;
      }
    }
Другие вопросы по тегам