Кэширование удаленной ссылки EJB 3.0

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

Таким образом, мое решение было чем-то вроде этого: Я взял апачскую библиотеку пула свободного городского населения и использовал ее реализацию StackObjectPool для моего удаленного ejb ссылочного кэша.

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

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

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 назад для объединения после успешного invokacion

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

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

Что Вы думаете о таком подходе? Это корректно? Возможно, некоторые другие решения, советы?

7
задан nesvarbu 22 June 2010 в 11:08
поделиться

2 ответа

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

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

Разрешен получить ссылку на сессионный компонент и попытаться вызвать ту же ссылку объект одновременно из нескольких потоки. Однако полученный клиент поведение в каждом потоке зависит от семантика параллелизма целевой bean. См. Раздел 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
ответ дан 7 December 2019 в 01:16
поделиться

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

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

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

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

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

РЕДАКТИРОВАТЬ:

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

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

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

5
ответ дан 7 December 2019 в 01:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: