如何修复 Ignite 性能问题?
How to fix Ignite performance issues?
我们在服务器和客户端模式下都使用 Ignite 2.7.6:两个服务器和六个客户端。
起初,每个带有客户端Ignite的应用程序节点都有2G堆。每个 Ignite 服务器节点有 24G offheap 和 2G heap。
在上次应用更新中,我们引入了新功能,该功能需要 20 个整体(用户组)的大约 2000 个缓存。缓存条目的大小很小,最多 10 个整数。
这些缓存是通过 ignite.getOrCreateCache(name)
方法创建的,因此它们具有默认缓存配置(堆外、分区)。
但是在更新后的一个小时内,我们在服务器节点上出现 OOM 错误:
[00:59:55,628][SEVERE][sys-#44759][GridDhtPartitionsExchangeFuture] Failed to notify listener: o.a.i.i.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture@3287dcbd
java.lang.OutOfMemoryError: Java heap space
堆现在在 Ignite 服务器节点上增加到 16G,在应用程序节点上增加到 12G。
正如我们所见,所有服务器节点现在都具有高 CPU 负载约 250%(更新前为 20%)并且 G1 Young Gen 暂停长达 5 毫秒(更新前为 300 微秒)。
服务器配置为:
<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="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="workDirectory" value="/opt/qwerty/ignite/data"/>
<property name="gridLogger">
<bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">
<constructor-arg type="java.lang.String" value="config/ignite-log4j2.xml"/>
</bean>
</property>
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="defaultDataRegionConfiguration">
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<property name="maxSize" value="#{24L * 1024 * 1024 * 1024}"/>
<property name="pageEvictionMode" value="RANDOM_LRU"/>
</bean>
</property>
</bean>
</property>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="localAddress" value="host-1.qwerty.srv"/>
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<value>host-1.qwerty.srv:47500</value>
<value>host-2.qwerty.srv:47500</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
<property name="communicationSpi">
<bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
<property name="localAddress" value="host-1.qwerty.srv"/>
</bean>
</property>
</bean>
</beans>
在 Ignite 服务器节点的内存转储中,我们看到很多 org.apache.ignite.internal.marshaller.optimized.OptimizedObjectStreamRegistry$StreamHolder
的 21Mb
内存泄漏报告显示:
Problem Suspect 1
One instance of "org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager" loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupies 529 414 776 (10,39 %) bytes. The memory is accumulated in one instance of "java.util.LinkedList" loaded by "<system class loader>".
Keywords
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
java.util.LinkedList
org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager
Problem Suspect 2
384 instances of "org.apache.ignite.thread.IgniteThread", loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupy 3 023 380 000 (59,34 %) bytes.
Keywords
org.apache.ignite.thread.IgniteThread
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
Problem Suspect 3
1 023 instances of "org.apache.ignite.internal.processors.cache.CacheGroupContext", loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupy 905 077 824 (17,76 %) bytes.
Keywords
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
org.apache.ignite.internal.processors.cache.CacheGroupContext
问题是我们做错了什么?我们能调什么?可能是我们代码的问题,但是如何判断出在哪里呢?
2000 个缓存很多。一个cache大概需要40M的数据结构。
我建议至少对具有相似目的和组成的所有缓存使用相同的 cacheGroup
,以共享其中一些数据结构。
我们在服务器和客户端模式下都使用 Ignite 2.7.6:两个服务器和六个客户端。
起初,每个带有客户端Ignite的应用程序节点都有2G堆。每个 Ignite 服务器节点有 24G offheap 和 2G heap。
在上次应用更新中,我们引入了新功能,该功能需要 20 个整体(用户组)的大约 2000 个缓存。缓存条目的大小很小,最多 10 个整数。
这些缓存是通过 ignite.getOrCreateCache(name)
方法创建的,因此它们具有默认缓存配置(堆外、分区)。
但是在更新后的一个小时内,我们在服务器节点上出现 OOM 错误:
[00:59:55,628][SEVERE][sys-#44759][GridDhtPartitionsExchangeFuture] Failed to notify listener: o.a.i.i.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture@3287dcbd
java.lang.OutOfMemoryError: Java heap space
堆现在在 Ignite 服务器节点上增加到 16G,在应用程序节点上增加到 12G。
正如我们所见,所有服务器节点现在都具有高 CPU 负载约 250%(更新前为 20%)并且 G1 Young Gen 暂停长达 5 毫秒(更新前为 300 微秒)。
服务器配置为:
<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="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="workDirectory" value="/opt/qwerty/ignite/data"/>
<property name="gridLogger">
<bean class="org.apache.ignite.logger.log4j2.Log4J2Logger">
<constructor-arg type="java.lang.String" value="config/ignite-log4j2.xml"/>
</bean>
</property>
<property name="dataStorageConfiguration">
<bean class="org.apache.ignite.configuration.DataStorageConfiguration">
<property name="defaultDataRegionConfiguration">
<bean class="org.apache.ignite.configuration.DataRegionConfiguration">
<property name="maxSize" value="#{24L * 1024 * 1024 * 1024}"/>
<property name="pageEvictionMode" value="RANDOM_LRU"/>
</bean>
</property>
</bean>
</property>
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="localAddress" value="host-1.qwerty.srv"/>
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<value>host-1.qwerty.srv:47500</value>
<value>host-2.qwerty.srv:47500</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
<property name="communicationSpi">
<bean class="org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi">
<property name="localAddress" value="host-1.qwerty.srv"/>
</bean>
</property>
</bean>
</beans>
在 Ignite 服务器节点的内存转储中,我们看到很多 org.apache.ignite.internal.marshaller.optimized.OptimizedObjectStreamRegistry$StreamHolder
的 21Mb
内存泄漏报告显示:
Problem Suspect 1
One instance of "org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager" loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupies 529 414 776 (10,39 %) bytes. The memory is accumulated in one instance of "java.util.LinkedList" loaded by "<system class loader>".
Keywords
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
java.util.LinkedList
org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager
Problem Suspect 2
384 instances of "org.apache.ignite.thread.IgniteThread", loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupy 3 023 380 000 (59,34 %) bytes.
Keywords
org.apache.ignite.thread.IgniteThread
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
Problem Suspect 3
1 023 instances of "org.apache.ignite.internal.processors.cache.CacheGroupContext", loaded by "jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100" occupy 905 077 824 (17,76 %) bytes.
Keywords
jdk.internal.loader.ClassLoaders$AppClassLoader @ 0x400000100
org.apache.ignite.internal.processors.cache.CacheGroupContext
问题是我们做错了什么?我们能调什么?可能是我们代码的问题,但是如何判断出在哪里呢?
2000 个缓存很多。一个cache大概需要40M的数据结构。
我建议至少对具有相似目的和组成的所有缓存使用相同的 cacheGroup
,以共享其中一些数据结构。