#java #jvm #heap-memory #ignite
#java #jvm #куча-память #ignite
Вопрос:
Я пытаюсь использовать Ignite в качестве базы данных в памяти для пар ключ-значение со значениями от 50 МБ до 800 МБ. Похоже, что Ignite выделяет пространство кучи через JVM, которое он никогда не очищает, даже если записи кэша удалены из кучи, очищены, подключенных клиентов нет и запущенных операций нет. Моя машина не сможет справиться с таким потреблением памяти, поэтому я ищу способ очистить некоторую память.
Мой тестовый сценарий выглядит следующим образом:
- Ignite версии 2.9
- Запуск с OpenJDK 11
Я тестирую Ignite локально с помощью скрипта python с помощью тонкого клиента pyignite:
client = Client()
client.connect('localhost', 10800)
my_cache = client.get_or_create_cache('default')
my_cache.clear()
data = createData() #creates 800 000 000 bytes test data
def put(caches):
i = caches
while i > 0:
my_cache.put('my key' str(i), data)
i -= 1
put(5)
my_cache.remove_all()
my_cache.destroy()
client.close()
Скрипт записывает данные объемом 800 МБ последовательно в 5 разных записей кэша. Следующий снимок иллюстрирует, как куча Ignite растет до своей максимальной точки, что само по себе понятно, но впоследствии остается около 10 ГБ даже после выполнения GC:
Выполнение второго тестового запуска с теми же данными не приводит к увеличению потребления кучи после GC, что наводит меня на мысль, что Ignite выделяет буферы для входящих данных внутри, которые соответствуют размеру данных. Это потребление памяти просто слишком велико, и моя машина не сможет справиться с этим в долгосрочной перспективе.
Конфигурация ignite довольно проста:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Durable memory configuration. -->
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="dataRegionConfigurations">
<list>
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<!-- Custom region name. -->
<property name="name" value="10GB_Region"/>
<!-- 100 MB initial size. -->
<property name="initialSize" value="#{100L * 1024 * 1024}"/>
<!-- 10GB maximum size. -->
<property name="maxSize" value="#{10096L * 1024 * 1024}"/>
</bean>
</list>
</property>
<!-- Redefining the default region's settings -->
<property name="defaultDataRegionConfiguration">
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<property name="name" value="Default_Region"/>
<property name="maxSize" value="#{5L * 1024 * 1024 * 1024}"/>
</bean>
</property>
</bean>
</property>
<property name="cacheConfiguration">
<list>
<!-- Partitioned cache example configuration (Atomic mode). -->
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="default"/>
<property name="atomicityMode" value="ATOMIC"/>
<property name="backups" value="1"/>
<property name="dataRegionName" value="10GB_Region"/>
</bean>
</list>
</property>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="addresses">
<list>
<value>127.0.0.1:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
- ignite visor конкретно говорит, что кэш находится вне кучи
- Гистограмма VisualVM показывает, что 98% текущих байтов отображаются в byte[]
- кажется, что есть потоки client-connector и data-streamer-stripe, которые остаются открытыми, по одному на операцию put в кэше, но я не уверен, сколько кучи им требуется
- предоставление подсказок о значении в my_cache.put не помогает
- cache.clear(), кэш.destroy() не помогает (и не должно, так как кэш находится вне кучи)
Любая помощь будет очень признательна!
Комментарии:
1. Возможно, вы правы; Я надеялся, что могут быть какие-то параметры конфигурации или параметры, которые установлены неправильно или о которых я не знаю, но если это действительно ошибка, мне следует связаться с продуктом напрямую. Спасибо за ваш вклад.
2. Да, извините за это, я не забуду чаще проверять StackOverflow.
3. Это хороший подход, но вы можете сделать его менее утомительным: достаточно частого посещения после публикации вопроса 😉
Ответ №1:
- Apache Ignite по умолчанию не хранит данные в куче, вместо этого он будет хранить данные вне кучи.
- Apahce Ignite действительно не будет освобождать удаленную кучу при удалении данных, но это позволит повторно использовать указанную удаленную кучу при поступлении новых данных.
- Совершенно непонятно, почему ваш инструмент сообщает об использовании ~ 16G кучи, поскольку Ignite не должен использовать более нескольких сотен МБАЙТ с предоставленной конфигурацией. Если это не просто куча, а вся оперативная память, тогда все готово. Вы должны ожидать, что должно быть выделено 10 ГБ. Почему он сообщает о большем размере поля, неясно.
Комментарии:
1. Что касается 3-го пункта, к сожалению, инструмент показывает только кучу, управляемую Ignite. Изменение максимального размера области не влияет на потребляемую кучу. Пункты 1 и 2 отражают мое понимание политики Ignite вне кучи.
2. Пожалуйста, соберите дамп кучи и попытайтесь найти утечки кучи / собрать гистограмму кучи.
3. Я собрал дамп кучи, и после более глубокого анализа я теперь вижу, что существует 5 массивов byte [], каждый длиной 800 000 024 байта (соответствует данным, которые я передаю Ignite) и еще 5 массивов, все длиной 1 073 741 848 Бит. Похоже, что второй набор массивов, возможно, является каким-то буфером. В этом случае я явно свяжусь с разработчиками Ignite, спасибо за ваш вклад!
4. Пожалуйста, опубликуйте эти результаты в списке разработчиков Apache Ignite. Спасибо за это расследование. Вы можете попытаться найти пользователей этих массивов, чтобы выяснить, в каких частях кода они хранятся.
Ответ №2:
Приношу свои извинения за длительную задержку всем, кому это интересно, но я получил ответ на свой вопрос после обращения в список рассылки Ignite. По-видимому, Ignite никогда не предназначался для использования таких больших объемов данных в одном запросе. Описанное поведение является ожидаемым и связано с разделением данных на пакеты и отправкой их на другие узлы или сохранением. Предлагаемое решение состоит в том, чтобы разбить данные на гораздо меньшие биты. Поскольку в моем случае это в настоящее время невозможно, я отпустил Ignite и искал другие подходы к хранению моих данных.