Кэширование удаленного эталона EJB 3.0 - PullRequest
7 голосов
/ 22 июня 2010

Я думал, как мне сэкономить время при поиске удаленной ссылки на ejb через jndi.У меня было приложение, которое должно было работать очень быстро, но оно также должно было вызывать удаленный ejb, что замедляло его.

Поэтому мое решение было примерно таким: я взял библиотеку apache commons-pool и использовал ее реализацию StackObjectPoolдля моего удаленного кеша ссылок ejb.

private static final ObjectPool pool = new StackObjectPool(new RemoteEjbFactory());

Factory выглядит примерно так:

public static class RemoteEjbFactory extends BasePoolableObjectFactory {

    @Override
    public Object makeObject() {
        try {
            return ServiceLocator.lookup(jndi);
        } catch (NamingException e) {
            throw new ConfigurationException("Could not find remote ejb by given name", e);
        }
    }
}

Затем я беру объект, заимствуя его из пула (если в пуле нет свободного объекта, он использует фабрикусоздать его):

SomeEjbRemote someEjb = null;
try {
        someEjb = (SomeEjbRemoteImpl) pool.borrowObject();
        someEjb.invokeRemoteMethod();
} catch (Throwable t) {
        if (someEjb != null) {
            pool.invalidateObject(someEjb);
        }
        pool.clear(); // Maybe its not neccessary
        someEjb = (SomeEjbRemoteImpl) pool.borrowObject();
        someEjb.invokeRemoteMethod(); // this time it should work
}

И, конечно, возвращать ejb обратно в пул после успешного вызова

finally {
    try {
         pool.returnObject(someEjb);
    } catch (Exception e) {
        logger.error("Could not return object to pool.", e);
    }
}

Как я понимаю, нет гарантии, что удаленная ссылка останется подключенной, поэтому, если мыперехватить исключение с помощью кэшированного удаленного ejb, мы просто аннулируем этот объект и повторяем попытку.

Что вы думаете о таком подходе?Это правильно?Может быть, какие-то другие решения, советы?

Ответы [ 2 ]

5 голосов
/ 22 июня 2010

из спецификации

3.4.9 Параллельный доступ к ссылкам на сессионный компонент

Допустимо получить ссылку на сессионный компонент и попытаться вызвать ту же ссылку объект одновременно из нескольких потоки. Тем не менее, в результате клиент поведение в каждом потоке зависит от семантика параллелизма целевой боб. См. Раздел 4.3.14 и раздел 4.8.5 для получения подробной информации о поведение параллелизма для сессионных компонентов.

Краткое содержание п. 4.3.14:

Если bean-компонент SLSB , каждый вызов будет обслуживаться одним EJB-компонентом в приложении. пул серверов. Приложение. Сервер синхронизирует вызовы экземпляров EJB, поэтому к каждому экземпляру EJB никогда не осуществляется одновременный доступ.

Для SFSB каждый вызов отправляется одному конкретному экземпляру EJB и приложению. Сервер не синхронизирует звонок. Таким образом, два одновременных вызова удаленной ссылки могут привести к одновременному доступу к экземпляру EJB, в результате чего получится javax.ejb.ConcurrentAccessException. Клиент отвечает за правильную синхронизацию доступа к удаленной ссылке.

И § 4.8.5 - о синглтоне EJB, вероятно, не о том, что вы используете.

Я предполагаю, что вы используете SLSB, поэтому вам не нужно иметь пул на стороне клиента: найдите удаленный компонент один раз и используйте одну и ту же ссылку из нескольких потоков.

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

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

Мои 2 цента

5 голосов
/ 22 июня 2010

Я отвечаю за JBoss AS, так как у меня ограниченный опыт работы с другими AS: s.

Удаленные JNDI-ссылки - это просто (балансировка нагрузки) прокси-серверы без соединения (см. Архитектура прокси кластеризации JBoss ). Сериализация их - это хорошо, это означает, что вы можете сохранять их как члены в других EJB-компонентах и ​​кэшировать их, как вы делаете (я не знаю, сериализует ли ваш пул ваши объекты, некоторые кеши делают).

Относительно аннулирования прокси: Прокси-серверы будут открывать соединение только на время вызова метода и, следовательно, не имеют «подключенного» состояния как такового. Прокси могут дополнительно иметь несколько IP-адресов и балансировку нагрузки. В JBoss список узлов динамически обновляется при каждом вызове метода, поэтому риск устаревания ссылки невелик. Тем не менее, существует вероятность того, что это произойдет, если все узлы выйдут из строя или прокси останется неактивным, а все IP-адреса узлов устареют. В зависимости от политики повторного использования пула (LRU или другой?) Вероятность того, что остальные кэшированные прокси-серверы будут недействительными, один из них будет варьироваться. Справедливая политика сведет к минимуму риск наличия в пуле очень старых записей, которых вы бы хотели избежать в этом сценарии.

При наличии справедливой политики вероятность того, что все устареют по одной и той же причине, возрастет, и ваша политика «чистого пула, если одна устарела» будет иметь смысл. Кроме того, вам нужно принять во внимание случай, когда другой узел не работает. Как и сейчас, ваш алгоритм перейдет в занятый цикл, просматривая ссылки, пока другой узел не работает. Я бы реализовал экспоненциальный откат для повторных попыток или просто рассмотрел бы его как фатальный сбой и сделал бы исключение исключением времени выполнения, в зависимости от того, можете ли вы жить с удаленным удаленным EJB-компонентом на время или нет. И сделайте исключение, которое вы отлавливаете, конкретным (например, RemoteCommunicationFailedException), избегайте отлова общих исключений или ошибок, таких как Exception, Error или Throwable.

Другой вопрос, который вы должны задать себе, - это количество параллелизма, которое вы хотите. Обычно прокси являются поточно-ориентированными для SLSB и однопоточными только для SFSB. Сами SFSB не являются поточно-ориентированными, а SLSB сериализуют доступ по умолчанию. Это означает, что, если вы не включите параллельный доступ к вашим EJB 3.1 bean-компонентам (см. tss link ), вам понадобится одна удаленная ссылка на поток. То есть: объединение N удаленных ссылок SLSB даст вам N потоков одновременного доступа. Если вы включаете параллельный доступ и пишете свой SLSB в виде потоково-безопасного компонента с аннотацией @ConcurrencyAttribute(NO_LOCK), вы можете получить неограниченный параллелизм только с одним прокси-сервером и удалить весь пул. Ваш выбор.

EDIT:

ewernli был прав: потокобезопасный SLSB-прокси создает один новый экземпляр на сервере за вызов. Это указано в 4.3.14:

Нет необходимости в каких-либо ограничениях против одновременного доступа клиента к сессионные компоненты без сохранения состояния, потому что Контейнер направляет каждый запрос к другой экземпляр лица без гражданства класс сессионного компонента.

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

...