Как EJB может распараллелить длительный интенсивный процесс?

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

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

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

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

Ответ 1

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

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

Информация о WorkManager

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

Ответ 2

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

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

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

Одна оговорка о таймере EJB заключается в том, что таймеры EJB являются постоянными. Когда вы создаете EJB Timer, он остается в контейнере, пока его работа не будет закончена или отменена. Полученная информация заключается в том, что если у вас длительный процесс, а сервер опускается, при перезапуске процесс будет продолжаться и будет выполняться резервное копирование. Разумеется, это может быть хорошо, но только если ваш процесс готов к перезапуску. Но если у вас есть простой процесс, повторяющийся через "10 000 элементов", если сервер опускается на элемент 9999, когда он возвращается, вы можете легко увидеть его, просто начиная с пункта 1. Это все работает, просто предостережение, которое нужно знать из.

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

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

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

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

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

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

Я легко мог создать фреймворк, который позволяет запускать задание либо в таймере EJB, либо в очереди разброса MDB, задачи одинаковы, и я мог следить за их прогрессом, останавливать их и т.д.

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

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

Ответ 3

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

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

Ответ 4

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

Подробнее

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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

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