Лабораторная работа №3
Разработка распределенного приложения с использованием фреймворка Spring Boot. Действия по варианту должны производиться в LXC контейнерах. Необходимо разработать параллельный вариант алгоритма с применением сервис- ориентированного подхода и фреймворка Spring Boot, замерить время его работы.
Вариант 22 Упорядочить столбцы матрицы по возрастанию первых элементов.
Запуск лабораторной работы CT123: mvn spring-boot:run - запуск сервиса CT124: mvn spring-boot:run - запуск сервиса Виртуальная машина Proxmox: curl http://192.168.22.124:8080/matrix/process?size=1000
Используемые технологии Spring Boot — для создания REST API сервиса. RestTemplate — для отправки HTTP-запросов между сервисами. CompletableFuture— для асинхронного выполнения задач.
Как работает программа:
MatrixProcessorController: Основной сервис для управления процессом. Разделяет матрицу, обрабатывает части параллельно, объединяет результаты. MatrixGeneratorController: Генерирует случайные матрицы. Выполняет сортировку столбцов для правой части матрицы.
Генерация матрицы: Запрос к /generate на GeneratorController Создается квадратная матрица заданного размера со случайными значениями 0-100 Разделение матрицы, исходная матрица делится на две части: Левая часть - обрабатывается локально в ProcessorController Правая часть - отправляется на удаленную обработку в GeneratorController Параллельная обработка: Локальная обработка (асинхронно): Сортировка столбцов по первому элементу Удаленная обработка (асинхронно): POST-запрос к /process на GeneratorController Аналогичная сортировка правой части Слияние результатов после завершения обеих задач: Столбцы из обеих частей объединяются по принципу merge sort Сохраняется общий порядок сортировки по первому элементу
Описание кода:
======Класс MatrixGeneratorController======
//Генерация квадратной матрицы случайных чисел
@GetMapping("/generate")
public double[][] generateMatrix(@RequestParam int size) {
//Обработка матрицы - сортировка столбцов по первому элементу @PostMapping("/process") public double[][] processMatrix(@RequestBody double[][] matrix) { System.out.println("Processing matrix with dimensions: " + matrix.length + "x" + (matrix.length > 0 ? matrix[0].length : 0)); return sortColumnsByFirstElement(matrix); } //Сортировка столбцов матрицы по значению первого элемента private double[][] sortColumnsByFirstElement(double[][] matrix) { // Проверка на пустую матрицу if (matrix.length == 0 || matrix[0].length == 0) { return matrix; } // Создание и сортировка индексов столбцов Integer[] columns = new Integer[matrix[0].length]; for (int i = 0; i < columns.length; i++) columns[i] = i;
Arrays.sort(columns, Comparator.comparingDouble(col -> matrix[0][col]));
// Создание новой матрицы с отсортированными столбцами double[][] sortedMatrix = new double[matrix.length][matrix[0].length]; ======Класс MatrixProcessorController====== // URL сервиса для генерации матриц private final String generatorUrl = "http://192.168.22.123:8080/matrix/generate?size="; // URL удаленного сервиса для обработки половин матрицы private final String processHalfUrl = "http://192.168.22.124:8080/matrix/process"; // Вспомогательный метод для вывода первых 10x10 элементов матрицы private void printMatrix(String name, double[][] matrix) { // Основной эндпоинт для обработки матрицы @GetMapping("/process") public String processMatrix(@RequestParam int size) { RestTemplate restTemplate = new RestTemplate(); long startTime = System.currentTimeMillis(); System.out.println("Program started...");
//Получение исходной матрицы из сервиса-генератора double[][] matrix = restTemplate.getForObject(generatorUrl + size, double[][].class); printMatrix("Original matrix", matrix);
//Разделение матрицы на левую и правую части int cols = matrix[0].length; int splitIndex = cols / 2; //Параллельная обработка половин матрицы CompletableFuture<double[][]> processedLeftFuture = CompletableFuture.supplyAsync(() -> { System.out.println("\nStart local processing..."); ./Локальная обработка левой части (сортировка столбцов) double[][] result = processMatrixLocally(leftPart);
CompletableFuture<double[][]> processedRightFuture = CompletableFuture.supplyAsync(() -> { System.out.println("\nStart remote processing..."); //Удаленная обработка правой части через REST API double[][] result = restTemplate.postForObject(processHalfUrl, rightPart, double[][].class); printMatrix("Remotely processed right part", result); return result; }); //Ожидание завершения обеих задач CompletableFuture.allOf(processedLeftFuture, processedRightFuture).join();
//Получение результатов обработки double[][] left = processedLeftFuture.join(); double[][] right = processedRightFuture.join();
//Слияние и финальная сортировка столбцов double[][] mergedMatrix = mergeSortedColumns(left, right); printMatrix("\nFinal merged matrix", mergedMatrix);
//Завершение работы и вывод статистики long endTime = System.currentTimeMillis(); // Метод для локальной обработки (сортировка столбцов по первому элементу) private double[][] processMatrixLocally(double[][] matrix) { // Алгоритм сортировки столбцов по первому элементу private double[][] sortColumnsByFirstElement(double[][] matrix) { // Создаем массив индексов столбцов для сортировки Integer[] columns = new Integer[matrix[0].length]; for (int i = 0; i < columns.length; i++) columns[i] = i;
// Сортировка индексов по значению первого элемента столбца Arrays.sort(columns, Comparator.comparingDouble(col -> matrix[0][col]));
// Создание новой матрицы с отсортированными столбцами double[][] sorted = new double[matrix.length][matrix[0].length]; // Слияние двух отсортированных матриц с сохранением порядка сортировки private double[][] mergeSortedColumns(double[][] left, double[][] right) { // Вспомогательный метод для копирования столбца между матрицами private void copyColumn(double[][] source, int srcCol, double[][] dest, int destCol) { Тесты: ====Вывод контейнера CT123==== Generate matrix for size: 100 Sorting columns by first element Generate matrix for size: 1000 Sorting columns by first element
====Вывод контейнера CT124====
Program started...
Original matrix (First 10x10 elements): 63 30 66 41 88 58 7 78 89 74 17 88 56 6 32 77 27 85 53 46 49 36 7 32 36 87 99 64 22 63 43 74 9 65 65 73 86 86 49 51 15 55 63 13 56 45 13 20 66 99 70 40 13 50 99 27 68 76 69 91 63 47 66 62 22 45 86 80 14 65 82 61 0 9 94 11 97 66 64 63 58 44 87 86 51 81 24 86 67 40 16 34 49 3 8 38 88 13 54 65
Left part (First 10x10 elements): 63 30 66 41 88 58 7 78 89 74 17 88 56 6 32 77 27 85 53 46 49 36 7 32 36 87 99 64 22 63 43 74 9 65 65 73 86 86 49 51 15 55 63 13 56 45 13 20 66 99 70 40 13 50 99 27 68 76 69 91 63 47 66 62 22 45 86 80 14 65 82 61 0 9 94 11 97 66 64 63 58 44 87 86 51 81 24 86 67 40 16 34 49 3 8 38 88 13 54 65
Right part (First 10x10 elements): 0 4 88 96 28 79 92 29 84 27 25 15 66 62 31 1 50 89 49 30 61 13 6 15 11 94 70 20 11 80 67 17 19 34 7 90 61 93 84 86 76 91 9 57 70 30 65 45 18 31 44 57 29 16 48 37 69 12 32 62 44 96 57 12 93 7 25 76 40 19 27 83 69 2 82 58 40 9 8 91 83 56 48 60 18 38 72 15 91 50 11 85 42 38 40 7 21 78 11 51
Start local processing...
Locally processed left part (First 10x10 elements): 0 1 7 8 9 10 14 17 19 20 91 7 27 74 99 12 78 42 9 2 59 34 99 79 28 22 22 6 47 28 42 53 86 1 40 99 85 33 84 17 14 36 13 63 3 22 80 94 79 29 69 79 68 66 66 32 26 17 56 73 39 75 86 89 8 6 28 89 90 5 46 27 97 77 35 70 23 80 84 91 39 99 24 70 75 85 1 12 85 30 22 70 88 77 93 81 83 59 25 64
Start remote processing...
Remotely processed right part (First 10x10 elements): 0 2 4 7 12 13 15 19 19 22 25 27 15 13 95 51 81 65 52 16 61 21 13 72 75 22 60 24 29 41 67 52 17 71 12 55 5 6 44 59 76 75 91 14 28 48 92 51 99 70 44 82 57 51 56 12 54 60 4 45 44 73 96 82 75 16 16 67 91 11 27 45 83 67 71 87 66 10 51 64 83 24 56 38 84 43 13 34 64 73 11 45 85 89 99 87 2 43 97 96
Final merged matrix (First 10x10 elements): 0 0 1 2 4 7 7 8 9 10 25 91 7 27 15 27 13 74 99 12 61 59 34 21 13 99 72 79 28 22 67 42 53 52 17 86 71 1 40 99 76 14 36 75 91 13 14 63 3 22 44 69 79 82 57 68 51 66 66 32 44 39 75 73 96 86 82 89 8 6 27 46 27 45 83 97 67 77 35 70 83 39 99 24 56 24 38 70 75 85 11 22 70 45 85 88 89 77 93 81
Matrix processed successfully. Total time: 166ms Program started...
Original matrix (First 10x10 elements): 55 45 42 10 45 54 40 52 48 59 4 96 65 52 14 88 4 53 82 88 63 35 25 88 7 10 17 47 98 99 53 53 57 5 79 22 18 35 97 54 18 33 76 83 98 57 96 7 63 6 10 76 76 18 63 89 47 91 86 70 71 69 39 5 30 86 2 28 78 21 36 54 43 47 41 14 92 8 22 7 1 57 0 2 58 14 38 31 35 46 14 86 62 88 37 18 80 87 23 59
Left part (First 10x10 elements): 55 45 42 10 45 54 40 52 48 59 4 96 65 52 14 88 4 53 82 88 63 35 25 88 7 10 17 47 98 99 53 53 57 5 79 22 18 35 97 54 18 33 76 83 98 57 96 7 63 6 10 76 76 18 63 89 47 91 86 70 71 69 39 5 30 86 2 28 78 21 36 54 43 47 41 14 92 8 22 7 1 57 0 2 58 14 38 31 35 46 14 86 62 88 37 18 80 87 23 59
Right part (First 10x10 elements): 2 81 39 89 68 63 20 12 68 49 4 71 2 89 69 44 26 38 85 37 12 67 31 60 77 34 68 51 92 44 12 83 12 51 70 27 29 72 27 61 0 59 83 62 59 98 98 37 64 42 49 63 32 43 44 59 68 64 53 41 91 19 44 0 14 34 86 73 17 45 29 50 0 12 5 67 36 26 78 81 45 3 85 60 19 12 36 57 75 0 78 63 48 27 60 76 99 4 83 80
Start local processing...
Start remote processing...
Locally processed left part (First 10x10 elements): 0 0 0 0 1 1 1 1 1 2 74 0 49 75 83 20 41 61 59 12 64 21 51 54 27 81 71 34 31 7 76 84 86 70 85 54 84 87 79 33 76 71 59 85 75 11 16 89 14 46 97 13 56 30 65 38 78 57 95 63 90 33 54 19 43 97 50 99 68 22 57 69 66 56 29 20 45 74 14 77 23 38 84 14 40 36 87 48 24 72 33 94 42 51 15 53 62 15 12 68
Remotely processed right part (First 10x10 elements): 0 0 0 0 0 0 0 0 0 0 48 60 56 68 3 97 70 40 29 81 2 39 12 3 33 46 37 78 36 99 88 76 59 44 67 82 66 44 68 79 10 20 95 17 3 19 94 18 99 9 19 32 56 7 33 73 31 11 97 77 67 13 99 86 4 68 23 71 9 71 77 6 24 27 51 8 29 77 95 50 5 44 62 14 62 32 7 68 88 17 90 44 77 32 18 77 36 24 47 57
Final merged matrix (First 10x10 elements): 0 0 0 0 0 0 0 0 0 0 48 74 60 56 68 3 0 97 70 49 2 64 39 12 3 33 21 46 37 51 88 76 76 59 44 67 84 82 66 86 10 76 20 95 17 3 71 19 94 59 19 97 32 56 7 33 13 73 31 56 67 90 13 99 86 4 33 68 23 54 77 57 6 24 27 51 69 8 29 66 5 23 44 62 14 62 38 32 7 84 90 33 44 77 32 18 94 77 36 42
Matrix processed successfully. Total time: 2757ms
Вывод: Сравнивая с результами предыдущих лабораторных работ: Однопоточный 14мс; Многопоточный (ThreadPool) 43мс; MPI 99мс. Можно сделать вывод, что сервисный подход медленнее локальных методов для матриц 1000x1000. Причины тому: накладные расходы на сериализацию/десериализацию данных, задержки сетевого взаимодействия между контейнерами. Для задач сортировки матриц сервисный подход на Spring Boot не оправдан при размерах данных менее 100k×100k. Многопоточные решения внутри одного JVM-процесса демонстрируют на порядок лучшую производительность благодаря отсутствию сетевых издержек и эффективному использованию ресурсов CPU. Сервисный подход оправдан только в распределенных системах, где требуется интеграция разнородных систем, необходима отказоустойчивость