Ignite DataStreamer中可能的内存泄漏

kel*_*ket 18 java garbage-collection memory-leaks kubernetes ignite

我正在启用持久性的Kubernetes集群中运行Ignite。每台机器都有一个24 GB的Java堆,其中20 GB专门用于持久内存,内存限制为110 GB。我相关的JVM选项是-XX:+AlwaysPreTouch -XX:+UseG1GC -XX:+ScavengeBeforeFullGC。在每个节点上运行DataStreamers几个小时后,群集中的节点达到k8s内存限制,触发了OOM终止。运行Java NMT后,我惊讶地发现分配给内部存储器的大量空间。

Java Heap (reserved=25165824KB, committed=25165824KB)
(mmap: reserved=25165824KB, committed=25165824KB)  

Internal (reserved=42425986KB, committed=42425986KB)
(malloc=42425954KB #614365) 
(mmap: reserved=32KB, committed=32KB) 
Run Code Online (Sandbox Code Playgroud)

Kubernetes指标证实了这一点:

在此处输入图片说明

“点燃缓存”是内核页面缓存。最后一个面板“堆+持久+缓冲区”是点火指标HeapMemoryUsed+ PhysicalMemorySize+ 的总和CheckpointBufferSize

我知道这不是数据积累的结果,因为DataStreamer在读取每个文件后都会刷新(最大约250MB),并且没有节点一次读取4个以上的文件。在排除了其他问题之后,我尝试设置-XX:MaxDirectMemorySize=10G并调用了手动GC,但是除了定期关闭所有pod并重新启动它们之外,似乎没有任何影响。

我不确定从这里去哪里。Ignite中是否有一种解决方法不强迫我使用第三方数据库?

编辑:我的DataStorageConfiguration

    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
            <property name="metricsEnabled" value="true"/>
            <property name="checkpointFrequency" value="300000"/>
            <property name="storagePath" value="/var/lib/ignite/data/db"/>
            <property name="walFlushFrequency" value="10000"/>
            <property name="walMode" value="LOG_ONLY"/>
            <property name="walPath" value="/var/lib/ignite/data/wal"/>
            <property name="walArchivePath" value="/var/lib/ignite/data/wal/archive"/>               
            <property name="walSegmentSize" value="2147483647"/>
            <property name="maxWalArchiveSize" value="4294967294"/>
            <property name="walCompactionEnabled" value="false"/>
            <property name="writeThrottlingEnabled" value="False"/>
            <property name="pageSize" value="4096"/>                
            <property name="defaultDataRegionConfiguration">
                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                    <property name="persistenceEnabled" value="true"/>
                    <property name="checkpointPageBufferSize" value="2147483648"/>
                    <property name="name" value="Default_Region"/>
                    <property name="maxSize" value="21474836480"/>
                    <property name="metricsEnabled" value="true"/>
                </bean>
            </property>
        </bean>
    </property> 
Run Code Online (Sandbox Code Playgroud)

更新:当我禁用持久性时,内部存储器将被正确处置:

在此处输入图片说明

UPDATE:证明这个问题这里有一个重复的例子。它可以在至少有22GB内存用于docker和约50GB存储空间的机器上运行。有趣的是,只有在传入字节数组或字符串作为值时,泄漏才真正引起注意。

kel*_*ket 2

内存泄漏似乎是由@QueryTextField我的缓存模型中值对象的注释触发的,该模型支持 Ignite 中的 Lucene 查询。

起初:case class Value(@(QueryTextField@field) theta: String)

将此行更改为:case class Value(theta: String)似乎可以解决问题。我没有解释为什么会这样,但也许对 Ignite 代码库有深入了解的人可以解释原因。