java - Apache Ignite IGFS 不使用非堆空间

标签 java performance ignite

我正在使用 Apache Ignite 2.6。我正在使用Ignite Filesystem,当我一遍又一遍地将大约25 MB的特定文件写入IGFS时,数据不会保存到非堆空间中。相反,它会进入堆,受到垃圾收集的影响,并且速度相对较慢。如何让 IGFS 将文件保存到我为其分配的大堆空间中?

高级架构——我现在有一个在 tomcat 内部运行的客户端 ignite 节点和一个服务器 ignite 节点,我打算在其上存储这些数据。一旦我按预期工作,就可以进行扩展——但由于上述问题,速度非常慢。当堆空间很快耗尽时,它也会出现 OOM。问题是,我希望它使用我分配的 30G 非堆空间!

我打算将其作为内存缓存。我为 JVM 分配了 2 G 的堆空间和 30G 的非堆空间。非堆空间永远不会被使用,因此会耗尽内存。我已经使用 JMX 控制台“内存”选项卡确认未使用非堆空间 - 非堆空间远低于 100M,而堆空间迅速膨胀到 2G,然后 JVM 崩溃。

详细信息:首先,我的 ignite 配置(spring xml):

 <?xml version="1.0" encoding="UTF-8"?>
 <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="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"/>
    <property name="searchSystemEnvironment" value="true"/>
</bean>
<bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="marshaller">
        <bean class="org.apache.ignite.internal.binary.BinaryMarshaller" />
    </property>

    <property name="fileSystemConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.FileSystemConfiguration">
                <property name="name" value="igfs"/>
                <property name="blockSize" value="#{128 * 1024}"/>
                <property name="perNodeBatchSize" value="512"/>
                <property name="perNodeParallelBatchCount" value="16"/>
                <property name="prefetchBlocks" value="32"/>
            </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>
    <property name="dataStorageConfiguration">
        <bean class="org.apache.ignite.configuration.DataStorageConfiguration" >
            <!-- if I don't set this, the system region runs out of memory almost immediately -->
            <property name="systemRegionMaxSize" value="#{6L * 1024 * 1024 * 1024"} />
            <property name="systemRegionInitialSize" value="#{6L * 1024 * 1024 * 1024"} />
        </bean>

    </property>
</bean>

这是我用来启动 ignite 服务器进程的脚本。它是一个在具有 64 G RAM 和 40 G 磁盘空间的 Linux 机器上运行的 shell 脚本。

IGNITE_HOME=/data/apache-ignite
export IGNITE_HOME
IGNITE_JMX_PORT=1234
export IGNITE_JMX_PORT
$IGNITE_HOME/bin/ignite.sh $IGNITE_HOME/ignite-media-server.xml -J-Xmx2G -J-Xms2G -J-XX::+HeapDumpOnOutOfMemoryError -J-XX:HeapDumpPath=$IGNITE_HOME -J-XX:+PrintGC -J-XX:+PrintGCTimeStamps -J-XX:+PrintGCDateStamps -J-Xloggc:$IGNITE_HOME/gc.log-$(date +%m%d-%H%M%S) -J-XX:+UseG1GC -J-XX:DisableExplicitGC -J-XX:MaxDirectMemorySize=30G 

这是创建我的客户端 igfs 对象的代码,我通过它保存要点燃的文件。它们往往偏大。

public void init() throws Exception{
    igniteInstanceName = "client-name=" + hostInfo.getLocalHost();
    Ignition.setClientMode(true); 
    // reading in the same config file as the server uses to start up above.  The big difference is the clientMode set to true here. 
    try(InputStream configFileInputStream = new FileInputStream(ResourceUtils.getFile("ignite-media-server.xml"));){
         ignite = IgnitionEx.start(configFileInputStream, igniteInstanceName, null, null);
         igfs = ignite.fileSystem("igfs");

    }
    catch(Throwable t){ /* do log */}

}

这是一个保存方法,可以保存我的文件以供点燃:

public saveStream(String cachePath, AudioInputStream toCache){
   OutputStream os = null;
   try{
       IgfsPath cacheFile = new IgfsPath(cachePath);
       os = igfs.create(cacheFile, true);
       AudioSystem.write(toCache.getDataStream, AudioFileFormat.TYPE.WAVE, os);
   }
   finally{
      // close streams
   }
}

为什么我的数据没有保存到快速堆外空间?我缺少什么?我的 server.config 几乎直接来自 igfs 提供的示例。

在其他困惑中,当我使用 ignitevisor.cmd 在较短的测试之前和之后检查服务器节点上的内存使用情况(这不会使其崩溃)时,我看到以下内容:

查看ignitevisor.cmd中ignite为空时的内存分配。看到我的 igfs 区域显示:

  • 已初始化堆内存:2g
  • 使用的堆内存:56mb
  • 初始化非堆内存:2mb
  • 使用的非堆内存:49 mb
  • 非堆内存最大值:744mb

创建 IGFS 中保存的 2G 大小的文件——距离 OOM 还差一点,因为从痛苦的经验来看,我知道它很快就会崩溃。使用ignitevisor.cmd查看节点的内存分配情况。这就是...... – MeowCode 2 分钟前

  • 已初始化堆内存:2GB
  • 使用的堆内存:1GB
  • 使用的非堆内存 64 MB
  • 非堆内存最大值:744mb

为什么非堆中仍然几乎没有任何东西?为什么 ignitevisor 认为非堆最大值是 744 MB,而它应该是 30 GB?

在其他方面,如果我将堆大小增加到 6 GB,它的运行时间会更长,但服务器仍然会因“OutOfMemoryError:Java heap space”而崩溃。有趣的是,即使启用磁盘持久性,我也可以重现这一点。检查堆转储文件会发现大量 ConcurrentLinkedHashMap 条目。这些条目本身是“org.apache.ignite.internal.GridTopic”对象。每个都有一个 uuid,大多数似乎是 TOPIC_DATASTREAM 类型。

最佳答案

数据会保存到堆外,但是您应该注意,IGFS 操作中涉及的许多 transient 对象仍会短暂保留在堆上(之后会被 GC)。

“JMX 控制台内存选项卡 - 非堆空间”是错误的指标。我认为没有任何关于堆外的 JVM 指标。但是,Ignite 将定期打印堆外统计信息。

为什么你会耗尽内存并不明显。您是否尝试过收集堆转储并分析它?

关于java - Apache Ignite IGFS 不使用非堆空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55536778/

相关文章:

java - 点燃堆不释放,这是内存泄漏吗?

java - 在 Java 的接口(interface)中使用固定类型约束?

java - 计算器不会接受用户输入

java - @Service 中的 Spring Boot slf4j Logger 不记录日志

java - return语句后执行的代码

c++ - 使用 n 维 C++ Vector 类实现算术运算符重载的更好方法?

java - Log4j 验证异常是否作为最后一个参数传递

sql - 按有序表上的最大日期删除重复行

redis - 内存分布式缓存中的数据分区和数据持久化

apache-spark - 尝试从 apache ignite context 的 sharedRDD 检索数据