Подтвердить что ты не робот

Параллельный синхронный запрос-ответ с JMS/ActiveMQ - шаблоны/библиотеки?

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

В Как мне реализовать ответ запроса с JMS?, ActiveMQ, похоже, препятствует идее временных или временных запросов на запрос или временных потребителей селекторов на JMSCorrelationID, из-за накладных расходов, связанных с их разворачиванием.

Однако, если я использую объединенные потребители для ответов, как мне отправить от потребителя ответа обратно в исходный запрашивающий поток?

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

Эта страница ActiveMQ рекомендует Lingo, которая не обновлялась с 2006 года, и Camel Spring Remoting, который был предан моей команде за ее многочисленные ошибки.

Есть ли лучшее решение в виде библиотеки, реализующей этот шаблон, или в виде другого шаблона для имитации синхронного запроса-ответа по JMS?


Связанный вопрос SO:

4b9b3361

Ответ 1

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

Тем не менее, все это упражнение заставляет меня переосмыслить JMS vs HTTP...:)

Ответ 2

В прошлом проекте у нас была аналогичная ситуация, когда запрос WS-синхронизации был обработан с помощью пары сообщений JMS Async req/res. Мы использовали Jboss JMS impl в это время и временные destinations, где большие накладные расходы.

Мы закончили тем, что написали потокобезопасный диспетчер, оставив WS до тех пор, пока не поступит ответ JMS. Мы использовали CorrelationID для сопоставления ответа на запрос.

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

BlockingMap

Если ваше решение является кластеризованным, вам нужно позаботиться о том, чтобы ответные сообщения отправлялись вправо node в кластере. Я не знаю ActiveMQ, но я помню, что сообщения JBoss имеют некоторые сбои под капотом для их кластеризуемых мест назначения.

Ответ 3

Я бы по-прежнему думал об использовании Camel и позволял ему обрабатывать потоки, возможно, без spring -remoting, а просто raw ProducerTemplates.

У Camel есть хорошая документация по этой теме и очень хорошо работает с ActiveMQ. http://camel.apache.org/jms#JMS-RequestreplyoverJMS

В связи с вопросом о том, как создавать потребитель, основанный на селекторе, и накладные расходы, то, что фактические документы ActiveMQ на самом деле заявляют, заключается в том, что для этого требуется обратная связь с брокером ActiveMQ, который может находиться на другой стороне земного шара или в сети с высокой задержкой, Накладные расходы в этом случае - это время прохода TCP/IP в брокером AMQ. Я бы рассматривал это как вариант. Использовали это с разумом с успехом.

Ответ 4

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

http://www.eaipatterns.com/RequestReplyJmsExample.html имеет решения основного потока буксировки с использованием responseToQueue или идентификатора корреляции.

Ответ 5

Это старый, но я приземлился здесь, ища что-то еще, и на самом деле имею некоторые идеи (надеюсь, будет полезно кому-то).

Мы реализовали очень похожий случай использования с Hazelcast, являющимся нашим шасси для кластерное межсетевое измельчение. Сущность - это 2 набора данных: 1 распределенная карта для ответов, 1 "локальный" список ожидающих ответа (на каждом node в кластере).

  • каждый запрос (получающий его собственный поток от Jetty) создает запись на карте локальных ожидающих; запись имеет, очевидно, корреляционный UID и объект, который будет служить семафором
  • тогда запрос отправляется на удаленный (REST/JMS), и исходный поток начинает ждать на семафоре; UID должен быть частью запроса
  • удаленный возвращает ответ и записывает его в карту ответов с коррелированным UID
  • отображает карту ответов; если UID нового входящего ответа найден на карте локальных ожидающих, он уведомляется о семафоре, издает исходный поток запросов, набирает ответ с карты ответов и возвращает его клиенту.

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