Apache Ignite可能存在内存泄漏问题?

3

我正试图将Ignite作为内存数据库来存储键值对,其中值的范围在50MB到800MB之间。看起来Ignite通过JVM分配堆空间,即使缓存条目是非堆外的,已经清除了,没有连接的客户端和没有正在运行的操作,它也从未清理。我的机器无法处理这样的内存消耗,因此我正在寻找一种清理部分内存的方法。

我的测试场景如下:

  • Ignite版本2.9
  • 使用OpenJDK 11运行

我通过一个使用pyignite轻量级客户端的Python脚本在本地测试Ignite:

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 MB的数据依次写入5个不同的缓存条目。以下快照展示了Ignite堆的增长到达峰值,这一点本身是可理解的,但之后即使在执行垃圾回收后,它仍然保持在约10GB左右:

Ignite堆

再次运行相同数据的第二次测试不会导致更大的堆内存消耗,在执行垃圾回收后,这让我相信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 特别指出缓存是 off-heap 的
  • VisualVM 直方图显示,98% 的实时字节映射到 byte[]
  • 好像有 client-connector 和 data-streamer-stripe 线程仍然保持打开状态,每个在缓存中进行 put 操作的线程一个,但我不确定它们需要多少堆内存
  • 在 my_cache.put 中提供值提示没有帮助
  • cache.clear(),cache.destroy() 没有帮助(而且也不应该,因为缓存是 off-heap)

任何帮助将非常感激!


1
也许你是正确的;我希望可能有一些未正确设置或我不知道的配置选项或参数,但如果确实是一个错误,那么我应该直接联系产品。感谢您的参与。 - Ka'2
1
是的,非常抱歉,我会记得更频繁地查看StackOverflow。 - Ka'2
那是一个不错的方法,但你可以让它更轻松:在发布问题后更频繁地访问就足够了;-) - GhostCat
2个回答

1
  1. 默认情况下,Apache Ignite不会将数据保存在堆中,而是会将数据保存在堆外。
  2. 当数据被删除时,Apache Ignite确实不会释放堆外内存,但它会允许在摄入新数据时重复使用该堆外内存。
  3. 目前还不清楚您的工具为什么会报告使用了大约16G的堆内存,因为根据提供的配置,Ignite不应该使用超过几百MB。如果这不仅仅是堆内存,而是所有RAM,那么就解释了。您应该期望分配10G,为什么Size字段报告更多并不清楚。

关于第三点,遗憾的是,该工具仅显示由Ignite管理的堆。更改区域的最大大小对消耗的堆没有影响。第1和2点反映了我对Ignite离堆策略的理解。 - Ka'2
1
请收集堆转储并尝试定位堆泄漏/收集堆直方图。 - alamar
我收集了一个堆转储,经过深入分析,我现在发现有5个byte[]数组,每个数组长800 000 024字节(对应我向Ignite提供的数据),还有另外5个数组,每个数组长1 073 741 848 B。第二组数组似乎是某种缓冲区。如果是这种情况,我将明确联系Ignite开发人员,感谢您的意见! - Ka'2
请在Apache Ignite开发者列表上发布这些发现。感谢您进行此调查。您可以尝试定位使用这些数组的用户,以找出哪些代码部分持有它们。 - alamar

0

对于所有关心此事的人,我很抱歉这么长时间才回复,但是在联系了Ignite邮件列表后,我终于得到了我的问题的答案。 显然,Ignite从来没有打算在单个查询中消耗如此大量的数据。 这种行为是预期的,与将数据分成包并将其发送到其他节点或将其放入持久性存储有关。 建议的解决方案是将数据分成更小的块。 由于当前在我的情况下不可能这样做,因此我必须放弃使用Ignite并寻找其他方法来存储我的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接