Как избежать слишком большого количества экземпляров канала 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 и очередь на всю жизнь программы. Но может кто-нибудь сказать мне, почему мой предыдущий подход заключается в утечке ресурсов, и что я мог бы сделать с этим, если я выбрал этот путь?


ОБНОВЛЕНИЕ (2017-01-25)

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

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

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

Спектакль

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

Незафиксированные сообщения

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

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

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

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

Среда

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

2 ответа

Решение

Вот Это Да! Не очень эффективный код. Соединение является FAR самым дорогим вызовом 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() );
   }
}

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

Другие вопросы по тегам