Как установить тайм-аут на сервере RabbitMQ?
Я пытаюсь RabbitMQ с this python.
Одна вещь, которую я заметил, заключается в том, что если я убиваю потребителя нечисто (эмулируя разбитую программу), сервер будет думать, что этот потребитель все еще существует надолго. Результатом этого является то, что любое другое сообщение будет проигнорировано.
Например, если вы убили потребителя 1 раз и снова подключитесь, то сообщения 1/2 будут проигнорированы. Если вы убьете другого потребителя, то 2/3 сообщения будут проигнорированы. Если вы убьете третью, тогда 3/4 сообщения будут проигнорированы и так далее.
Я попытался включить подтверждения, но, похоже, это не помогает. Единственное решение, которое я нашел, - это вручную остановить сервер и reset его.
Есть ли лучший способ?
Как воссоздать этот сценарий
-
Запустите rabbitmq.
-
Unarchive эта библиотека.
-
Загрузите пользователя и издателя здесь.
Запустите amqp_consumer.py дважды. Запустите amqp_publisher.py, загрузив некоторые данные и наблюдайте, что он работает так, как ожидалось. Сообщения получаются в круговом стиле.
-
Убейте один из потребительских процессов с помощью kill -9 или диспетчера задач.
-
Теперь, когда вы публикуете сообщение, 50% сообщений будут потеряны.
Ответы
Ответ 1
Я не вижу amqp_consumer.py
или amqp_producer.py
в tarball, поэтому воспроизведение ошибки сложнее.
RabbitMQ завершает соединения, освобождая их неподтвержденные сообщения для повторной доставки другим клиентам, всякий раз, когда операционная система сообщает, что сокет закрыт. Ваши симптомы очень странные, даже если kill -9
должен правильно очистить сокет TCP.
Некоторые люди заметили проблемы с продолжением сокетов дольше, чем при работе с брандмауэром или устройством NAT между клиентами AMQP и сервером. Может быть, это проблема, или вы запускаете все на локальном хосте? Кроме того, в какой операционной системе вы используете различные компоненты системы?
ETA: Из вашего комментария ниже, я предполагаю, что, хотя вы используете сервер в Linux, вы можете запускать клиентов в Windows. Если это так, то может случиться так, что драйвер Windows TCP не закрывает сокеты правильно, что отличается от поведения kill-9 в Unix. (В Unix ядро будет правильно закрывать TCP-соединения для любого убитого процесса.)
Если это так, то плохая новость заключается в том, что RabbitMQ может освобождать ресурсы только при закрытии сокета, поэтому, если клиентская операционная система этого не делает, ничего не может сделать. Это то же самое, что и почти все другие службы на основе TCP.
хорошие новости, тем не менее, заключается в том, что AMQP поддерживает вариант "heartbeat" для этих случаев, когда сетевая структура ненадежна. Вы можете попробовать включить биения сердца. Когда они включены, если сервер не получает никакого трафика в пределах настраиваемого интервала, он решает, что соединение должно быть мертвым.
плохая новость, однако, заключается в том, что я не думаю, что py-amqplib поддерживает heartbeats на данный момент. Стоит попробовать, хотя!
Ответ 2
RabbitMQ не имеет тайм-аута на подтверждение от клиента, что сообщение обработано: см. этот пост (весь поток может быть представляет интерес). Некоторые важные пункты с поста:
Модель AMQP ack для подписки и "pull" идентичны. В обоих случаях сообщение сохраняется на сервер, но недоступен для других потребителей, пока ack'ed (и удаляется), nack'ed (с basic.reject, хотя RabbitMQ не реализует этого) или канал/соединение закрыто (при котором сообщение становится доступным другим потребителям).
и (мои акценты)
Нет ожидаемого ожидания ACKs. Обычно это не проблема , поскольку общие случаи отсутствия ack - сбой сети или клиента - приведет к подключению упал (и, таким образом, поведение, описанное выше). Все еще, тайм-аут может быть полезен, скажем, иметь дело с живым, но не реагирующим потребители. Это вызвало обсуждение раньше. Существует ли конкретный использования, вы имеете в виду, что требует таких функций?
Проблема может возникнуть, потому что в модели вытаскивания клиента сложнее обнаружить поврежденное соединение (в отличие от живого, но невосприимчивого потребителя), особенно, поскольку сервер, похоже, счастлив ждать навсегда.
Обновление: В Linux вы можете присоединить обработчики сигналов для SIGTERM и/или SIGKILL и/или SIGINT и, надеюсь, закрыть соединение с помощью клиента. В Windows я считаю, что закрытие из Task Manager вызывает API Win32 TerminateProcess
, о котором MSDN говорит:
Если процесс завершается TerminateProcess
, все потоки процесс немедленно прекращается без возможности запуска дополнительного кода. Это означает, что нить не выполнить код в обработчике завершения блоки. Кроме того, не прилагается DLL уведомляются о том, что этот процесс отсоединение.
Это означает, что может быть трудно поймать завершение и закрыть в порядке.
Возможно, стоит потратить на список RabbitMQ свой собственный вариант использования для таймаута ack.
Ответ 3
Просьба представить несколько дополнительных сведений об объявленных вами компонентах. Обычно (и независимо от реализации клиента) очередь со свойствами
- эксклюзивный и
- автоудаление
должен быть удален, как только соединение между объявляющим клиентом и брокером распадается. Однако это не поможет вам с общими очередями. Пожалуйста, подробно расскажите, что именно вы пытаетесь моделировать.