IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  Технология Java  >

JCA 1.5 : Часть 1. Оптимизация и управление циклом жизни

Соединения становятся лучше, адаптеры ресурсов начинают собственную жизнь

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Дэвид Карри, штатный инженер-программист, IBM UK Ltd

21.02.2008

В первой части серии из трех статей Java-разработчик Дэвид Карри знакомит с некоторыми приемами оптимизации Java™ 2 Enterprise Edition (J2EE) Connector Architecture (JCA) 1.5, которые ускорят работу имеющихся или новых исходящих адаптеров ресурсов. Он также рассматривает некоторые дополнения, которые позволят адаптерам ресурсов начать свою собственную новую жизнь. Данная серия очень важна для тех, кто хочет улучшить производительность (или добавить новую функциональность) существующих адаптеров ресурсов или думает над написанием нового JCA 1.5-совместимого адаптера ресурсов. Также она должна быть интересна тем, кто пишет приложения, использующие адаптеры ресурсов, и хочет знать немного больше о том, что происходит за кулисами.

JCA 1.5, самая новая версия J2EE Connector Architecture, имеет много существенных улучшений и важных дополнений. В данной статье, первой в серии из трех статей, посвященной этим изменениям, я познакомлю вас с некоторыми приемами оптимизации, которые ускорят работу приложений, использующих исходящие адаптеры ресурсов, особенно тех, которые используют транзакции. Затем я рассмотрю расширения в соглашении по управлению циклом жизни, которые должны предохранить приложения от разрыва соединений и позволить адаптерам ресурсов начать собственную жизнь. Она подготовит вас к работе со второй частью данной серии, в которой рассматриваются новые соглашения по управлению работой и поступлению транзакций, а также с третьей частью, в которой исследуется давно ожидаемое соглашение по поступлению транзакций, больше известное как поддержка управляемых сообщениями компонентов (Message-Driven Bean, MDB).

Предполагается наличие у вас достаточного понимания соглашения по управлению JCA-соединением. Все принципы оригинальной спецификации 1.0 все еще применимы, поэтому, если вы являетесь новичком в JCA, я рекомендую сначала поработать с вводным учебным руководством Вили Фаррелла (см. раздел "Ресурсы").

"Ленивые" соединения становятся быстрее

Новая версия спецификации JCA не может сделать соединение между приложением и серверной системой быстрее, но JCA 1.5 представила два набора интерфейсов, которые могут ускорить приложения, использующие соединения. Первый набор снимает ограничения в управлении серверами приложений описателями (handles) соединений предыдущих версий JCA.

Как известно многим из вас, J2EE поддерживает две модели использования соединений, которые я буду называть get-use-close (получить-использовать-закрыть) и cached-handle (кэшированный описатель). Более подробное описание этих моделей поможет понять улучшения производительности, которые предложила JCA 1.5 в этой области.

Get-use-close

В модели get-use-close приложение всегда получает новое соединение при его необходимости, использует и закрывает его, как показано в листинге 1 (для простоты я не включал в листинги примеров логику обработки исключительных ситуаций).


Листинг 1. EJB-компонент (Enterprise JavaBean - EJB), использующий модель get-use-close
public class GetUseCloseEJB implements SessionBean {

    ...

    public void businessMethod() {

       InitialContext context = new InitialContext();
       DataSource dataSource = (DataSource)context.lookup
       ("java:comp/env/jdbc/mydatasource");
       Connection connection = datasource.getConnection();

       ...

       connection.close();

    }

}

Модель get-use-close может выглядеть неэффективной, но организация пулов соединений, реализуемых сервером приложений, должна сделать операцию "get" недорогой по затрачиваемым ресурсам. И поскольку приложение поддерживает соединение столько, сколько нужно, различные экземпляры или части приложения могут повторно использовать соединение, уменьшая, таким образом, общий объем используемых ресурсов. Это продемонстрировано на рисунке 1.


Рисунок 1. Модель get-use-close в действии
Рисунок 1. Модель get-use-close в действии

Как показано на рисунке 1, каждый раз, когда метод компонента вызывает getConnection, менеджер соединений повторно использует управляемое соединение из пула и создает только новый описатель соединения. Когда описатель соединения уведомляет менеджер соединений о том, что он был закрыт, управляемое соединение очищается и возвращается в пул. Время связи управляемого соединения с этим экземпляром приложения показано на рисунке 1 зелеными полосками.

Cached-handle

В модели cached-handle приложение получает соединение заранее и кэширует ссылку на него в поле экземпляра, как показано в листинге 2.


Листинг 2. Модель cached-handle
public class CachedHandleEJB implements SessionBean {

    private Connection _connection;

    ...

    public void ejbCreate() {

       InitialContext context = new InitialContext();
       DataSource dataSource = (DataSource)context.lookup
       ("java:comp/env/jdbc/mydatasource");
       _connection = datasource.getConnection();

    }

    public void businessMethod() {

       ...

    }

}

Создатели приложений обычно используют модель cached-handle, поскольку они думают, что приложение будет работать лучше. Но, благодаря преимуществам организации пулов в модели get-use-close, между двумя этими моделями нет больших различий в производительности. Хотя модель cached-handle упрощает логику бизнес-метода, требуется дополнительная логика на закрытие соединения при пассивации и воссоздания его при активации. Существует также возможность оставить в пассивном состоянии открытое соединение, когда компонент должен быть уничтожен контейнером (например, из-за генерирования в методе исключительной ситуации времени выполнения).

Самой большой проблемой модели cached-handle является то, что когда один экземпляр компонента или сервлета поддерживает соединение, другой экземпляр не может использовать его, то есть должно быть как минимум столько же соединений, сколько экземпляров. Это показано на рисунке 2.


Рисунок 2. Модель cached-handle в действии
Рисунок 2. Модель cached-handle в действии

На рисунке 2 вы можете увидеть, что управляемое соединение связывается с описателем соединения при создании EJB-компонента (начало зеленой полоски) и не может использоваться впоследствии кем-нибудь, кроме этого экземпляра компонента (зеленая полоска продолжается бесконечно).

Спецификация JCA 1.5 решает данную проблему, предоставляя два новых интерфейса, приведенных в листинге 3.


Листинг 3. Интерфейсы для диссоциации и "ленивой" ассоциации
public interface DissociatableManagedConnection {

    void dissociateConnections() throws ResourceException;

}

public interface LazyAssociatableConnectionManager {

    void associateConnection(Object connection,
                             ManagedConnectionFactory mcf,
                             ConnectionRequestInfo cxReqInfo)
            throws ResourceException

}

Диссоциация

Управляемые адаптером ресурсов соединения реализуют первый интерфейс (интерфейс для диссоциации (dissociation)), чтобы уведомить менеджер соединений о поддержке адаптером такой оптимизации. Когда соединение временно выходит за пределы области видимости (то есть, когда метод компонента или сервлета возвращает управление), менеджер соединений может, если он тоже поддерживает такую оптимизацию, разорвать ассоциацию описателя соединения, поддерживаемую приложением, с управляемым соединением, которое представляет физический ресурс. Это позволяет возвратить в пул управляемое соединение для использования другими частями приложения.

"Ленивая" ассоциация

Вместо переназначения описателя соединения управляемому соединению при следующем вызове метода оптимизация использует "ленивую" ассоциацию (lazy association). Если метод не использует соединение, или вызывает только простые методы с описателем соединения, не требующие обращения к серверу, управляемое соединение не удаляется лишний раз из пула. Вместо этого, когда описатель соединения определяет, что больше не должен быть переназначен управляемому соединению, он может выполнить приведение типа менеджера соединений в LazyAssociatableConnectionManager и вызвать метод associateConnection. Этот метод принимает описатель соединения в качестве первого параметра, за которым следует фабрика соединений, и запрашивает информацию, переданную при первом вызове allocateConnection. Затем менеджер соединений ищет еще одно подходящее управляемое соединение в пуле и использует метод управляемого соединения associateConnection для связывания его с описателем соединения.

На рисунке 3 показан эффект от этой оптимизации при использовании модели cached-handle, приведенной выше на рисунке 2.


Рисунок 3. "Ленивая" ассоциация уменьшает объем используемых ресурсов
Рисунок 3. "Ленивая" ассоциация уменьшает объем используемых ресурсов

Пунктирные стрелки на рисунке 4 указывают на уведомление менеджера соединений EJB-контейнером при завершении работы метода. В этот момент управляемое соединение отделяется от описателя соединений, и только когда метод попытается использовать описатель, управляемое соединение ассоциируется с ним повторно. Короткая зеленая полоска показывает, как управляемое соединение теперь связывается с EJB-компонентом за более короткое время и, следовательно, может использоваться повторно в любом месте.



В начало


Зачислять или не зачислять

Каждому известно, что транзакции дороги, особенно XA (глобальные) транзакции. Но в любом случае очень важно не выполнять работы больше, чем необходимо. Еще одна пара новых интерфейсов в JCA 1.5 предотвращает ненужное зачисление (enlistment) объектов XAResource.

Давайте более подробно рассмотрим проблему, которую решает это улучшение. Предположим, что вы берете EJB-компонент, приведенный в листинге 1, и разворачиваете его, используя управляемые контейнером транзакции и транзакционный атрибут RequiresNew для бизнес-метода. При активации метода начинается новая транзакция. При создании соединения менеджер соединений ничего не знает о том, как оно будет использоваться, поэтому он должен получить XAResource из связанного управляемого соединения и зачислить его в транзакцию. Соединение может использоваться только для запроса к базе данных или вовсе не использоваться, но менеджер соединений все равно должен зачислить соединение на случай выполнения операции вставки или обновления. Это означает, что как минимум адаптер ресурсов должен начать, зафиксировать или отменить и завершить транзакцию на стороне сервера. На рисунке 4 показан этот поток событий.


Рисунок 4. Интенсивное транзакционное зачисление
Рисунок 4. Интенсивное транзакционное зачисление

На рисунке 4 вы можете увидеть, что XAResource зачисляется в транзакцию (то есть, получает поток start) сразу же после получения соединения. Это означает, что в ресурс нужно направить поток завершения при окончании транзакционного метода, даже если метод не использовал соединение транзакционным образом.

Если в транзакцию вовлекается другой ресурс, вам придется выполнить не нужную двухфазную фиксацию, вызывая дополнительный поток prepare. Единственной экономией здесь является то, что менеджер ресурсов все еще может возвратить XA_RDONLY (для операции "только чтение") из вызова prepare для уведомления о том, что он на самом деле ничего не сделал. Менеджер транзакций не должен направлять вызов завершения этому менеджеру ресурсов, и если только один менеджер ресурсов на самом деле выполнил какую-либо работу в транзакции, менеджер транзакций должен уметь избегать медленной операции записи в свой log-файл.

"Ленивое" зачисление ресурсов

К этому времени вы уже должны понимать, что нежелательно зачислять ресурсы в транзакцию, пока это станет абсолютно необходимым. Спецификация JCA 1.5 имеет решение: "ленивое" зачисление (lazy enlistment). В листинге 4 приведены два интерфейса, разработанные для поддержки такой оптимизации.

WebSphere закладывает фундамент JCA 1.5

IBM WebSphere® Application Server V5 устраняет недостатки модели соединений cached-handle расширением спецификации JCA 1.0, известным как интеллектуальные описатели соединений (smart connection handles). Спецификация JCA 1.5 взяла это расширение в модифицированной форме в виде двух интерфейсов (см. листинг 3).

Также для своей поддержки "ленивого" зачисления ресурсов JCA 1.5 позаимствовала из WebSphere Application Server V5 расширение отложенного зачисления ресурсов в транзакцию (deferred transaction enlistment).

Более подробная информация об этих расширениях WebSphere приведена в статье Кевина Келле (Kevin Kelle), размещенной на developerWorks (см. раздел "Ресурсы").


Листинг 4. Интерфейсы для "ленивого" зачисления ресурсов
public interface LazyEnlistableManagedConnection {

}

public interface LazyEnlistableConnectionManager {

    void lazyEnlist(ManagedConnection mc)
            throws ResourceException;

}

Интерфейс LazyEnlistableManagedConnection - это маркерный интерфейс, реализуемый управляемым соединением для уведомления менеджера соединений о том, что этому соединению не нужно интенсивное зачисление в существующую транзакцию при создании нового соединения в транзакции или в случае начала новой транзакции, когда соединение уже имеется. Если описатель соединения собирается выполнить некоторую работу, которая должна быть частью какой-нибудь транзакции, а его управляемое соединение еще не было зачислено, он должен определить, реализует ли менеджер соединений интерфейс LazyEnlistableConnectionManager. Если да, - он должен вызвать метод lazyEnlist, передавая управляемое соединение. Этот метод ничего не возвращает, но если транзакция связывается с вызывающим потоком, в этот момент зачисляется XAResource из управляемого соединения. Если соединение не зачислено в транзакцию, необходимо вызывать lazyEnlist повторно перед каждой последующей частью работы, для того чтобы проверить, началась ли транзакция после последнего вызова этого метода.

На рисунке 5 показана новая последовательность событий.


Рисунок 5. "Ленивое" транзакционное зачисление
Рисунок 5. "Ленивое" транзакционное зачисление

На рисунке 5 можно увидеть, что XAResource больше не зачисляется при получении соединения. Вместо этого менеджер соединений ожидает, пока соединение не уведомит вызовом lazyEnlist о намерении выполнить некоторую транзакционную работу перед зачислением XAResource.



В начало


Когда что-то не работает

Первая версия спецификации JCA предоставляла для ресурсов адаптера механизм уведомления менеджера соединений о том, что с соединением что-то не в порядке. Это был метод connectionErrorOccurred интерфейса ConnectionEventListener. При получении этого уведомления менеджер соединений уничтожал управляемое соединение, передавшее событие, для того чтобы оно больше не использовалось. Все это очень хорошо. Но если, например, соединение с севером терялось, очень вероятно, что становились неработоспособными также и другие управляемые соединения в пуле.

JCA 1.5 представила элегантное решение данной проблемы в виде интерфейса ValidatingManagedConnectionFactory, приведенного в листинге 5.


Листинг 5. Интерфейс для определения неработающих соединений
public interface ValidatingManagedConnectionFactory {

    Set getInvalidConnections(Set connectionSet)
            throws ResourceException;

}

Реализуемый фабрикой управляемых соединений, интерфейс ValidatingManagedConnectionFactory содержит единственный метод getInvalidConnections, который принимает набор управляемых соединений и возвращает подмножество, которое адаптер ресурсов считает нерабочими. Адаптер ресурсов может применять любую форму проверки работоспособности, но обычно она заключается в передаче серверу какой-нибудь формы команды "ping" для тестирования соединения. Менеджер соединений может затем вызвать этот метод, когда адаптер ресурсов указывает на ошибку соединения, или даже периодически удалять поврежденные соединения из пула.



В начало


Начало и конец

Первая версия JCA обеспечивала подробную модель жизненного цикла для управляемых соединений и связанных с ними описателей соединений, но в нее не была включена аналогичная концепция для адаптера ресурсов в целом. Первым моментом, когда развернутый адаптер ресурсов узнавал о своем существовании на сервере приложений, было создание фабрики управляемых соединений. Это было исправлено в JCA 1.5 путем введения интерфейса ResourceAdapter, приведенного в листинге 6.


Листинг 6. Методы цикла жизни в новом интерфейсе адаптера ресурсов
public interface ResourceAdapter {

    void start(BootstrapContext ctx)
            throws ResourceAdapterInternalException;

    void stop();

    ...

}

Адаптер ресурсов может дать имя классу, реализующему этот интерфейс в элементе resourceadapter-class в своем дескрипторе развертывания (ra.xml). Кроме реализации интерфейса ResourceAdapter класс может поддерживать несколько свойств через шаблон JavaBean. Как и для фабрик управляемых соединений, эти свойства объявляются в дескрипторе развертывания вместе с их значениями по умолчанию (см. листинг 7). После установки адаптера ресурсов сервер приложений должен разрешить администратору переопределять эти значения по умолчанию.


Листинг 7. Пример дескриптора развертывания адаптера ресурсов
<connector>
  ...
  <resourceadapter>
    <resourceadapter-class>
      example.ExampleResourceAdapterImpl
    </resourceadapter-class>
    <config-property>
      <config-property-name>ServerName</config-property-name>
      <config-property-type>java.lang.String</config-property-type>
      <config-property-value>MyServer</config-property-value>
    </config-property>
    <config-property>
      <config-property-name>PortNumber</config-property-name>
      <config-property-type>java.lang.String</config-property-type>
      <config-property-value>1976</config-property-value>
    </config-property>
  </resourceadapter>
  ...
</connector>

В начале работы сервер приложений создает экземпляр класса, указанного в дескрипторе развертывания, и устанавливает свойства, указанные администратором. Класс должен реализовывать метод equals, основанный на этих свойствах, для того чтобы сервер приложений мог гарантировать создание только одного эквивалентного экземпляра. Затем вызывается start, в который передается объект, реализующий интерфейс BootstrapContext. Вы можете использовать этот объект для создания таймеров, планирования работы в других потоках и для управления импортируемыми транзакциями. Данные вопросы я подробно рассматриваю во второй части данной серии статей. Метод не должен блокировать работу, а должен возвращать управление через какое-то время.

Сервер приложений обычно вызывает метод stop адаптера ресурсов перед остановкой своей работы или перед отменой развертывания адаптера ресурсов. Спецификация JCA 1.5 описывает две фазы этого процесса. Первая - сервер приложений останавливает все приложения, зависящие от останавливаемого адаптера ресурсов. Это гарантирует, что потоки приложения больше не используют объекты адаптера ресурсов и что все транзакции завершены. Затем сервер приложений вызывает метод stop. В этот момент адаптер ресурсов должен выполнить корректную остановку своей работы (например, освободить сетевые и прикладные ресурсы, записать все данные из кэша на сервер). После вызова метода stop сервер приложений не может снова использовать экземпляр адаптера ресурсов.

Интерфейс ManagedConnectionFactory остается неизменным для обеспечения обратной совместимости, но если вы хотите, чтобы исходящие ресурсы имели доступ к возможностям, обеспечиваемым адаптером ресурсов, реализуйте также новый интерфейс ResourceAdapterAssociation, приведенный в листинге 8.


Листинг 8. Интерфейс ResourceAdapterAssociation
public interface ResourceAdapterAssociation {

    ResourceAdapter getResourceAdapter();
    void setResourceAdapter(ResourceAdapter ra)
            throws ResourceException;

}

После создания фабрики управляемых соединений сервер приложений вызовет метод setResourceAdapter для связывания ее с адаптером ресурсов. Эта ассоциация затем фиксируется на время жизни фабрики управляемых соединений. Метод вызывается только один раз.



В начало


Заключение

В данной статье я рассмотрел четыре улучшения, которые JCA 1.5 привнесла в существующие исходящие соглашения. "Ленивая" ассоциация и оптимизация зачисления ресурсов должны увеличить производительность приложений, использующих соединения, а проверка фабрики управляемых соединений должна улучшить обработку при каких-либо нарушениях в работе. Добавление функциональности управления циклом жизни на уровне адаптера ресурсов открывает для них множество новых интересных возможностей. Во второй части данной серии статей мы рассмотрим, как новые соглашения по управлению работой и поступлению транзакций используют этот фундамент.



Ресурсы



Об авторе

Дэвид Карри (David Currie) недавно пришел в IBM Software Services for WebSphere, базирующуюся в Hursley, Великобритания. До этого он занимался разработкой WebSphere Application Server, сначала транзакциями, а затем проектированием и реализацией JCA-адаптеров ресурсов для поддержки систем обмена сообщениями. Связаться с ним можно по адресу david_currie@uk.ibm.com.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



ДаНетНе знаю
 


 


12345
 


В начало


IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.

    IBM в России Конфиденциальность Контакты