gpt4 book ai didi

java - Ignite DataStreamer 中可能存在内存泄漏

转载 作者:太空狗 更新时间:2023-10-29 22:41:35 28 4
gpt4 key购买 nike

我在启用持久性的 Kubernetes 集群中运行 Ignite。每台机器都有一个 24GB 的 Java 堆,其中 20GB 专门用于持久内存,内存限制为 110GB。我的相关 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)

Kubernetes 指标证实了这一点:

enter image description here

“Ignite Cache”是内核页面缓存。最后一个面板“Heap + Durable + Buffer”是点火指标 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>

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

enter image description here

更新:问题已得到证明 here有一个可重现的例子。它可以在至少具有 22GB docker 内存和大约 50GB 存储空间的机器上运行。有趣的是,只有在将字节数组或字符串作为值传递时,泄漏才会真正引人注目。

最佳答案

长篇小说

设置walSegmentSize=64mb (或者只是删除设置并使用默认值)并设置 -XX:MaxDirectMemorySize=<walSegmentSize * 4> .

说明

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

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

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

默认情况下,Ignite 使用内存映射文件写入 WAL - 它通过直接内存缓冲区工作。该缓冲区的大小是 WAL 段的大小。在这里,我们开始讨论有趣的事情。

您的 WAL 段很大! 2GB - 很多。默认值为 64mb,我很少看到使用超过该值的环境。在某些特定工作负载和某些特定磁盘中,我们建议设置 256mb。

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

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

做什么

  1. 选择一个理智的walSegmentSize .我不知道选择 2GB 背后的原因,但我建议选择默认的 64mb 或 256mb,如果您确定遇到小 WAL 段的问题。

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

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

关于java - Ignite DataStreamer 中可能存在内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55752357/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com