即使分配了8GB的空间,Hazelcast也会在堆空间中忍受内存不足的错误。

问题描述 投票:0回答:1

在我的项目中,我有一个需求,从oracle数据库中缓存900万数据到Hazelcast.但显然Hazelcast消耗的堆空间比它应该消耗的更多。我已经为应用程序分配了8bg的堆空间,但我仍然得到了内存不足的错误。

下面是我的数据加载器类。

public class CustomerProfileLoader  implements ApplicationContextAware, MapLoader<Long, CustomerProfile> {

private static CustomerProfileRepository customerProfileRepository;

    @Override
    public CustomerProfile load(Long key) {
        log.info("load({})", key);
        return customerProfileRepository.findById(key).get();
    }

    @Override
    public Map<Long, CustomerProfile> loadAll(Collection<Long> keys) {
        log.info("load all in loader executed");
        Map<Long, CustomerProfile> result = new HashMap<>();
        for (Long key : keys) {
            CustomerProfile customerProfile = this.load(key);
            if (customerProfile != null) {
                result.put(key, customerProfile);
            }
        }
        return result;
    }

   @Override
    public Iterable<Long> loadAllKeys() {

        log.info("Find all keys in loader executed");

        return customerProfileRepository.findAllId();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        customerProfileRepository = applicationContext.getBean(CustomerProfileRepository.class);
    }
}

下面是存储库查询。如果我改变下面的查询,使其限制为200万个数据,那么一切都正常。

 @Query("SELECT b.id FROM CustomerProfile b ")
    Iterable<Long> findAllId();

下面是我的地图配置 hazelcast.xml 文件。在这里,我给 backup count 作为 zero,之前是1,但这并没有任何区别。

<?xml version="1.0" encoding="UTF-8"?>
<hazelcast
        xsi:schemaLocation="http://www.hazelcast.com/schema/config
        http://www.hazelcast.com/schema/config/hazelcast-config-3.11.xsd"
        xmlns="http://www.hazelcast.com/schema/config"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <!-- Use port 5701 and upwards on this machine one for cluster members -->

    <network>
        <port auto-increment="true">5701</port>

        <join>
            <multicast enabled="false"/>
            <tcp-ip enabled="true">
                <interface>127.0.0.1</interface>
            </tcp-ip>
        </join>
    </network>

    <map name="com.sample.hazelcast.domain.CustomerProfile">
        <indexes>
            <!-- custom attribute without an extraction parameter -->
            <index ordered="false">postalCode</index>
        </indexes>
        <backup-count>0</backup-count>
        <map-store enabled="true" initial-mode="EAGER">
            <class-name>com.sample.hazelcast.CustomerProfileLoader</class-name>
        </map-store>
    </map>
</hazelcast>

数据库 表结构。

ID                   NOT NULL NUMBER(19)        
LOGIN_ID       NOT NULL VARCHAR2(32 CHAR) 
FIRSTNAME              VARCHAR2(50 CHAR) 
LASTNAME               VARCHAR2(50 CHAR) 
ADDRESS_LINE1          VARCHAR2(50 CHAR) 
ADDRESS_LINE2          VARCHAR2(50 CHAR) 
CITY                    VARCHAR2(30 CHAR) 
postal_code                VARCHAR2(20 CHAR) 
COUNTRY                 VARCHAR2(30 CHAR) 
CREATION_DATE  NOT NULL DATE              
UPDATED_DATE   NOT NULL DATE              
REGISTER_NUM          NOT NULL VARCHAR2(10 CHAR) 

其他点。

  • 我现在只有一个hazelcast服务器实例在运行,分配的堆空间为8GB。JAVA_OPTS=-Xmx8192m. 之前是4GB,但当我遇到堆空间错误时,我增加到了8GB,但没有成功。
  • 目前maploader是在第一次访问map时执行的。
  • 这个特殊的表(customer_profile)有6列,其中没有任何二进制类型。它只有基本的值,比如firstname lastname之类的。
  • hazelcast使用的版本是3.8。

现在我面临的问题是。

我得到的堆空间错误(java.lang.OutOfMemoryError。Java堆空间)时,它获取所有数据并加载到map。现在表里有900万个数据。

而且它需要很多时间来加载数据,可能我可以通过运行多个实例的hazelcast服务器来解决这个问题。

我是一个新手,所以任何帮助将是非常感激的:)

java hazelcast
1个回答
6
投票

在我看来,真正的问题是你有太多的数据,无法在8GB的堆中容纳。

你说你有100个字节的数据,平均每行表示为字符串数据。

这里有一些估计1 将9,000,000行数据表示成一个 "大 "字,所需的空间是多少?HashMap. 假设有9个字符串,2个日期和一个。int.

  • 在64位的JVM中,一个字符串的开销是48字节+每个字符2字节。 因此,9个Java字符串代表大约100字节的字符数据,大约相当于650字节。
  • A Date 是32字节×2-&gt;64字节。
  • 一条记录代表9个字符串,2个日期和一个int,将是112个字节。
  • 一个键(比如一个 Integer)将是24个字节。
  • 一个HashMap条目将是40个字节。
  • (650 + 64 + 112 + 24 + 40) x 9,000,000 -> ~8,000,000,000 字节。
  • HashMap的主数组将是2^24 x 8字节==~128,000,000字节。

如你所见,那是超过8Gbytes的实际数据。 然后考虑到一个事实,即一个Java堆需要相当大的工作空间,比如说至少30%。

这一点也不奇怪,你会得到OOMEs。 我的估计是你的堆需要大50%......并且假设你对每行100字节的估计是准确的。


这完全是基于你的 loadAll 方法,该方法似乎是将数据库中的所有记录以一个常规的 HashMap. 它没有考虑到Hazelcast用于缓存的堆空间或其他内存。

虽然你可以直接扩展堆,但我认为改变你的代码,让它不像那样实现行,会更有意义。 目前还不清楚这样做是否有意义。 这将取决于如何使用地图。


1 - 我假设你使用的是Java 8。

© www.soinside.com 2019 - 2024. All rights reserved.