Как избежать слишком большого количества экземпляров канала IBM MQ?

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

Что делаю, схематично:

  • qm = new MQQManager()
  • q = qm.accessQueue()
  • depth = q.getCurrentDepth()
  • (сделайте что-нибудь с depth)
  • q.close()
  • qm.close()

Это работает как шарм!

Из-за лени я написал свой код, чтобы каждый раз проходить все 6 шагов приведенной выше последовательности. В итоге я повторял этот цикл каждые 10 секунд. Примерно через полчаса люди, которые следят за сервером, сказали мне, что на нем открыто 153 экземпляра. Ясно, что простого выполнения close() в очереди и QM недостаточно, чтобы убрать за собой.

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


ОБНОВЛЕНИЕ (25 января 2017 г.)

Сроки и принятие

Роджер предоставил красивый код и несколько полезных пояснений по темам производительности и незафиксированных сообщений. Это круто, но ответа Евгения было ровно (и минимально) достаточно для решения моей проблемы, и он был немного быстрее. Мое маленькое приложение теперь делает именно то, что я хочу, после того как я просто изменил close() на disconnect() по совету Юджина. Теперь я немного разорван о том, кто должен получить галочку. Мои извинения вам обоим!

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

Производительность

Честно говоря, мне плевать на производительность. Сервер намного толще, чем необходимо для того, что он сейчас делает, и мой клиент мониторинга (тема этого вопроса) работает на машине разработки, которая обычно пуста. Я надеюсь, что он послужит своей цели в течение дня или двух, тогда я выброшу его. В то же время, если одно подключение каждые 10 секунд вызывает проблемы с производительностью, они должны балансировать нагрузку на Raspberry Pi или что-то в этом роде.

Неподтвержденные сообщения

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

моя настоящая проблема,

который включает в себя от нескольких до нескольких сотен сообщений с задержкой обработки от 5 до 20 минут примерно в одно и то же время каждое утро. Я подозреваю, что мой принимающий клиент зависает из-за «зависания» сетевой операции ввода-вывода с чем-то другим, кроме MQS. Один из шагов, которые я хочу предпринять в изучении этого, — продемонстрировать, что в MQS действительно существует очередь ожидающих сообщений, и она не обрабатывается. Я хотел бы увидеть, когда эта очередь начнет накапливаться, как долго она там будет находиться и как быстро она исчезнет, ​​как только мой клиент снова проснется.

Это соединение принимает от 2 000 до 10 000 сообщений в день с пиками, соответствующими пакетным процессам во второй половине дня и вечером, но задержки происходят только утром, часто с довольно небольшими объемами. Я хотел бы увидеть журнал размеров очередей, чтобы лучше понять, что происходит. В качестве следующего шага мне, вероятно, потребуется больше инструментовки в принимающем клиенте.

Окружающая среда

Что бы это ни стоило, на сервере работает WSMQ 6, поэтому мой клиент использует получение очереди с блокировкой и ожиданием, а не изящный асинхронный процесс уведомления, который я бы предпочел использовать. Мой получающий клиент — это автономное приложение C, работающее под RHEL на виртуальной машине.


person Carl Smotricz    schedule 23.01.2017    source источник
comment
Ответ Роджера включает в себя DISCONNECT и описание того, почему CONNECT каждые 10 секунд требует больших ресурсов и не должен быть разработан таким образом, и предоставляет рабочий пример кода для демонстрации. Ошеломленный, что это не был принятый ответ.   -  person T.Rob    schedule 25.01.2017
comment
@T.Rob: Простое объяснение: ответ Роджера великолепен, но в то время, когда я согласился, ответ Юджина был единственным. О, подождите, теперь я вижу, что могу изменить это. Готово, спасибо за подсказку!   -  person Carl Smotricz    schedule 25.01.2017


Ответы (2)


Ух ты! Не очень эффективный код. Соединение, безусловно, является самым дорогим вызовом MQ API. Также бессмысленно получать глубину очереди. Это дает вам ВСЕ незафиксированные и зафиксированные сообщения в очереди. то есть глубина очереди может сказать, что в очереди 5 сообщений, но ваша программа может получить только 3!! Вы бы сказали, что MQ не работает, но на самом деле 2 сообщения не переданы, следовательно, недоступны для потребителя.

Если вы действительно хотите получать и регистрировать информацию каждые 10 секунд, ОСТАВАЙТЕСЬ на связи.

Вот лучший способ сделать это:

boolean working = true;
int openOptions  = CMQC.MQOO_INQUIRE + CMQC.MQOO_FAIL_IF_QUIESCING;
int depth = 0;
MQQueueManager qm = null;
MQQueue q = null;

try
{
   qm = new MQQueueManager("MQA1");

   while (working)
   {
      try
      {
         q = qm.accessQueue("TEST.Q1", openOptions);
         depth = q.getCurrentDepth();
//         (do something with depth)
      }
      catch (MQException e)
      {
         System.out.println("CC = " + e.completionCode + " : RC=" + e.reasonCode);
         System.out.println(e.getLocalizedMessage() );
         working = false;
      }
      finally
      {
         if (q != null)
         {
            q.close();
            q = null;
         }
      }

      try
      {
         if (working)
            Thread.sleep(10*1000); // time in milliseconds
      }
      catch (InterruptedException ie) {}
   }
}
catch (MQException e)
{
   System.out.println("CC = " + e.completionCode + " : RC=" + e.reasonCode);
   System.out.println(e.getLocalizedMessage() );
}
finally
{
   try
   {
      if (q != null)
         q.close();
   }
   catch (MQException e)
   {
      System.out.println("CC = " + e.completionCode + " : RC=" + e.reasonCode);
      System.out.println(e.getLocalizedMessage() );
   }

   try
   {
      if (qm != null)
         qm.disconnect();
   }
   catch (MQException e)
   {
      System.out.println("CC = " + e.completionCode + " : RC=" + e.reasonCode);
      System.out.println(e.getLocalizedMessage() );
   }
}
person Roger    schedule 24.01.2017
comment
Боже, ты сделал большую часть моей работы! Спасибо. Я собираюсь ответить на ваш комментарий в тексте моего вопроса для уточнения, если вы хотите добавить больше обсуждения. - person Carl Smotricz; 25.01.2017

Я думаю, вам действительно следует использовать disconnect в блоке finally вместо close.

person Eugene    schedule 23.01.2017
comment
Сравнивая документы QM.close() и .disconnect(), становится почти очевидным, что мне следовало использовать именно функцию disconnect(). Спасибо!! - person Carl Smotricz; 24.01.2017