Ignite требует больше памяти в куче

В настоящее время я работаю над созданием Apache Ignite в качестве слоя кэширования. Мое требование — загрузить 10 миллионов данных на сервер при запуске. После кэширования 400 000 записей я столкнулся с ошибкой «Превышены служебные данные GC». Я проверил наличие утечек памяти, и мой код выглядит нормально. Может ли эта проблема быть связана с оперативной памятью моей системы (8 ГБ)?

Я попытался увеличить начальный размер кучи, настроив эти JAVA_OPTS.

-Xms512m -Xmx4g -Xmn2048m -XX:+UseParallelGC

После такой настройки я могу обрабатывать до 800 000 записей, но сразу после этого моя IDE выходит из строя. Мне пришлось перезагрузить систему.

Конфигурация сервера:

 IgniteConfiguration cfg = new IgniteConfiguration();
        cfg.setIgniteInstanceName("Instance");
        cfg.setConsistentId("Node");

        // Create TCP Communication SPI
        TcpCommunicationSpi commSpi = new TcpCommunicationSpi();

        // Set the socketWriteTimeout to 5 seconds (5000 milliseconds)
        commSpi.setSocketWriteTimeout(5000);

        // Data storage configuration

        DataStorageConfiguration storageCfg = new DataStorageConfiguration();
        DataRegionConfiguration regionCfg = new DataRegionConfiguration();
        regionCfg.setName("500MB_Region");

        regionCfg.setPersistenceEnabled(true);
        regionCfg.setInitialSize(1024L * 1024 * 1024); // 1GB initial size
        regionCfg.setMaxSize(6L * 1024 * 1024 * 1024); // 6GB maximum size

        regionCfg.setMetricsEnabled(true); // Enable metrics for monitoring
        // Data region configuration
        regionCfg.setPageEvictionMode(DataPageEvictionMode.RANDOM_LRU);
        regionCfg.setPageReplacementMode(PageReplacementMode.RANDOM_LRU);
        storageCfg.setDefaultDataRegionConfiguration(regionCfg);

        CacheConfiguration<String, String> marksCacheCfg = new CacheConfiguration<>();
        marksCacheCfg.setName("poswavierCache");
        marksCacheCfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
        marksCacheCfg.setCacheMode(CacheMode.REPLICATED);
        marksCacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_ASYNC);

        cfg.setCacheConfiguration(marksCacheCfg);
        cfg.setPeerClassLoadingEnabled(true);
        cfg.setDataStorageConfiguration(storageCfg);


        Ignite igniteServer = Ignition.start(cfg);
        igniteServer.cluster().state(ClusterState.ACTIVE);

        IgniteCache<String, String> marksCache = igniteServer.getOrCreateCache("poswavierCache");
        igniteServer.resetLostPartitions(Arrays.asList("poswavierCache"));
        igniteServer.cluster().baselineAutoAdjustEnabled(true);

Вот как я передаю данные на свой сервер с помощью datastreamer:

 private static final int BATCH_SIZE = 100000;

    @Autowired
    private IgniteCacheService igniteCacheService;

    @Autowired
    private ProductLinesRepo productLinesRepo;

    public CompletableFuture<Void> processAllRecords() {
        long startTime = System.currentTimeMillis();

        int pageNumber = 0;
        Page<ProductLines> page;
        CompletableFuture<Void> future = CompletableFuture.completedFuture(null);

        do {
            page = productLinesRepo.findRecordsWithPanNotNull(PageRequest.of(pageNumber++, BATCH_SIZE));
            List<ProductLines> records = page.getContent();
            if (!records.isEmpty()) {
                int finalPageNumber = pageNumber;
                future = future.thenCompose(result ->
                        CompletableFuture.runAsync(() -> {
                            igniteCacheService.streamBulkData("poswavierCache", records);
                            logger.info("Processed {} records", (finalPageNumber - 1) * BATCH_SIZE + records.size());
                        }));

            }
        } while (page.hasNext());

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        logger.info("Total time taken for processing all records: {} milliseconds", totalTime);

        return future;
    }

DataStreamer:

public void streamBulkData(String cacheName, List<ProductLines> records) {
        try (IgniteDataStreamer<String, ProductLines> streamer = ignite.dataStreamer(cacheName)) {
            streamer.allowOverwrite(true);

            for (ProductLines record : records) {
                String key = record.getPan_no();
                if (key != null) {
                    streamer.addData(key, record);
                } else {
                    System.err.println("Skipping record with null key: " + record);
                }
            }

            streamer.flush();

        } catch (CacheException e) {
            System.err.println("Error streaming data to cache: " + e.getMessage());
            e.printStackTrace();
        }
    }
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь нет одной очевидной вещи, указывающей на проблему, но есть несколько вещей, которые ничего не стоят.

Во-первых, из того, что вы написали, похоже, что у вас одна нода с 8Гб памяти. Для распределенной базы данных в памяти это не очень много.

Во-вторых, похоже, вы перегружаете свою машину. Поскольку Ignite находится в памяти, никогда нельзя разрешать его переключение на диск. Однако вы настроили 4 ГБ кучи и 6 ГБ вне кучи. Это уже превышает 8 ГБ вашей памяти, даже если не учитывать операционную систему, Java и любые другие накладные расходы.

Это не повлияет на использование памяти, но вы настроили вытеснение и сохранение. Выберите один — возможно, настойчивость.

Я не уверен, что понимаю, где находится ваш стример данных (я предполагаю, что это клиент), но он будет использовать много памяти. Вы действительно хотите передавать данные в потоковом режиме, а не копировать их все в память и публиковать в большом пакете.

Наконец, вы настроили Java для использования параллельного сборщика мусора, который очень старый и плохо подходит для многоядерных систем с большим объемом памяти, таких как Ignite. Общая рекомендация — использовать G1. Подробнее в документации.

Что вы подразумеваете под копированием данных в память из внешней базы данных на кеширующий сервер?? Можете ли вы объяснить это, пожалуйста?

Dude Ramasamy 03.04.2024 13:11

Я не уверен, о чем ты спрашиваешь? В своем ответе я никогда не упоминаю внешнюю базу данных.

Stephen Darlington 03.04.2024 14:49

Да жаль. Но мой вариант использования заключается в том, что мне нужно загрузить в кеш 10 миллионов записей из внешней базы данных при запуске. Извините за путаницу

Dude Ramasamy 04.04.2024 07:36

Пожалуйста, задайте это как отдельный вопрос. Похоже, это не связано с этим вопросом.

Stephen Darlington 08.04.2024 14:51

Другие вопросы по теме