diff --git a/khasyanov_aidar_lab_3/README.md b/khasyanov_aidar_lab_3/README.md new file mode 100644 index 0000000..66096ff --- /dev/null +++ b/khasyanov_aidar_lab_3/README.md @@ -0,0 +1,240 @@ +# Лабораторная работа №3 +Разработка распределенного приложения с использованием фреймворка Spring Boot. Действия по варианту должны производиться +в LXC контейнерах. Необходимо разработать параллельный вариант алгоритма с применением сервис-ориентированного подхода и +фреймворка Spring Boot, замерить время его работы. + +## Вариант и задание +2. Разделить элементы матрицы на наименьший элемент. + +## Как запустить лабораторную работу +1. Установить **Java 17** и **Maven** в каждом контейнере. +2. Поставить на два контейнера из трёх копии Worker-service +3. На главный контейнер поставить Master-service +4. В сегменте кода MasterController прописать IP контейнеров с Worker-service и порт, прописанный в application.properties +``` + System.out.println("{Master} Отправка частей матрицы работникам..."); + double[] result1 = restTemplate.postForObject("http://192.168.26.128:8081/process", + new Matrix(part1, min), double[].class); + double[] result2 = restTemplate.postForObject("http://192.168.26.129:8081/process", + new Matrix(part2, min), double[].class); +``` + +5. Собрать и запустить Master-service в главном контейнере: +``` +mvn clean package +java -jar target/master-0.0.1-SNAPSHOT.jar +``` + +6. Собрать и запустить Worker-service в остальных контейнерах +``` +mvn clean package +java -jar target/worker-0.0.1-SNAPSHOT.jar +``` + +5. Запустить обработки выполнить GET-запрос в виртуальной машине, в которой находятся контейнеры, к Master-сервису: +``` +curl http://localhost:8080/start +``` + +## Что делает +Master-servise находит наименьший элемент в матрице, делит матрицу на части, и распределяет их по контейнерам с +Worker-service, где происходит деление частей матрицы на наименьший элемент. После части матрицы отправляются обратно и +собираются. + +## Описание кода + + + +### 1. MasterController.java + +``` +package org.example.master; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import java.util.Arrays; +import java.util.Random; + +@RestController +@RequestMapping("/master") +public class MasterController +{ + int arraySize = 1000; + private final RestTemplate restTemplate = new RestTemplate(); + + @PostMapping("/process") + public double process() + { + long startTime = System.nanoTime(); + + System.out.println("{Master} Генерация матрицы..."); + double[][] matrix = generateMatrix(); + double[] flatMatrix = flattenMatrix(matrix); + + System.out.println("{Master} Поиск наименьшего элемента..."); + double min = Arrays.stream(flatMatrix).min().orElse(Double.NaN); + System.out.println("{Master} Наименьший элемент: " + min); + + System.out.println("{Master} Разделение матрицы на части..."); + int halfSize = (arraySize * arraySize) / 2; + double[] part1 = Arrays.copyOfRange(flatMatrix, 0, halfSize); + double[] part2 = Arrays.copyOfRange(flatMatrix, halfSize, arraySize * arraySize); + + System.out.println("{Master} Отправка частей матрицы работникам..."); + double[] result1 = restTemplate.postForObject("http://192.168.26.128:8081/process", + new Matrix(part1, min), double[].class); + double[] result2 = restTemplate.postForObject("http://192.168.26.129:8081/process", + new Matrix(part2, min), double[].class); + + System.out.println("{Master} Сборка матрицы из частей..."); + double[] resultMatrix = new double[arraySize * arraySize]; + System.arraycopy(result1, 0, resultMatrix, 0, result1.length); + System.arraycopy(result2, 0, resultMatrix, result1.length, result2.length); + double[][] finalMatrix = unflattenMatrix(resultMatrix, arraySize); + + long endTime = System.nanoTime(); + long time = (endTime - startTime) / 1000000; + System.out.println("{Master} Вычисления завершены. Время: " + time + " мс"); + + return time; + } + + static class Matrix + { + public double[] matrix; + public double min; + + public Matrix(double[] matrix, double min) + { + this.matrix = matrix; + this.min = min; + } + } + + private double[][] generateMatrix() + { + Random random = new Random(); + double[][] matrix = new double[arraySize][arraySize]; + for (int i = 0; i < arraySize; i++) + { + for (int j = 0; j < arraySize; j++) + { + matrix[i][j] = random.nextInt(-1000000 , 1000000); + } + } + return matrix; + } + + private double[] flattenMatrix(double[][] matrix) + { + return Arrays.stream(matrix).flatMapToDouble(Arrays::stream).toArray(); + } + + private double[][] unflattenMatrix(double[] array, int arraySize) + { + double[][] matrix = new double[arraySize][arraySize]; + for (int i = 0; i < arraySize; i++) + { + System.arraycopy(array, i * arraySize, matrix[i], 0, arraySize); + } + return matrix; + } +} +``` +MasterController: Основной контроллер, который обрабатывает запросы на /master/process. +processMatrix(): Метод, который генерирует матрицу, находит наименьший элемент, делит матрицу на две части и +отправляет их воркерам для обработки. +MatrixTask: Внутренний класс, который используется для передачи данных (часть матрицы и наименьший элемент) между Master +и Worker. +generateMatrix(): Метод для генерации квадратной матрицы со случайными значениями. +flattenMatrix(): Метод, который преобразует двумерную матрицу в одномерный массив. +unflattenMatrix(): Метод, который преобразует одномерный массив обратно в двумерную матрицу заданного размера. + +### 2. WorkerApplication.java +``` +package org.example.pr; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class WorkerApplication { + public static void main(String[] args) { + SpringApplication.run(WorkerApplication.class, args); + } +} +``` +WorkerApplication: Основной класс для запуска приложения Worker. Использует аннотацию @SpringBootApplication для +автоматической конфигурации Spring Boot. + +### 3. WorkerController.java +``` +package org.example.worker; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import java.util.Arrays; +import java.util.Random; + +@RestController +public class WorkerController +{ + @PostMapping("/process") + public double[] processMatrix(@RequestBody MatrixTask task) + { + double[] matrix = task.matrix; + double min = task.min; + System.out.println("{Worker} Данные получены"); + + System.out.println("{Worker} Деление матрицы на наименьший элемент..."); + for (int i = 0; i < matrix.length; i++) matrix[i] /= min; + System.out.println("{Worker} Деление матрицы завершено."); + return matrix; + } + + static class Matrix + { + public double[] matrix; + public double min; + + public Matrix(double[] matrix, double min) + { + this.matrix = matrix; + this.min = min; + } + } +} +``` +WorkerController: Контроллер, который обрабатывает запросы на /process. +processMatrix(): Метод, который принимает задачу от Master, обрабатывает матрицу, деля каждый элемент на наименьший элемент, +и возвращает результат. +MatrixTask: Внутренний класс, который используется для получения данных от Master. + +## Вывод программы + +### Master +``` +{Мастер} Генерация матрицы... +{Мастер} Поиск наименьшего элемента... +{Мастер} Наименьший элемент: -1000000.0 +{Мастер} Разделение матрицы на части... +{Мастер} Отправка частей матрицы работникам... +{Мастер} Сборка матрицы из частей... +{Мастер} Вычисления завершены. Время: 5512 мс +``` + +### Worker +``` +{Worker} Данные получены +{Worker} Деление матрицы на наименьший элемент... +{Worker} Деление матрицы завершено. +``` + +## Выводы по работе +В ходе лабораторной работы было разработано распределённое приложение +на основе Spring Boot, которое использует сервис-ориентированную архитектуру +для параллельной обработки данных. Spring Boot оказался куда медленнее MPI и ThreadPoolExecutor/ForkJoinPool. Накладные +расходы на HTTP-запросы, передача данных по сети увеличивает время выполнения, также управление потоками в MPI и +специализированных библиотеках более эффективно, так как они оптимизированы для параллельной обработки. \ No newline at end of file diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/.gitignore b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterApplication.java b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterApplication.java new file mode 100644 index 0000000..3c92beb --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterApplication.java @@ -0,0 +1,12 @@ +package org.example.master; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MasterApplication +{ + public static void main(String[] args) + { + SpringApplication.run(MasterApplication.class, args); + } +} diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterController.java b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterController.java new file mode 100644 index 0000000..7125c1b --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/java/org/example/master/MasterController.java @@ -0,0 +1,93 @@ +package org.example.master; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import java.util.Arrays; +import java.util.Random; + +@RestController +@RequestMapping("/master") +public class MasterController +{ + int arraySize = 1000; + private final RestTemplate restTemplate = new RestTemplate(); + + @PostMapping("/process") + public double process() + { + long startTime = System.nanoTime(); + + System.out.println("{Master} Генерация матрицы..."); + double[][] matrix = generateMatrix(); + double[] flatMatrix = flattenMatrix(matrix); + + System.out.println("{Master} Поиск наименьшего элемента..."); + double min = Arrays.stream(flatMatrix).min().orElse(Double.NaN); + System.out.println("{Master} Наименьший элемент: " + min); + + System.out.println("{Master} Разделение матрицы на части..."); + int halfSize = (arraySize * arraySize) / 2; + double[] part1 = Arrays.copyOfRange(flatMatrix, 0, halfSize); + double[] part2 = Arrays.copyOfRange(flatMatrix, halfSize, arraySize * arraySize); + + System.out.println("{Master} Отправка частей матрицы работникам..."); + double[] result1 = restTemplate.postForObject("http://192.168.26.128:8081/process", + new Matrix(part1, min), double[].class); + double[] result2 = restTemplate.postForObject("http://192.168.26.129:8081/process", + new Matrix(part2, min), double[].class); + + System.out.println("{Master} Сборка матрицы из частей..."); + double[] resultMatrix = new double[arraySize * arraySize]; + System.arraycopy(result1, 0, resultMatrix, 0, result1.length); + System.arraycopy(result2, 0, resultMatrix, result1.length, result2.length); + double[][] finalMatrix = unflattenMatrix(resultMatrix, arraySize); + + long endTime = System.nanoTime(); + long time = (endTime - startTime) / 1000000; + System.out.println("{Master} Вычисления завершены. Время: " + time + " мс"); + + return time; + } + + static class Matrix + { + public double[] matrix; + public double min; + + public Matrix(double[] matrix, double min) + { + this.matrix = matrix; + this.min = min; + } + } + + private double[][] generateMatrix() + { + Random random = new Random(); + double[][] matrix = new double[arraySize][arraySize]; + for (int i = 0; i < arraySize; i++) + { + for (int j = 0; j < arraySize; j++) + { + matrix[i][j] = random.nextInt(-1000000 , 1000000); + } + } + return matrix; + } + + private double[] flattenMatrix(double[][] matrix) + { + return Arrays.stream(matrix).flatMapToDouble(Arrays::stream).toArray(); + } + + private double[][] unflattenMatrix(double[] array, int arraySize) + { + double[][] matrix = new double[arraySize][arraySize]; + for (int i = 0; i < arraySize; i++) + { + System.arraycopy(array, i * arraySize, matrix[i], 0, arraySize); + } + return matrix; + } +} \ No newline at end of file diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/resources/application.properties b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/resources/application.properties new file mode 100644 index 0000000..a3ac65c --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Master-service/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 \ No newline at end of file diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/.gitignore b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerApplication.java b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerApplication.java new file mode 100644 index 0000000..b3ef5f6 --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerApplication.java @@ -0,0 +1,12 @@ +package org.example.worker; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class WorkerApplication +{ + public static void main(String[] args) + { + SpringApplication.run(WorkerApplication.class, args); + } +} diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerController.java b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerController.java new file mode 100644 index 0000000..6079523 --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/java/org/example/worker/WorkerController.java @@ -0,0 +1,36 @@ +package org.example.worker; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import java.util.Arrays; +import java.util.Random; + +@RestController +public class WorkerController +{ + @PostMapping("/process") + public double[] processMatrix(@RequestBody MatrixTask task) + { + double[] matrix = task.matrix; + double min = task.min; + System.out.println("{Worker} Данные получены"); + + System.out.println("{Worker} Деление матрицы на наименьший элемент..."); + for (int i = 0; i < matrix.length; i++) matrix[i] /= min; + System.out.println("{Worker} Деление матрицы завершено."); + return matrix; + } + + static class Matrix + { + public double[] matrix; + public double min; + + public Matrix(double[] matrix, double min) + { + this.matrix = matrix; + this.min = min; + } + } +} diff --git a/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/resources/application.properties b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/resources/application.properties new file mode 100644 index 0000000..bafddce --- /dev/null +++ b/khasyanov_aidar_lab_3/SSPR_LAB_3/Worker-service/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8081 \ No newline at end of file