Как избежать блокировки просмотра очереди после вызова контрольной точки ActiveMQ
Существует проблема при использовании ActiveMQ с большим количеством постоянных очередей (250), 1000 постоянных текстовых сообщений, 10 КБ.
Сценарий требует, чтобы эти сообщения оставались в хранилище в течение длительного времени (дней), пока они не будут использованы (большие объемы данных размещаются для распространения среди многих потребителей, которые могут быть отключены в течение нескольких дней).
После заполнения хранилища этими сообщениями и перезапуска брокера мы можем просматривать / использовать некоторые очереди до вызова #checkpoint через 30 секунд.
Этот вызов заставляет посредника использовать всю доступную память и никогда не освобождает ее для других задач, таких как просмотр / использование очереди. Внутренне MessageCursor, похоже, решает, что недостаточно памяти и останавливает доставку содержимого очереди браузерам / потребителям.
=> Есть ли способ избежать этого поведения по конфигурации или это ошибка?
Ожидается, что мы можем использовать / просматривать любую очередь при любых обстоятельствах.
Приведенные ниже параметры находятся в рабочем состоянии в течение некоторого времени, и некоторые рекомендации применяются в документации ActiveMQ (политики назначения, systemUsage, параметры сохранения и т. Д.)
- Поведение протестировано с ActiveMQ: 5.11.2, 5.13.0 и 5.5.1.
- Настройки памяти: Xmx=1024м
- Java: 1,8 или 1,7
- ОС: Windows, MacOS, Linux
- Персистентный адаптер: KahaDB или LevelDB
- Диск: достаточно свободного места (200 ГБ) и физической памяти (не более 16 ГБ).
Помимо вышеупомянутых настроек мы используем следующие настройки для брокера (кстати: изменение memoryLimit на более низкое значение, такое как 1mb, не меняет ситуацию):
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" producerFlowControl="false" optimizedDispatch="true" memoryLimit="128mb" timeBeforeDispatchStarts="1000">
<dispatchPolicy>
<strictOrderDispatchPolicy />
</dispatchPolicy>
<pendingQueuePolicy>
<storeCursor />
</pendingQueuePolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
<systemUsage>
<systemUsage sendFailIfNoSpace="true">
<memoryUsage>
<memoryUsage limit="500 mb" />
</memoryUsage>
<storeUsage>
<storeUsage limit="80000 mb" />
</storeUsage>
<tempUsage>
<tempUsage limit="1000 mb" />
</tempUsage>
</systemUsage>
</systemUsage>
Если мы установим cursorMemoryHighWaterMark в destinationPolicy на более высокое значение, например 150 или 600, в зависимости от разницы между memoryUsage и доступным пространством кучи, то это немного облегчает ситуацию, но в действительности это не вариант для производственных систем. Посмотреть.
Экран с информацией из Oracle Mission Control, показывающей те экземпляры ActiveMQTextMessage, которые никогда не высвобождаются из памяти:
2 ответа
У нас есть решение для нашей проблемы путем изменения (queue) адресной политики policyEntry.
После тщательного исследования (без изменения исходного кода ActiveMQ) на данный момент мы должны принять ограничения, определенные единственным параметром memoryLimit, используемым как для #checkpoint/cleanup process, так и для просмотра / потребления очередей.
1.) Память
Это не проблема, если мы используем намного более высокий уровень memoryLimit (вместе с более высокой max-heap) для поддержки как кэширования сообщений по назначению во время рабочего процесса #checkpoint/cleanup, так и наших требований к просмотру / использованию сообщений.
Но больше памяти не вариант в нашем сценарии, нам нужно иметь дело с 1024 м макс-кучи и 500 м памяти.
Кроме того, следует подробно обсудить постоянную установку более высоких значений MemoryLimits только из-за более постоянных очередей, содержащих сотни / тысячи ожидающих сообщений вместе с определенными сценариями автономного / неактивного потребителя (IMHO).
2.) Постоянные адаптеры
Мы исключили постоянные адаптеры как причину проблемы, потому что поведение не меняется, если мы переключаем различные типы постоянных хранилищ (KahaDB, LevelDB, JDBC-PostgreSQL).
Во время сеансов отладки с KahaDB мы также видим регулярную обработку контрольных точек, управление хранилищем осуществляется, как и ожидалось.
3.) Политика назначения / проверка срока действия
Наша проблема полностью исчезнет, если мы отключим кэширование и проверку истечения срока действия, которая является реальной причиной проблемы.
Соответствующие свойства задокументированы, и есть хорошая статья в блоге о Приоритетах сообщений с описанием, вполне подходящим для нашего сценария:
- http://activemq.apache.org/how-can-i-support-priority-queues.html
- http://blog.christianposta.com/activemq/activemq-message-priorities-how-it-works/
Мы просто добавили useCache="false" и expireMessagesPeriod="0" в policyEntry:
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">" producerFlowControl="false" optimizedDispatch="true" memoryLimit="128mb" timeBeforeDispatchStarts="1000"
useCache="false" expireMessagesPeriod="0">
<dispatchPolicy>
<strictOrderDispatchPolicy />
</dispatchPolicy>
<pendingQueuePolicy>
<storeCursor />
</pendingQueuePolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
Последствия очевидны, если мы больше не используем кэширование in-mem и никогда не проверяем срок действия сообщения.
Поскольку мы не используем ни истечение срока действия сообщения, ни приоритеты сообщений, и текущая отправка сообщений является для нас достаточно быстрой, этот компромисс приемлем с учетом ограничений системы.
Следует также подумать о четко определенных предопределенных ограничениях на потребление памяти во время определенных рабочих процессов. Размер сообщения в нашем сценарии может быть от 2 байтов до прибл. 100 КБ, поэтому для оптимизации поведения системы в отношении производительности и использования памяти могут быть полезны дополнительные индивидуальные политики policyEntries и конфигурации клиентов (см. http://activemq.apache.org/per-destination-policies.html).
У меня была похожая проблема, и ActiveMQ на самом деле не был "базой данных"; сообщения должны проходить через ActiveMQ, и для такого длительного хранения я бы рекомендовал использовать базу данных или обмениваться файлами по FTP.
Я также рекомендовал бы использовать providerFlowControl="true", поэтому, если ActiveMQ не сможет обрабатывать сообщения, это замедлит работу производителя.