Данная статья является описанием моего эксперимента передать управление ресурсами JVM нейронной сети, которая будет предсказывать необходимость управления ресурсами на основе текущих данных, таких как загрузка CPU и память.
Отмечу, что не берется в расчет влияние, в текущем моменте времени, дополнительных процессов загрузки ресурсов нашей системы.
Применимость и потенциальные возможности
Предполагается, что нейронная сеть сможет предсказывать пиковые нагрузки, что позволит избежать избыточного расхода ресурсов или, наоборот, их нехватки. На практике это может быть полезно в разных системах, особенно в микросервисной архитектуре, где контейнеры регулярно требуют динамического управления ресурсами. Например Kubernetes динамически изменяет ресурсы на основе данных, которые передает AI-сервис. Это может быть полезно, если в будущем потребуется увеличить автономность системы.
Что мы реализуем
Мы построим систему, которая:
-
Считывает показатели системы (CPU, память) в реальном времени.
-
Обучает нейронную сеть на исторических данных для предсказания вероятности перегрузки.
-
Корректирует параметры JVM, если прогнозируемая нагрузка превышает порог.
Пример данных для обучения
Для простоты в качестве данных для обучения мы будем использовать CSV-файл jvm_usage.csv
, который содержит три столбца:
-
CPU
— текущая загрузка процессора, -
Memory
— текущее использование памяти, -
HighLoad
— метка перегрузки (0 или 1), обозначающая, была ли нагрузка высокой.
Пример содержимого CSV:
0.7,3000,0
0.8,4000,1
0.6,2000,0
1.0,4500,1
Настройка многослойной нейронной сети на Java
Для реализации нейронной сети мы используем библиотеку DeepLearning4j
. Создадим модель с двумя слоями для обработки входных данных о CPU и памяти и одним выходным нейроном, который будет прогнозировать необходимость увеличения ресурсов JVM.
Подключение необходимых зависимостей
В build.gradle
добавьте:
dependencies { implementation ("org.slf4j:slf4j-simple:1.7.32") implementation ("org.deeplearning4j:deeplearning4j-core:1.0.0-beta7") implementation ("org.nd4j:nd4j-native-platform:1.0.0-beta7") implementation ("org.datavec:datavec-api:1.0.0-beta7") implementation ("org.datavec:datavec-local:1.0.0-beta7") }
Код для настройки и обучения модели
import org.deeplearning4j.nn.api.OptimizationAlgorithm; import org.deeplearning4j.nn.conf.MultiLayerConfiguration; import org.deeplearning4j.nn.conf.NeuralNetConfiguration; import org.deeplearning4j.nn.conf.layers.DenseLayer; import org.deeplearning4j.nn.conf.layers.OutputLayer; import org.deeplearning4j.nn.multilayer.MultiLayerNetwork; import org.nd4j.linalg.activations.Activation; import org.nd4j.linalg.dataset.api.iterator.DataSetIterator; import org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator; import org.nd4j.linalg.learning.config.Nesterovs; import org.nd4j.linalg.lossfunctions.LossFunctions; import org.nd4j.linalg.api.ndarray.INDArray; import org.nd4j.linalg.factory.Nd4j; import org.datavec.api.records.reader.impl.csv.CSVRecordReader; import org.datavec.api.split.FileSplit; import java.io.File public class JVMAIManager { private MultiLayerNetwork model; public void initializeModel() { MultiLayerConfiguration config = new NeuralNetConfiguration.Builder() .seed(123) .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT) .updater(new Nesterovs(0.1, 0.9)) .list() .layer(0, new DenseLayer.Builder().nIn(2).nOut(10) .activation(Activation.RELU) .build()) .layer(1, new DenseLayer.Builder().nIn(10).nOut(10) .activation(Activation.RELU) .build()) .layer(2, new OutputLayer.Builder(LossFunctions.LossFunction.XENT) .activation(Activation.SIGMOID) .nIn(10).nOut(1).build()) .build(); model = new MultiLayerNetwork(config); model.init(); } public void trainModel(String datasetPath) throws Exception { int batchSize = 50; int labelIndex = 2; int numClasses = 1; CSVRecordReader reader = new CSVRecordReader(); reader.initialize(new FileSplit(new File(datasetPath))); DataSetIterator iterator = new RecordReaderDataSetIterator(reader, batchSize, labelIndex, numClasses); model.fit(iterator); } public double predict(double currentCpu, double currentMemory) { INDArray input = Nd4j.create(new double[]{currentCpu, currentMemory}, new int[]{1, 2}); INDArray output = model.output(input); return output.getDouble(0); } }
Данный блок кода строит архитектуру нейронной сети, задавая её конфигурацию и порядок слоёв:
-
Инициализация настроек сети. Мы начинаем с установки базовых параметров сети с помощью
NeuralNetConfiguration.Builder()
. Здесь задаётся seed (случайное начальное значение для генератора), которое помогает воспроизводить результаты, а также выбирается алгоритм оптимизации — стохастический градиентный спуск (SGD). Этот метод регулирует веса сети, минимизируя ошибку на каждом шаге обучения. Дополнительно, для улучшения и стабилизации процесса обучения, мы подключаем обновляющий алгоритмNesterovs
— метод, который «заглядывает» вперёд, избегая лишних колебаний. -
Создание слоёв. Мы добавляем три слоя в сеть:
-
Первый слой — DenseLayer, или полносвязный слой, принимает на вход два признака (например, значения загрузки процессора и памяти) и выводит 10 нейронов. Он использует функцию активации ReLU (Rectified Linear Unit), которая сохраняет положительные значения и обнуляет отрицательные. Этот слой помогает сети находить сложные зависимости между признаками.
-
Второй слой — ещё один полносвязный слой с 10 нейронами и функцией активации ReLU. Этот слой обрабатывает и преобразует выходные данные из первого слоя, углубляя сеть для лучшего обучения.
-
Выходной слой — OutputLayer, служит для получения конечного предсказания. Здесь мы используем функцию активации Sigmoid, которая выводит значение от 0 до 1. Это полезно для задач бинарной классификации, где результат нужно интерпретировать как вероятность принадлежности к одному из двух классов. Мы также указываем функцию потерь
XENT
(кросс-энтропия), которая вычисляет расхождение между предсказанием и истинным ответом, помогая сети улучшать точность.
-
-
Инициализация модели. С помощью вызова
MultiLayerNetwork
создаётся нейронная сеть на основе конфигурации, и вызываетсяmodel.init()
, что завершает процесс построения архитектуры сети и подготавливает её для обучения.
Мониторинг и адаптивная настройка JVM
Добавим классJVMAIAutotuner
для мониторинга и динамического управления параметрами JVM:
import java.lang.management.ManagementFactory; import com.sun.management.OperatingSystemMXBean; import java.util.logging.Logger; public class JVMAIAutotuner { private static final Logger logger = Logger.getLogger(JVMAIAutotuner.class.getName()); private final OperatingSystemMXBean osBean; private final JVMAIManager aiManager; public JVMAIAutotuner(JVMAIManager aiManager) { this.osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); this.aiManager = aiManager; } public void monitorAndAdapt() { try { while (true) { double cpuLoad = osBean.getSystemCpuLoad(); double usedMemory = osBean.getTotalPhysicalMemorySize() - osBean.getFreePhysicalMemorySize(); double prediction = aiManager.predict(cpuLoad, usedMemory); logger.info(String.format("Прогноз вероятности высокой нагрузки: %.2f", prediction)); if (prediction > 0.8) { logger.info("Высокая вероятность перегрузки. Увеличиваем ресурсы JVM..."); increaseHeapMemory(); } Thread.sleep(5000); } } catch (Exception e) { logger.warning("Ошибка в мониторинге и адаптации: " + e.getMessage()); } } private void increaseHeapMemory() { logger.info("Перезапуск JVM с увеличенной памятью..."); // Логика перезапуска или конфигурации контейнера } }
Локальный запуск кода
В классе Main
создаем экземпляры JVMAIManager
и JVMAIAutotuner
и запускаем:
public class Main { public static void main(String[] args) throws Exception { JVMAIManager aiManager = new JVMAIManager(); aiManager.initializeModel(); aiManager.trainModel("path/to/jvm_usage.csv"); // Укажите путь к CSV-файлу JVMAIAutotuner autotuner = new JVMAIAutotuner(aiManager); autotuner.monitorAndAdapt(); } }
Результаты и возможные доработки
Такой подход позволяет автоматически управлять ресурсами JVM, прогнозируя высокие нагрузки. Вы можете адаптировать этот код для использования в реальных условиях, например, в среде Kubernetes, добавив поддержку динамической настройки контейнеров через API и интеграцию с системой мониторинга, такой как Prometheus.
ссылка на оригинал статьи https://habr.com/ru/articles/856376/
Добавить комментарий