即使分配了 8GB space,Hazelcast 最终也会出现堆 space 内存不足错误

Hazelcast endup in heap space out of memory error even if 8GB space allocated

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

下面是我的数据加载器 class .

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>

数据库Table结构:

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) 

其他要点:

我现在面临的问题是:

当它获取所有数据和将其加载到地图上。现在table里面有900万条数据。

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

我是 hazelcast 的新手,非常感谢任何帮助:)

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

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

这里有一些估计1 space 需要将 9,000,000 行数据表示为 HashMap。假设有9个字符串,2个日期和一个int.

  • 在 64 位 JVM 中,字符串的开销为 48 字节 + 每个字符 2 字节。所以 9 Java 个字符串代表大约 100 个字节的字符数据,总计大约 650 个字节。
  • A Date 是 32 字节 x 2 -> 64 字节
  • 代表 9 个字符串、2 个日期和 1 个整数的记录将是 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 字节

如您所见,实际数据超过 8GB。然后考虑到 Java 堆需要大量工作 space 的事实;至少说30%。

您得到 OOME 一点也不奇怪。我的估计是您的堆需要大 50%...并且假定您对每行 100 字节的估计是准确的。


这完全基于您的 loadAll 方法,该方法似乎将数据库中的所有行具体化为常规 HashMap。它不考虑 Hazelcast 用于缓存的堆 space 或其他内存。

虽然您可以只扩展堆,但我认为更改代码更有意义,这样它就不会像那样具体化行。目前尚不清楚这是否有意义。这将取决于地图的使用方式。


1 - 我假设您使用的是 Java 8.