Обычно в списке рассылки постоянно возникает множество вопросов, касающихся поддержки приоритетов сообщений ActiveMQ, а также хороших вопросов о наблюдаемом поведении и «что действительно поддерживается»? Я надеюсь помочь вам понять, что происходит под прикрытием и какие уровни приоритета могут быть поддержаны. Детали могут стать кровавыми для некоторых. Если вас не интересуют подробности, взгляните на ActiveMQ wiki для общего обзора.
Во-первых, поскольку ActiveMQ поддерживает JMS 1.1, давайте посмотрим, что спецификация JMS говорит о поддержке «JMSPriority»:
JMS определяет значение приоритета из десяти уровней, где 0 — самый низкий приоритет, а 9 — самый высокий. Кроме того, клиенты должны рассматривать приоритеты 0-4 как градации нормального приоритета и приоритеты 5-9 как градации ускоренного приоритета. JMS не требует от провайдера строгой реализации порядка приоритетов сообщений; однако, он должен сделать все возможное, чтобы доставить ускоренные сообщения раньше обычных сообщений.
ActiveMQ отмечает три различных уровня «Приоритета»:
- По умолчанию (JMSPriority == 4)
- Высокий (JMSPriority> 4 && <= 9)
- Низкий (JMSPriority> 0 && <4)
Если вы не укажете приоритет для вашего MessageProducer или отдельных сообщений (см. MessageProducer # send (message, deliveryMode, priority, timeToLive) ), клиент ActiveMQ по умолчанию будет использовать JMSPriority == 4. Как потребитель JMS вы можете ожидать порядок FIFO, если производители не используют приоритет или вы не используете какую-либо другую форму критериев выбора в пункте назначения.
ActiveMQ также «делает все возможное», чтобы доставлять ускоренные сообщения раньше, чем «нормальные» сообщения, как говорится в спецификации. Хранилище сообщений, которое использует ваш брокер, в значительной степени способствует тому, как это точно делается, но в целом можно ожидать, что брокер будет соблюдать строгую (0-9) поддержку приоритетов только для хранилищ сообщений, поддерживаемых JDBC. Для хранилищ сообщений, поддерживаемых KahaDB, поддерживается только «приоритет категории» (Низкий, По умолчанию, Высокий, где приоритеты в каждой категории не всегда различаются, то есть 5 и 9 считаются «Высокими»). Тем не менее, при правильных настройках и профиле обмена сообщениями вы можете повлиять на то, как [строгая] расстановка приоритетов происходит даже с KahaDB, поэтому давайте взглянем немного.
Включение приоритета сообщения
Вы можете включить приоритет сообщений в своих очередях с помощью следующего параметра в файле конфигурации activemq.xml:
1
2
3
4
5
6
7
|
< destinationPolicy > < policyMap > < policyEntries > < policyEntry queue = 'queueName' prioritizeMessages = 'true' /> </ policyEntries > </ policyMap > </ destinationPolicy > |
Для queueName
поддержка подстановочных знаков, поэтому вы можете включить приоритетную поддержку для иерархии сообщений.
Когда вы включите приоритетную поддержку, брокер будет использовать приоритетные структуры связанных списков в своих курсорах сообщений, а также даст KahaDB подсказку использовать приоритетные категории при хранении сообщений на диске. Существуют различные уровни строгости порядка приоритетов, но в худшем случае можно предположить, что приоритеты будут поддерживаться категориями. Следующие факторы влияют на то, насколько строгим может быть порядок приоритетов при использовании хранилища KahaDB:
- Кеширование включено / отключено в курсоре очереди
- MaxPageInSize для сколько сообщений на страницу из магазина в пакете
- Потребительская предварительная выборка
- Проверка просроченных сообщений
- Настройки памяти брокера
- Постоянные / непостоянные сообщения
В следующем разделе представлена небольшая информация о том, что происходит в KahaDB для поддержки приоритета, а в следующих разделах будет рассказано о том, как происходят события в памяти брокера, и, наконец, они рассылаются потребителю, а также будут указываться, как возникают различные факторы сверху. в игру.
Категории приоритетов KahaDB
Сначала мы начнем с того, как сообщения хранятся на диске и загружаются в место назначения. KahaDB (хранилище сообщений по умолчанию) — это файловая база данных сообщений, которую брокер использует для сохранения сообщений в «журнале» или «журнале». Посредник также отслеживает, какие сообщения находятся в журнале, сохраняя отдельный «индекс», который содержит информацию о сообщениях (например, его местоположение в журнале, с каким пунктом назначения он связан, упорядочением и т. Д.). Индекс также имеет понятие «приоритет» сообщения, которое реализуется с помощью трех структур B + Tree, по одной для каждого уровня приоритета (см. MessageOrderIndex в org.apache.activemq.store.kahadb.MessageDatabase). Эта деталь реализации является корнем приоритетов сообщений и имеет значение для остальных посредников, поскольку сообщения удаляются из хранилища.
Когда сообщения извлекаются из хранилища, они выполняются партиями (maxPageInSize), и сообщения, находящиеся в BTree «highPriority», извлекаются первыми. Когда сообщения с высоким приоритетом исчерпаны, хранилище предложит приоритет по умолчанию, а затем и сообщения с низким приоритетом.
Вы можете установить maxPageInSize так:
1
2
|
< policyEntry queue = 'queueName' prioritizeMessages = 'true' maxPageSize = '500' > |
Чем больше размер страницы, тем больше количество сообщений в пакете и тем больше сообщений вы можете видеть одновременно за один «снимок». Для каждого пакета, занесенного в память, его сообщения будут строго расставлены по приоритетам, как описано ниже курсором хранилища. Недостатком является то, что если ваши сообщения большие, ввод 500 за раз может исчерпать память вашего брокера. По умолчанию установлено значение 200.
Списки приоритетов курсора сообщений
Когда постоянные сообщения поступают в посредник от производителя, они сохраняются на диске, но они также кэшируются в памяти в ожидании отправки потребителю. Это настройка по умолчанию, поэтому нет необходимости явно устанавливать ее. Идея заключается в том, чтобы иметь возможность отправлять быстрым потребителям без необходимости извлекать его непосредственно с диска (если потребители становятся медленными, брокер самонастраивается, чтобы не использовать кэш, как только он заполнится, чтобы не было OOM). Хорошая вещь об этом состоит в том, что когда поддержка приоритетов используется для очереди, внутренние списки, используемые для курсоров, будут поддерживать строгий приоритет (0-9), поэтому для всех сообщений, которые в настоящее время находятся в памяти (в кеше), они будут отсортированы должным образом по возрастанию. Хитрость заключается в том, что происходит, когда все сообщения в кэше являются «сообщениями с более низким приоритетом», а затем сообщение брокера приходит с высоким приоритетом, но не помещается в кэш, потому что оно заполнено… в этом случае сообщение будет отправлено непосредственно в хранилище, будет проиндексировано в индексе «высокого приоритета», но не будет доступно для отправки перед сообщениями с более низким приоритетом, пока оно не будет выгружено в память в следующем пакете.
Когда в посредник поступают непостоянные сообщения, они не попадают в хранилище сообщений. Они будут храниться в памяти как можно дольше и помещаться на диск (во временное хранилище) только после того, как память превысит определенный порог (по умолчанию> 70%). Таким образом, то же поведение для кэшированных сообщений выше применимо к непостоянным сообщениям, а именно к тем, которые находятся в памяти, будут упорядочены строго (0-9), но как только они будут отправлены на диск, наблюдаются только категории.
Если вы отключите кеш курсора (со следующей настройкой)
1
2
|
< policyEntry queue = 'queueName' prioritizeMessages = 'true' useCache = 'false' /> |
затем вы могли бы помочь исключить описанный выше сценарий, когда кэш заполняется сообщениями с более низким приоритетом, когда поступает сообщение с высоким приоритетом (и застревает на диске, поскольку его нельзя перенести в память). Однако выполнение этого замедлит вашу пропускную способность, поскольку сообщения должны быть выгружены с диска перед отправкой потребителям, что замедлит отправку. Но учтите, что при этом вы с большей вероятностью увидите сообщения, не имеющие «строгого» приоритета, даже если в курсоре находятся списки приоритетов. Однако они будут правильно следовать приоритетным категориям (Высокий, По умолчанию, Низкий). Напомним, что если вы отключите кэш, вы сможете получать сообщения с более высоким приоритетом более оперативно, чем если бы кэш был включен и заполнен сообщениями с более низким приоритетом. Но отключение кеша само по себе не даст вам строгий приоритет.
Отключение кэша помогает получать сообщения с высоким приоритетом для потребителей, а не сообщения с более низким приоритетом, однако для того, чтобы это работало как задумано (и утомило меня), вам нужно отключить message expiry check
асинхронных message expiry check
. Это истечение срока действия проверяет сообщения в памяти каждые 30 секунд независимо от того, готовы ли они к отправке (по умолчанию), выполняет проверку TTL (время жизни) и отбрасывает те сообщения, срок действия которых должен истечь. Такая проверка эффективно переносит сообщения в память и останавливает обычную «страницу для отправки» настолько, чтобы пропустить сообщения с более высоким приоритетом.
1
2
|
< policyEntry queue = 'queueName' prioritizeMessages = 'true' useCache = 'false' expireMessagesPeriod = '0' > |
Отключение проверки истечения срока действия, тем не менее, сохранит сообщения с истекшим сроком хранения в хранилище дольше, поскольку единственная проверка истечения срока действия будет выполняться непосредственно перед отправкой, поэтому примите обоснованное решение по этому поводу и всем настройкам ActiveMQ, с которыми вы будете работать. Но чтобы двигаться в направлении приоритетов строгого (эр) порядка, вы захотите отключить это.
Наконец, потребительская предварительная выборка играет роль в достижении «строгого порядка». По умолчанию для предварительной очереди установлено значение 1000 для потребителей очереди, что означает, что им будет отправлено 1000 сообщений в пакете. Это помогает ускорить потребителя, когда он потребляет сообщения, но с точки зрения приоритетной обработки он по сути также действует как кэш сообщений (обсуждался выше) и может способствовать отсутствию «строгого порядка». «Приоритет категории» также может быть нарушен, если ваша предварительная выборка заполнена сообщениями с более низким приоритетом, и есть новое высокоприоритетное сообщение, пришедшее к брокеру, вы не увидите его до следующей отправки сообщения потребителю. Таким образом, чем меньше предварительная выборка, тем больше шансов увидеть сообщения с более высоким приоритетом, чем более низкие. При предварительной выборке 1 вы всегда получите сообщение с наивысшим приоритетом, о котором знает курсор хранилища.
1
2
|
< policyEntry queue = 'queueName' prioritizeMessages = 'true' useCache = 'false' expireMessagesPeriod = '0' queuePrefetch = '1' > |
Приоритет сообщения на стороне клиента
ActiveMQ также имеет приоритетную поддержку, встроенную прямо в клиент сообщений, и он включен по умолчанию. Это означает, что когда сообщения отправляются вашему потребителю (даже до того, как ваш потребитель их получает, используя предварительную выборку), они будут кэшироваться на стороне потребителя и иметь приоритет по умолчанию. Это независимо от того, используете ли вы приоритетную поддержку на стороне брокера. Это может повлиять на порядок, который вы видите на потребителя, так что имейте это в виду. Чтобы отключить его, установите следующий параметр конфигурации в URL вашего брокера, например, tcp://0.0.0.0:61616?jms.messagePrioritySupported=false
Но, как упоминалось выше, вам нужно понизить предварительную выборку до 1, чтобы получить наилучшие шансы на достижение строгого порядка.
компромиссы
Таким образом, в конечном счете, получение строго упорядоченных сообщений с KahaDB возможно, но есть существенные компромиссы, и это не будет применимо для каждой ситуации обмена сообщениями. Хотите оптимизированный, быстрый обмен сообщениями? или вы хотите замедлить обмен сообщениями для достижения строгого (er) упорядочения по приоритетам. Каждая ситуация индивидуальна и должна оцениваться в каждом конкретном случае. В целом, однако, вы можете положиться на приоритеты уровня категории.
Изменение порядка сообщений в больших очередях и поддержание высокой производительности проблематично, и большинство поставщиков очереди сообщений делают это не очень хорошо. Поддержка приоритетов ActiveMQ является сильной, но существует другая хорошая альтернатива, как обсуждалось в вики ActiveMQ, описывающей приоритет сообщений, а именно: использование селекторов сообщений и балансировка потребителей таким образом, что сообщения с высоким приоритетом в конечном итоге потребляются первыми. Такой подход имеет тенденцию давать больше гибкости и контроля, но это для другого поста.