在我的项目中,我有一个需求,从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)
其他点。
JAVA_OPTS=-Xmx8192m
. 之前是4GB,但当我遇到堆空间错误时,我增加到了8GB,但没有成功。现在我面临的问题是。
我得到的堆空间错误(java.lang.OutOfMemoryError。Java堆空间)时,它获取所有数据并加载到map。现在表里有900万个数据。
而且它需要很多时间来加载数据,可能我可以通过运行多个实例的hazelcast服务器来解决这个问题。
我是一个新手,所以任何帮助将是非常感激的:)
在我看来,真正的问题是你有太多的数据,无法在8GB的堆中容纳。
你说你有100个字节的数据,平均每行表示为字符串数据。
这里有一些估计1 将9,000,000行数据表示成一个 "大 "字,所需的空间是多少?HashMap
. 假设有9个字符串,2个日期和一个。int
.
Date
是32字节×2->;64字节。Integer
)将是24个字节。如你所见,那是超过8Gbytes的实际数据。 然后考虑到一个事实,即一个Java堆需要相当大的工作空间,比如说至少30%。
这一点也不奇怪,你会得到OOMEs。 我的估计是你的堆需要大50%......并且假设你对每行100字节的估计是准确的。
这完全是基于你的 loadAll
方法,该方法似乎是将数据库中的所有记录以一个常规的 HashMap
. 它没有考虑到Hazelcast用于缓存的堆空间或其他内存。
虽然你可以直接扩展堆,但我认为改变你的代码,让它不像那样实现行,会更有意义。 目前还不清楚这样做是否有意义。 这将取决于如何使用地图。
1 - 我假设你使用的是Java 8。