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

Время ожидания метода MSMQ Receive()

Недавно мой оригинальный вопрос был MSMQ Slow Queue Reading, однако я перешел от этого, и теперь думаю, что я знаю проблему немного понятнее.

Мой код (ну, собственно, часть библиотеки с открытым исходным кодом, которую я использую) выглядит следующим образом:

queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic);

Что использует функция Messaging.MessageQueue.Receive, а очередь - MessageQueue. Проблема заключается в следующем.

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

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

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

Я проверил много разных вещей, и все кажется нормальным и не отличается от очереди, которая работает нормально. Существует много свободного места на диске (13gig free) и RAM (около 350 МБ освобождает 1GB от того, что я могу сказать). Я проверил записи в реестре, которые все выглядят так же, как и другие очереди, и монитор производительности не показывает ничего из нормального. Я также запускаю инструмент TMQ и не вижу ничего подобного.

Я использую Windows XP на всех компьютерах, и все они имеют установленный пакет обновления 3. Я не отправляю большое количество сообщений в очереди, самое большее это будет 1 раз в 2 секунды, но, как правило, намного реже. Сообщения также малы и нигде рядом с пределом 4 МБ.

Единственное, что я только что заметил, это файлы p0000001.mq и r0000067.mq в папке C:\WINDOWS\system32\msmq\storage, равны 4,096KB, однако они являются такими же размерами и на других компьютерах, которые в настоящее время не испытывают проблема. Проблема не возникает с каждой очередью на компьютере сразу, так как я могу воссоздать 1 очередь задач на компьютере, а остальные очереди все еще испытывают проблему.

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

В настоящее время ситуация такова:

  • ComputerA - 4 очереди в обычном режиме
  • ComputerB - 2 очереди, испытывающие проблемы, 1 обычная очередь
  • Проблемы с системой ComputerC - 2
  • ComputerD - 1 очередь обычная
  • ComputerE - 2 очереди в обычном режиме

Итак, у меня есть большое количество компьютеров/очередей для сравнения и тестирования.

4b9b3361

Ответ 1

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

class MSMQListener
{
    public void StartListening(string queuePath)
    {
        MessageQueue msQueue = new MessageQueue(queuePath);
        msQueue.ReceiveCompleted += QueueMessageReceived;
        msQueue.BeginReceive();
    }

    private void QueueMessageReceived(object source, ReceiveCompletedEventArgs args)
    {
        MessageQueue msQueue = (MessageQueue)source;

        //once a message is received, stop receiving
        Message msMessage = null;
        msMessage = msQueue.EndReceive(args.AsyncResult);

        //do something with the message

        //begin receiving again
        msQueue.BeginReceive();
    }
}

Ответ 2

Мы также используем NServiceBus и имели аналогичную проблему внутри нашей сети.

В основном MSMQ использует UDP с двухфазными фиксациями. После получения сообщения оно должно быть подтверждено. Пока он не будет подтвержден, он не может быть получен на стороне клиента, поскольку транзакция приема не была завершена.

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

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

Ответ 3

Попробуйте это

общий прием сообщений (тайм-аут TimeSpan, курсор)

перегруженная функция.

Чтобы получить курсор для MessageQueue, вызовите метод CreateCursor для этой очереди.

Курсор используется с такими методами, как Peek (TimeSpan, Cursor, PeekAction) и Receive (TimeSpan, Cursor), когда вам нужно читать сообщения, которые не находятся в передней части очереди. Это включает в себя чтение сообщений синхронно или асинхронно. Курсоры не должны использоваться для чтения только первого сообщения в очереди.

При чтении сообщений в транзакции Message Queuing не откатывает движение курсора, если транзакция прервана. Например, предположим, что есть очередь с двумя сообщениями: A1 и A2. Если вы удалите сообщение A1 во время транзакции, Message Queuing переместит курсор на сообщение A2. Однако, если транзакция прерывается по какой-либо причине, сообщение A1 вставляется обратно в очередь, но курсор остается указывать на сообщение A2.

Чтобы закрыть курсор, вызовите Close.

Ответ 4

Если вы хотите использовать что-то полностью синхронное и без события, вы можете протестировать этот метод

public object Receive(string path, int millisecondsTimeout)
{
    var mq = new System.Messaging.MessageQueue(path);
    var asyncResult = mq.BeginReceive();
    var handles = new System.Threading.WaitHandle[] { asyncResult.AsyncWaitHandle };
    var index = System.Threading.WaitHandle.WaitAny(handles, millisecondsTimeout);
    if (index == 258) // Timeout
    {
        mq.Close();
        return null;
    }
    var result = mq.EndReceive(asyncResult);
    return result;
}