Обеспечение последовательной обработки JMS-сообщений в кластере OC4J

У нас есть приложение, которое обрабатывает JMS-сообщение с помощью управляемого сообщениями bean-компонента. Это приложение развернуто на сервере приложений OC4J. (10.1.3)

Мы планируем развернуть это приложение на нескольких серверах приложений OC4J, которые будут настроены для работы в кластере.

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

Знаете ли вы о параметре конфигурации, который будет управлять обработкой сообщений в кластере OC4J?

Или вы думаете, что мы должны реализовать наш собственный код синхронизации, который будет синхронизировать компоненты, управляемые сообщениями, в кластере?


person Ladislav Petrus    schedule 11.09.2009    source источник
comment
Ребята, спасибо за понимание дизайна. Уверяю, с дизайном все в порядке. Основная цель приложения - не обрабатывать jms-сообщения, очередь предназначена только для обработки задач, которые могут выполняться в фоновом режиме и не требуют высокой производительности. Требование к этим сообщениям состоит в том, что они должны обрабатываться в том порядке, в котором они были помещены, а также они не должны обрабатываться параллельно, иначе произойдет olc. Вопрос в том, есть ли простой способ настроить приложение j2ee, работающее в кластере, чтобы иметь только один активный mdb?   -  person Ladislav Petrus    schedule 12.09.2009
comment
Конечно, вы можете использовать описанный мной механизм аренды с однократной арендой. это действительно просто, особенно если где-то уже есть база данных.   -  person Don Branson    schedule 12.09.2009
comment
Итак, какой уровень пропускной способности вам нужен? сколько сообщений в секунду, например?   -  person Don Branson    schedule 12.09.2009
comment
Прежде всего, спасибо за ответы и потраченное время. Опишу наше приложение более подробно. Наше приложение представляет собой веб-приложение интрасети с ограниченной пользовательской базой, поэтому мы не ожидаем увеличения нагрузки на приложение. Он уже внедрен в производственную среду в течение трех лет. Теперь наш заказчик хочет развернуть приложение в кластере с балансировкой нагрузки, в основном из-за надежности оборудования. В настоящее время он развернут в кластере с ручным аварийным переключением. Нам необходимо адаптировать дизайн части обработки JMS, чтобы гарантировать последовательную обработку сообщений.   -  person Ladislav Petrus    schedule 12.09.2009
comment
Мы не требуем увеличения скорости обработки сообщений, поэтому в настоящее время ищем решение, требующее минимальных усилий. Лучшим подходом было бы изменить конфигурацию mdb, но неясно, позволяет ли конфигурация mdb контролировать количество экземпляров mdb в кластере. Другой возможностью было бы изменить конфигурацию расширенной очереди oracle, чтобы разрешить только одну активную транзакцию, но документация по oracle aq не дает никаких намеков на то, что было бы правильным подходом.   -  person Ladislav Petrus    schedule 12.09.2009
comment
Мы рассматриваем разработку индивидуального решения для синхронизации как крайний вариант. В этом случае, насколько нам известно, нам придется отказаться от концепции mdbs и разработать собственную архитектуру обработки сообщений, которая позволит нам синхронизировать экземпляры кластера.   -  person Ladislav Petrus    schedule 12.09.2009
comment
Я обновил свой ответ, чтобы ответить на приведенные выше комментарии.   -  person Don Branson    schedule 12.09.2009


Ответы (3)


Я выполнил последовательную обработку сообщений в кластере в довольно большом масштабе - 1,5 миллиона + сообщений в день, используя комбинацию паттерна «Конкурирующие потребители» и паттерна аренды.

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

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

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

Редактировать:

Я объясняю это решение более подробно здесь: http://coders-log.blogspot.com/2008/12/favorite-projects-series-installment-2.html

Редактировать:

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

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

Итак, позвольте мне предложить это. В момент, когда ваш MDB регистрируется для получения сообщений из очереди, он должен проверить распределенную блокировку и посмотреть, сможет ли он ее захватить. Первый MDB, который захватит блокировку, побеждает, и только он зарегистрируется для получения сообщений. Итак, теперь у вас есть сериализация. Какую форму должен принимать этот замок? Есть много возможностей. Ну как насчет этого. Если у вас есть доступ к базе данных, ее транзакционная блокировка уже дает вам кое-что из того, что вам нужно. Создайте таблицу с одной строкой. В строке указан идентификатор сервера, на котором в данный момент находится блокировка, и время истечения срока действия. Это аренда сервера. У каждого сервера должен быть способ сгенерировать свой уникальный идентификатор, например, имя сервера плюс идентификатор потока.

Если сервер может получить доступ к обновлению строки, а срок аренды истек, он должен получить ее. В противном случае он сдается. Если он получает аренду, ему необходимо обновить строку, указав время в ближайшем будущем, например, пять минут или около того, и зафиксировать обновление. Активный сервер должен обновить аренду до истечения ее срока. Я рекомендую обновлять его, когда остается половина времени, поэтому каждые 2-1 / 2 минуты, если срок аренды истекает через пять. Теперь у вас есть аварийное переключение. Если активный MDB умирает, его возьмет на себя другой MDB (и только один).

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

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

Да, и между прочим - убедитесь, что администраторы сервера используют NTP для разумной синхронизации часов.

person Don Branson    schedule 11.09.2009
comment
Спасибо за подсказку! Читая ваш ответ, я вспомнил, что мы полностью забыли о методах жизненного цикла MDB. Я думаю, мы сможем разработать простой механизм, который будет зависеть только от этих методов, чтобы гарантировать, что только один MDB обрабатывает сообщения в кластере. Мы будем использовать механизмы блокировки, предоставляемые базой данных oracle (dbms_lock). Когда у нас будет рабочее решение, я опубликую подробности. - person Ladislav Petrus; 12.09.2009

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

Используете ли вы реализацию JMS по умолчанию с OC4J или другую?

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

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

person SteveD    schedule 11.09.2009
comment
Мы используем расширенную очередь Oracle в качестве бэкэнда. - person Ladislav Petrus; 12.09.2009

Я согласен со Стивендиком: может быть, вы не в правильном направлении с дизайном. Что касается идентификатора последовательности или аналогичных подходов, я предлагаю вам получить представление об архитектурах обмена сообщениями с помощью Шаблоны интеграции предприятия: проектирование, создание и развертывание решений для обмена сообщениями (авторы Грегор Хопи и Бобби Вульф). Это отличная книга, множество полезных шаблонов ... Я уверен, что силы и проблема, с которой вы сталкиваетесь, хорошо описаны в ней.

person JuanZe    schedule 11.09.2009