Отслеживание утечки памяти в Spring Azure qPID JMS-код - PullRequest
1 голос
/ 24 апреля 2020

Я пытаюсь отследить и определить root причину утечки памяти в нашем очень маленьком и простом приложении Spring Boot.

Используется следующее: - Spring Boot 2.2.4 - azure -servicebus-jms-spring-boot-starter 2.2.1 - MS SQL

Функция: Приложение только отправляет Azure очередь ServiceBus, сохраняет данные и отправляет данные в другой пункт назначения. Это небольшое приложение, поэтому оно легко запускается с 64 мегабайтами памяти, несмотря на то, что я даю ему до 256 мегабайт через опцию Xmx. Важное замечание: очередь отправляется в транзакционном режиме Spring по умолчанию с выделенным JmsTransactionManager, который на самом деле является внутренней TM ChainedTransactionManager вместе с dbTM и дополнительным исходящим JMS TM. Оба объекта JMS ConnectionFactory создаются как CachingConnectionFactory.

Поведение:

После запуска приложения кажется, что все в порядке. Там нет traffi c, поэтому я вижу в журнале, что он открывает транзакции и закрывает при проверке очереди (jms: message-driven-channel-adapter).

Однако через некоторое время, когда по-прежнему нет трафика c, ни одно сообщение не было использовано, память начинает подниматься, как это отслеживается с помощью JVVM.

Возникла ошибка:

--2020-04-24 11:17:01.443 - WARN 39892 ---   [er.container-10] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'MY QUEUE NAME HERE' - trying to recover. Cause: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JMS transaction; nested exception is javax.jms.IllegalStateException: The Session was closed due to an unrecoverable error.

... и через несколько минут он достигает MAX кучи, и с этого момента он завершается ошибкой OutOfMemory в потоке, открывающем соединения JMS.

--2020-04-24 11:20:04.564 - WARN 39892 ---   [windows.net:-1]] i.n.u.concurrent.AbstractEventExecutor   : A task raised an exception. Task: org.apache.qpid.jms.provider.amqp.AmqpProvider$$Lambda$871/0x000000080199f840@1ed8f2b9
-
java.lang.OutOfMemoryError: Java heap space
        at java.base/java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:61)
        at java.base/java.nio.ByteBuffer.allocate(ByteBuffer.java:348)
        at org.apache.qpid.proton.engine.impl.ByteBufferUtils.newWriteableBuffer(ByteBufferUtils.java:99)
        at org.apache.qpid.proton.engine.impl.TransportOutputAdaptor.init_buffers(TransportOutputAdaptor.java:108)
        at org.apache.qpid.proton.engine.impl.TransportOutputAdaptor.pending(TransportOutputAdaptor.java:56)
        at org.apache.qpid.proton.engine.impl.SaslImpl$SwitchingSaslTransportWrapper.pending(SaslImpl.java:842)
        at org.apache.qpid.proton.engine.impl.HandshakeSniffingTransportWrapper.pending(HandshakeSniffingTransportWrapper.java:138)
        at org.apache.qpid.proton.engine.impl.TransportImpl.pending(TransportImpl.java:1577)
        at org.apache.qpid.proton.engine.impl.TransportImpl.getOutputBuffer(TransportImpl.java:1526)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:994)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:985)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider.lambda$close$3(AmqpProvider.java:351)
        at org.apache.qpid.jms.provider.amqp.AmqpProvider$$Lambda$871/0x000000080199f840.run(Unknown Source)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:510)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:518)
        at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at java.base/java.lang.Thread.run(Thread.java:835)

HeapDumps:

Я сделал пару снимков кучи в течение всего этого процесса и посмотрел на то, что увеличивается. Я вижу подозрительное количество объектов ConcurrentHashMap / String / Byte [].

Есть кто-нибудь подсказка / подсказка, что может быть не так в этой настройке, и библиотеки: Spring Boot, Apache qPid, используемый под капотом Azure JMS зависимость et c.? Большое спасибо.

enter image description here

Обновление # 1 У меня есть четкое свидетельство того, что проблема связана с Spring или azure service bus начальная библиотека - не используется клиент qPid. Я бы сказал, что библиотека содержит ошибку, а не Spring, просто мое предположение. Вот как выглядит сбойная установка:

  1. Существует два назначения JMS и одна БД, каждая с менеджером транзакций
  2. Существует ChainedTransactionManager, обертывающийся над тремя TM.
  3. Приложение интеграции Spring, которое подключается к Azure очереди ServiceBus через jms: message-driven-channel-adapter и устанавливает менеджер транзакций на этом компоненте (как создано в пункте 2)
  4. Запустите приложение. Трафик c в очереди не требуется, через 10 минут приложение обработает sh из-за OutOfMemoryError ... в пределах этих 10 минут я смотрю журнал на уровне отладки, и единственное, что происходит, - это открытие и закрытие транзакций с использованием ChainedTransactionManager ... также, как написано в комментариях, другое важное условие - это третий JMS TransactionManager ... с 2 ТМ он работает и стабилен, с 3 это будет sh ...

1 Ответ

1 голос
/ 26 апреля 2020

Дополнительные исследования и предпринятые шаги выявили наиболее вероятную root причину класса Spring CachingConnectionFactory . Как только я удалил это и использовал только нативные типы, проблема ушла, и профиль потребления памяти очень отличается и здоров.

Я должен сказать, что создал CachingConnectionFactory с использованием стандартного конструктора и больше не настраивал поведение. Однако эти значения Spring по умолчанию явно приводят к утечке памяти согласно моему опыту.

В прошлом у меня была утечка памяти с ActiveMq, которая должна была быть устранена с помощью CachingConnectionFactory , и теперь у меня есть утечка памяти с Azure ServiceBus при использовании CachingConnectionFactory .. странно :) В обоих случаях я вижу это как ошибки, потому что управление памятью должно быть правильным независимо от того, включено кэширование или нет.

Пометка этого как мой ответ.

Протестированный случай: проблема возникает при получении и отправке сообщения как со своей собственной TM, так и с обеими JMS connectionFactories типа CachedConnectionFactory. В конце я протестировал приложение. с фабрикой входящих соединений типа CachedConnectionFactory и исходящим просто нативного типа ... утечки памяти тоже нет.

...