Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Ignite DataStreamer中可能存在内存泄漏_Java_Memory Leaks_Kubernetes_Garbage Collection_Ignite - Fatal编程技术网

Java Ignite DataStreamer中可能存在内存泄漏

Java Ignite DataStreamer中可能存在内存泄漏,java,memory-leaks,kubernetes,garbage-collection,ignite,Java,Memory Leaks,Kubernetes,Garbage Collection,Ignite,我在启用持久性的Kubernetes集群中运行Ignite。每台机器都有一个24GB的Java堆,其中20GB用于持久内存,内存限制为110GB。我的相关JVM选项是-XX:+AlwaysPreTouch-XX:+UseG1GC-XX:+ScreeveBeFoullGC。在每个节点上运行DataStreamers几个小时后,我集群上的节点达到其k8s内存限制,触发OOM终止。在运行JavaNMT之后,我惊讶地发现分配给内部内存的空间非常大 Java Heap (reserved=25165824

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

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

Internal (reserved=42425986KB, committed=42425986KB)
(malloc=42425954KB #614365) 
(mmap: reserved=32KB, committed=32KB) 
Kubernetes metrics证实了这一点:

“Ignite缓存”是内核页面缓存。最后一个面板“堆+持久+缓冲区”是ignite度量的总和
HeapMemoryUsed
+
PhysicalMemorySize
+
CheckpointBufferSize

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

我不知道接下来该怎么办。Ignite中是否有一种解决方法不强迫我使用第三方数据库

编辑:我的数据存储配置

    <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> 

更新:当我禁用持久性时,内部内存被正确处理:

更新:通过一个可复制的示例演示了该问题。它可以在docker至少有22GB内存和50GB存储的机器上运行。有趣的是,只有当传入字节数组或字符串作为值时,泄漏才真正明显

我不知道您的案例中的“内部”是什么,但Ignite通常会将其所有数据存储在堆外内存中。请注意,它也不是“直接”内存


您可以,以及。

在启用和不启用持久性的情况下,我可以从您的图表中看到ignite缓存指标的巨大差距。这意味着,通过持久性,您实际上正在将数据写入数据存储目录wal、walArchive。如果Kubernetes吊舱也考虑了内存中的目录限制,那么它可能很快就会耗尽内存

TLDR 设置
walSegmentSize=64mb
(或者只需删除设置并使用默认值),然后设置
-XX:MaxDirectMemorySize=

解释 在计算Ignite的内存需求时,人们经常忘记的一件事是直接内存缓冲区大小

直接内存缓冲区是从Java进程中的单独空间分配的JVM管理的缓冲区-它既不是Java堆,也不是Ignite数据区域或Ignite检查点缓冲区

直接内存缓冲区是Java中与非堆内存交互的正常方式。有很多东西使用它(从JVM的内部代码到应用程序),但在Ignite服务器中,直接内存池的主要用户是写前日志

默认情况下,Ignite使用内存映射文件写入WAL,该文件通过直接内存缓冲区工作。该缓冲区的大小是WAL段的大小。现在我们来谈谈有趣的事情

你的墙是巨大的!2GB-这是很多。默认值是64mb,我很少看到一个环境会使用更多的内存。在某些特定的工作负载和某些特定的磁盘中,我们建议设置256mb

因此,在直接内存池中创建了2GB缓冲区。默认情况下,直接内存的最大大小等于
-Xmx
——在您的情况下为24GB。我可以看到这样一种情况:您的直接内存池将膨胀到24GB(从尚未清除的旧缓冲区),使应用程序的总大小至少
20+2+24+24=70GB

这解释了40GB的内部JVM内存(我认为这是数据区域+直接)。这也解释了为什么当持久性关闭时,您没有看到问题——在这种情况下,您没有WAL

怎么办
  • 选择一个正常的
    walSegmentSize
    。我不知道2GB选择背后的原因,但我建议您要么选择默认的64mb,要么选择256mb,如果您确定您对小型WAL段有问题的话

  • 通过
    -XX:MaxDirectMemorySize=
    设置JVM直接内存池的限制。我发现将其设置为
    walSegmentSize*4
    的值是一个安全的选择,即在256mb-1gb的范围内


  • 即使您在进行上述更改后发现内存消耗问题,也要保留它们,因为它们是99%群集的最佳选择。

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

    最初:
    case类值(@(QueryTextField@field)θ:字符串)

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

    对不起,我应该从一开始就更清楚地回答我的问题。在我的集群上启用了持久性,因此页面逐出在这种情况下不相关。我对问题进行了编辑以反映。我知道,在Ignite中,堆外内存是可配置的,每个数据区域都可以配置——我已经在映像的最后一个面板中显示了Ignite“正式”消耗的堆外内存总量,这远远低于RSS使用总量,因此内存泄漏