Как EJB может распараллелить длинный процесс, интенсивно использующий процессор? - PullRequest
13 голосов
/ 05 января 2010

Приложение имеет длительный процесс с интенсивным использованием ЦП, который в настоящее время выполняется последовательно на одном сервере (метод EJB), когда клиент запрашивает его.

Теоретически возможно (с концептуальной точки зрения) разделить этот процесс на N порций и выполнить их параллельно, при условии, что выходные данные всех параллельных заданий могут быть собраны и объединены перед отправкой обратно клиенту инициировал процесс. Я хотел бы использовать это распараллеливание для оптимизации производительности.

Как я могу реализовать это распараллеливание с EJB? Я знаю, что мы не должны создавать потоки в методе EJB. Вместо этого мы должны публиковать сообщения (по одному на задание), которые будут использоваться компонентами, управляемыми сообщениями (MDB). Но тогда это больше не будет синхронный вызов. И синхронность, по-видимому, является обязательным требованием в этом случае, поскольку мне нужно собрать выходные данные всех заданий, прежде чем отправить их обратно клиенту.

Есть ли решение для этого?

Ответы [ 6 ]

10 голосов
/ 05 января 2010

Есть множество способов сделать это.

Во-первых, вы можете использовать EJB Timer для создания однократного запуска процесса, который начнется немедленно. Это хорошая техника для порождения процессов в фоновом режиме. Таймер EJB связан с конкретной реализацией Session Bean. Вы можете либо добавить таймер EJB к каждому сессионному компоненту, который вы хотите сделать, либо у вас может быть один сессионный компонент, который затем может вызывать логику вашего приложения через некоторый механизм диспетчеризации.

Для меня я передаю сериализуемый блоб параметров вместе с именем класса, которое соответствует определенному интерфейсу, универсальному сессионному компоненту, который затем выполняет класс. Таким образом, я могу легко справиться с чем угодно.

Одно предупреждение о таймере EJB - это то, что таймеры EJB являются постоянными. После создания EJB-таймер остается в контейнере, пока его работа не будет завершена или отменена. Причиной этого является то, что если у вас длительный процесс, а сервер отключается, то при перезапуске процесс продолжится и возобновит работу. Помните, что это может быть хорошо, но только если ваш процесс готов к повторному запуску. Но если у вас есть простой процесс, повторяющий «10000 элементов», если сервер отключается на 9999 элементах, когда он возвращается, вы можете легко увидеть, что он просто начинается с первого элемента. Это все выполнимо, просто предостережение из.

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

Самое умное здесь, и кое-что, что я также сделал, используя работу с Timer Bean, заключается в том, что вы можете контролировать, сколько «заданий» будет выполняться, исходя из того, сколько экземпляров MDB вы настроили в системе.

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

Это на самом деле работает на удивление хорошо. Есть небольшие накладные расходы, которые разделяют процесс и направляют его через очередь JMS, но это все, по сути, «время запуска». Как только это начнется, вы получите реальную выгоду.

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

Я обнаружил, что после того, как вы перешли на длительный процесс в фоновом режиме, вы можете заплатить цену за мгновенный доступ к этому процессу. То есть, нет никакой причины непосредственно контролировать исполняющие классы, просто пусть они публикуют интересную информацию и статистику в базе данных, или JMX, или что-то еще, вместо того, чтобы иметь что-то, что может контролировать объект напрямую, потому что он разделяет то же пространство памяти.

Мне было легко настроить инфраструктуру, позволяющую запускать задачи либо на EJB Timer, либо в очереди разброса MDB, задачи одинаковы, и я мог отслеживать их выполнение, останавливать их и т. Д.

Вы можете комбинировать технику рассеяния для создания нескольких заданий таймера EJB. Одним из бесплатных преимуществ MDB является то, что он действует как пул потоков, который может ограничивать ваши задания (поэтому вы не переполняете свою систему слишком большим количеством фоновых процессов). Вы получаете это «бесплатно», просто используя функции управления EJB в контейнере.

Наконец, в Java EE 6 появился новый «асинхронный» (или что-то) квалификатор для методов Session Bean. Я не знаю подробностей о том, как это работает, поскольку мне еще предстоит поиграть с новым контейнером Java EE 6. Но я думаю, вы, вероятно, не захотите менять контейнеры только для этого объекта.

6 голосов
/ 05 января 2010

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

Используйте WorkManager из API Commonj. Он учитывает управляемые потоки в контейнере Java EE и специально разработан для вашего случая использования. Если вы используете WebSphere или WebLogic, эти API уже доступны на вашем сервере. Для других вам придется внедрить стороннее решение в себе.

Информация WorkManager

Похожие вопросы Почему нереста не рекомендуется

4 голосов
/ 05 января 2010

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

Ситуация, в которой вы находитесьОписание чисто и правильно обрабатывается архитектурой, основанной на событиях, с серверной частью обмена сообщениями.Начальное событие инициирует процесс (который затем может быть тривиально распараллелен, если рабочие подписываются на тему события), а сам процесс агрегации вызывает событие по его завершении.Вы по-прежнему можете сжать эту последовательность в пределах цикла запрос / ответ, но при необходимости вы нарушите букву и дух спецификаций архитектуры системы Java EE.

2 голосов
/ 04 апреля 2014

Назад в будущее - Java EE 7 имеет гораздо больше поддержки параллелизма через ManagedThreadFactory, службу ManagedExecutor и т. Д. (JSR 236: Утилиты параллелизма для Java EE), с помощью которых вы можете создавать свои собственные «управляемые» потоки. Это больше не табу в EE AS ​​поддерживает его (Wildfly?) через использование ManagedThread * API's

Подробнее

https://jcp.org/aboutJava/communityprocess/ec-public/materials/2013-01-1516/JSR236-EC-F2F-Jan2013.pdf http://docs.oracle.com/javaee/7/tutorial/doc/concurrency-utilities002.htm

1 голос
/ 05 января 2010

Вы достаточно хорошо проанализировали ситуацию, и нет, для этого нет паттерна, соответствующего модели EJB.

Создание потоков в основном запрещено, поскольку оно обходится без приложения . стратегия управления потоком сервера, а также из-за транзакций 1006 *.

Я работал над проектом с аналогичными требованиями и решил порождать дополнительные потоки (в отличие от sepc). Операция распараллеливания была доступна только для чтения, поэтому она работала в отношении транзакции (поток, по сути, не имел бы транзакцию, связанную с ними). Я также знал, что не буду создавать слишком много потоков на вызовы EJB, поэтому количество потоков не было проблемой. Но если ваши потоки должны изменять данные, то вы серьезно нарушаете транзакционную модель EJB. Но если вы работаете в чистых вычислениях, это может быть нормально.

Надеюсь, это поможет ...

1 голос
/ 05 января 2010

Однажды я участвовал в проекте, в котором транзакции EJB выполнялись до 5 часов одновременно. Aargh!

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

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

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

...