Очереди

  • Михаил
  • 12 мин. на прочтение
  • 66
  • 17 Dec 2019
  • 27 Feb 2023

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

Некоторые протоколы (например, STOMP и MQTT) основаны на идее тем. Для них очереди выступают в роли буфера накопления данных для потребителей. Однако по-прежнему важно понимать, какую роль играют очереди, поскольку многие функции по-прежнему работают на уровне очередей, даже для этих протоколов.

Потоки — это альтернативная структура данных для обмена сообщениями, доступная в RabbitMQ. Потоки предоставляют функции, отличные от очередей.

Некоторые ключевые темы, затронутые в этом руководстве,

Темы, связанные с потребителями, см. в руководстве для потребителей . Очереди и потоки кворума также имеют специальные руководства.

Основы

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

Очереди в RabbitMQ — это FIFO («первым пришел, первым вышел») . Некоторые функции очереди, а именно приоритеты и повторная постановка в очередь потребителями, могут повлиять на упорядочение, наблюдаемое потребителями.

Имена

У очередей есть имена, поэтому приложения могут ссылаться на них.

Приложения могут выбирать имена очередей или просить брокера сгенерировать для них имя. Имена очередей могут содержать до 255 байт символов UTF-8.

Имена очередей, начинающиеся с «amq». зарезервированы для внутреннего использования брокером. Попытки объявить очередь с именем, нарушающим это правило, приведут к исключению на уровне канала с кодом ответа 403 ( ACCESS_REFUSED ).

Очереди с именем сервера

В AMQP 0-9-1 брокер может генерировать уникальное имя очереди от имени приложения. Чтобы использовать эту функцию, передайте пустую строку в качестве аргумента имени очереди: такое же сгенерированное имя может быть получено последующими методами в том же канале с использованием пустой строки там, где ожидается имя очереди. Это работает, потому что канал запоминает последнее имя очереди, сгенерированное сервером.

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

Характеристики

У очередей есть свойства, определяющие их поведение. Есть набор обязательных свойств и карта необязательных:

  • Имя
  • Надежный (очередь переживет перезапуск брокера)
  • Эксклюзивный (используется только одним подключением, и очередь будет удалена при закрытии этого подключения)
  • Автоматическое удаление (очередь, в которой был хотя бы один потребитель, удаляется, когда последний потребитель отписывается)
  • Аргументы (необязательные; используются плагинами и специфичными для брокера функциями, такими как срок жизни сообщения, ограничение длины очереди и т. д.)

Обратите внимание, что не все комбинации свойств имеют смысл на практике. Например, автоматически удаляемые и монопольные очереди должны иметь имя сервера . Предполагается, что такие очереди используются для данных, специфичных для клиента или соединения (сеанса).

Когда автоматически удаляемые или монопольные очереди используют общеизвестные (статические) имена, в случае отключения клиента и немедленного повторного подключения возникнет естественное состояние гонки между узлами RabbitMQ, которые удалят такие очереди и восстановят клиентов, которые попытаются их повторно объявить. . Это может привести к сбою или исключениям при восстановлении соединения на стороне клиента, а также создать ненужную путаницу или повлиять на доступность приложения.

Декларация и эквивалентность свойств

Перед использованием очереди ее необходимо объявить. Объявление очереди приведет к ее созданию, если она еще не существует. Объявление не будет иметь никакого эффекта, если очередь уже существует и ее атрибуты такие же, как в объявлении. Когда существующие атрибуты очереди не совпадают с атрибутами в объявлении, будет возбуждено исключение уровня канала с кодом 406 ( PRECONDITION_FAILED ).

Необязательные аргументы

Необязательные аргументы очереди, также известные как «x-аргументы» из-за их имени поля в протоколе AMQP 0-9-1, представляют собой карту (словарь) произвольных пар ключ/значение, которые могут предоставляться клиентами при объявлении очереди. .

Карта используется различными функциями и плагинами, такими как

и так далее.

Большинство необязательных аргументов можно динамически изменять после объявления очереди, но есть и исключения. Например, тип очереди ( x-queue-type ) и максимальное количество приоритетов очереди ( x-max-priority ) должны быть установлены во время объявления очереди и не могут быть изменены после этого.

Необязательные аргументы очереди можно задать двумя способами:

  • В группы очередей с помощью политик (рекомендуется)
  • Для каждой очереди, когда очередь объявляется клиентом

Первый вариант более гибкий, ненавязчивый, не требует модификации и повторного развертывания приложения. Поэтому он настоятельно рекомендуется для большинства пользователей. Обратите внимание, что некоторые необязательные аргументы, такие как тип очереди или максимальное количество приоритетов, могут предоставляться только клиентами, поскольку они не могут быть изменены динамически и должны быть известны во время объявления.

То, как необязательные аргументы предоставляются клиентами, варьируется от клиентской библиотеки к клиентской библиотеке, но обычно это аргумент рядом с durable , auto_delete и другими аргументами функции (метода), объявляющей очереди.

Порядок сообщений

Очереди в RabbitMQ представляют собой упорядоченные наборы сообщений. Сообщения ставятся в очередь и извлекаются из очереди (доставляются потребителям) в порядке FIFO .

Порядок FIFO не гарантируется для приоритетных и сегментированных очередей .

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

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

Приложения-потребители могут предполагать, что первоначальные доставки (те, в которых для свойства redelivered установлено значение false ) одному потребителю выполняются в том же порядке FIFO, в котором они были поставлены в очередь. Для повторяющихся доставок ( свойство redelivered имеет значение true ) исходный заказ может зависеть от времени подтверждения и повторной доставки потребителем, и поэтому не гарантируется.

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

Долговечность

Очереди могут быть устойчивыми или временными. Метаданные долговременной очереди хранятся на диске, а метаданные временной очереди по возможности хранятся в памяти. Такое же различие делается для сообщений во время публикации в некоторых протоколах, например AMQP 0-9-1 и MQTT.

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

Временные очереди будут удалены при загрузке узла. Поэтому они не переживут перезапуск узла по замыслу. Сообщения во временных очередях также будут отброшены.

Устойчивые очереди будут восстановлены при загрузке узла, включая сообщения в них, опубликованные как постоянные. Сообщения, опубликованные как временные, будут удалены во время восстановления, даже если они были сохранены в устойчивых очередях.

Как выбрать

В большинстве других случаев рекомендуется использовать устойчивые очереди. Для реплицированных очередей единственным разумным вариантом является использование устойчивых очередей.

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

Временные очереди могут быть разумным выбором для рабочих нагрузок с временными клиентами, например, для временных подключений WebSocket в пользовательских интерфейсах, мобильных приложениях и устройствах, которые, как ожидается, перейдут в автономный режим или будут использовать переключатели. Такие клиенты обычно имеют временное состояние, которое должно быть заменено при повторном подключении клиента.

Некоторые типы очередей не поддерживают временные очереди. Очереди кворума должны быть устойчивыми, например, из-за допущений и требований базового протокола репликации.

Временные очереди

С некоторыми рабочими нагрузками очереди должны быть недолговечными. Хотя клиенты могут удалять объявленные ими очереди перед отключением, это не всегда удобно. Кроме того, клиентские подключения могут завершаться сбоем, что может привести к оставлению неиспользуемых ресурсов (очередей).

Есть три способа сделать так, чтобы очередь удалялась автоматически:

  • Эксклюзивные очереди (рассмотренные ниже)
  • TTL (также рассматриваются ниже)
  • Автоудаление очередей

Очередь с автоудалением будет удалена, когда ее последний потребитель будет отменен (например, с помощью basic.cancel в AMQP 0-9-1) или исчезнет (закрыт канал или соединение или потеряно TCP-соединение с сервером).

Если у очереди никогда не было потребителей, например, когда все потребление происходит с использованием метода basic.get (API "pull"), она не будет автоматически удалена. В таких случаях используйте монопольные очереди или очередь TTL.

Эксклюзивные очереди

Эксклюзивная очередь может использоваться (потребляться, очищаться, удаляться и т. д.) только путем объявления соединения. Попытка использовать монопольную очередь из другого соединения приведет к исключению уровня канала RESOURCE_LOCKED с сообщением об ошибке, в котором говорится, что невозможно получить монопольный доступ к заблокированной очереди .

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

Общепринято делать эксклюзивные очереди с именем сервера.

Эксклюзивные очереди объявляются на «клиент-локальном» узле (узле, к которому подключен клиент, объявляющий очередь), независимо от значения queue_master_locator .

Реплицированные и распределенные очереди

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

Очереди также могут быть объединены между слабо связанными узлами или кластерами.

Обратите внимание, что внутрикластерная репликация и федерация являются ортогональными функциями и не должны рассматриваться как прямые альтернативы.

Потоки — это еще одна реплицируемая структура данных, поддерживаемая RabbitMQ, с другим набором поддерживаемых операций и функций.

Срок жизни и предел длины

Длина очередей может быть ограничена . Очереди и сообщения могут иметь TTL .

Обе функции можно использовать для истечения срока действия данных и как способ ограничения максимального количества ресурсов (ОЗУ, дискового пространства), которое может использовать очередь, например, когда потребители отключаются от сети или их пропускная способность отстает от издателей.

В памяти и долговременном хранении

Очереди хранят сообщения в оперативной памяти и/или на диске. В некоторых протоколах (например, AMQP 0-9-1) это частично контролируется клиентом. В AMQP 0-9-1 это делается через свойство сообщения ( delivery_mode или, в некоторых клиентах, persisted ).

Публикация сообщений как временных предполагает, что RabbitMQ должен хранить как можно больше сообщений в оперативной памяти. Очереди, однако, выгружают на диск даже временные сообщения, когда им не хватает памяти .

Постоянные сообщения, направляемые в постоянные очереди, сохраняются в пакетах или по прошествии определенного времени (долей секунды).

Ленивые очереди выгружают сообщения на диск более агрессивно, независимо от их свойства постоянства.

Дополнительные сведения см. в разделе Использование памяти , Сигналы тревоги , Сигналы тревоги памяти , Сигналы тревоги свободного места на диске , Контрольный список производства и Руководство по настройке хранилища сообщений .

Приоритеты

Очереди могут иметь 0 или более приоритетов . Эта функция является необязательной: только очереди с максимальным числом приоритетов, настроенным с помощью необязательного аргумента (см. выше), будут выполнять приоритизацию.

Издатели указывают приоритет сообщения, используя поле приоритета в свойствах сообщения.

Если желательны очереди с приоритетом, мы рекомендуем использовать от 1 до 10. В настоящее время использование большего количества приоритетов потребует больше ресурсов (процессы Erlang).

Загрузка ЦП и аспекты параллелизма

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

В случае, когда желательно отказаться от порядка сообщений в пользу параллелизма (лучшее использование ядра ЦП), Rabbitmq-sharding предоставляет сознательный способ сделать это прозрачно для клиентов.

Метрики и мониторинг

RabbitMQ собирает несколько показателей об очередях. Большинство из них доступны через RabbitMQ HTTP API и пользовательский интерфейс управления , который предназначен для мониторинга. Это включает в себя длину очереди, скорость входящего и исходящего трафика, количество потребителей, количество сообщений в различных состояниях (например, готовых к доставке или неподтвержденных ), количество сообщений в ОЗУ и на диске и т. д.

rabbitmqctl может отображать очереди и некоторые основные метрики.

Показатели времени выполнения, такие как использование планировщика виртуальных машин, активность GC процесса очереди (Erlang), объем оперативной памяти, используемой процессом очереди, длина почтового ящика процесса очереди, можно получить с помощью плагина rabbitmq-top и отдельных страниц очереди в пользовательском интерфейсе управления.

Потребители и благодарности

Сообщения могут потребляться путем регистрации потребителя (подписки), что означает, что RabbitMQ будет отправлять сообщения клиенту, или извлекаться индивидуально для протоколов, которые это поддерживают (например, метод basic.get AMQP 0-9-1), аналогично HTTP GET.

Доставленные сообщения могут быть подтверждены потребителем явно или автоматически, как только доставка будет записана в сокет соединения.

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

Предварительная выборка и потребительская перегрузка

Режим автоматического подтверждения может также перегрузить потребителей, которые не могут обрабатывать сообщения так же быстро, как они доставляются. Это может привести к постоянному увеличению использования памяти и/или подкачке ОС для процесса-потребителя.

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

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

Большое количество неподтвержденных сообщений приведет к увеличению использования памяти брокером.

Состояния сообщения

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

Разбивку сообщений по состояниям можно найти в пользовательском интерфейсе управления.

Определение длины очереди

Длину очереди можно определить несколькими способами:

  • С AMQP 0-9-1, используя свойство ответа метода queue.declare ( queue.declare-ok ). Имя поля — message_count . Способ доступа к ней зависит от клиентской библиотеки.
  • Использование HTTP-API RabbitMQ .
  • С помощью команды rabbitmqctl list_queues .

Длина очереди определяется как количество сообщений, готовых к доставке.