Лабораторная работа №3
Задание
Разработать распределенное приложение с использованием фреймворка Spring Boot.
Необходимо: разработать параллельный вариант алгоритма с применением сервис-ориентированного подхода и фреймворка Spring Boot, замерить время его работы. Действия по варианту должны производиться в LXC контейнерах.
Вариант: упорядочить строки матрицы по возрастанию суммы их элементов (18).
Описание
Этот проект представляет собой распределенное приложение, разработанное с использованием фреймворка Spring Boot. Приложение состоит из двух сервисов, работающих в отдельных LXC-контейнерах:
-
MatrixMasterService (Ubuntu) — основной сервис, который генерирует матрицу, разделяет её на части, сортирует одну часть и отправляет другую часть на сортировку во второй сервис.
-
MatrixWorkerService (RockyLinux) — вспомогательный сервис, который получает часть матрицы, сортирует её и возвращает результат.
Приложение упорядочивает строки матрицы по возрастанию суммы их элементов.
Технологии
-
Spring Boot — фреймворк для создания микросервисов.
-
LXC — технология контейнеризации для запуска изолированных сред.
-
Maven — инструмент для сборки и управления зависимостями.
-
Java 17 — язык программирования (а также JDK под него).
-
REST API — для взаимодействия между сервисами.
-
SLF4J/Logback — для логирования.
Как работает программа
MatrixMasterService
1. Класс MatrixMasterServiceApplication
Этот класс является точкой входа в приложение. Он запускает Spring Boot приложение.
@SpringBootApplication
public class MatrixMasterServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MatrixMasterServiceApplication.class, args);
}
}
2. Класс MatrixController
Этот класс содержит REST-контроллер, который обрабатывает HTTP-запросы.
- Метод generateAndProcessMatrix:
- Логика работы:
- Генерация случайной матрицы 8x8.
- Разделение матрицы на две части.
- Отправка первой половины в MatrixWorkerService.
- Сортировка второй половины.
- Получение отсортированной первой половины.
- Сборка и вывод итоговой матрицы.
- Логика работы:
@GetMapping("/generate-and-process")
public int[][] generateAndProcessMatrix() {
long startTime = System.currentTimeMillis();
logger.info("Начало генерации и обработки матрицы");
// Генерация матрицы 8x8
int[][] matrix = generateRandomMatrix(8, 8);
logger.info("Сгенерирована матрица:\n{}", formatMatrix(matrix));
// Разделяем матрицу на две части
int mid = matrix.length / 2;
int[][] firstHalf = Arrays.copyOfRange(matrix, 0, mid);
int[][] secondHalf = Arrays.copyOfRange(matrix, mid, matrix.length);
// Отправляем первую половину в MatrixWorkerService
logger.info("Отправка первой половины матрицы в MatrixWorkerService:\n{}", formatMatrix(firstHalf));
int[][] sortedFirstHalf = sendToWorkerService(firstHalf);
// Сортируем вторую половину в MatrixMasterService
logger.info("Сортировка второй половины матрицы в MatrixMasterService:\n{}", formatMatrix(secondHalf));
sortMatrixRows(secondHalf);
logger.info("Отсортированная вторая половина матрицы:\n{}", formatMatrix(secondHalf));
// Получаем отсортированную первую половину
logger.info("Получена отсортированная первая половина матрицы:\n{}", formatMatrix(sortedFirstHalf));
// Собираем отсортированные части
int[][] result = new int[matrix.length][];
System.arraycopy(sortedFirstHalf, 0, result, 0, sortedFirstHalf.length);
System.arraycopy(secondHalf, 0, result, sortedFirstHalf.length, secondHalf.length);
// Сортируем итоговую матрицу
logger.info("Сортировка двух частей матрицы...\n");
sortMatrixRows(result);
logger.info("Итоговая отсортированная матрица:\n{}", formatMatrix(result));
long endTime = System.currentTimeMillis();
logger.info("Обработка матрицы завершена. Время выполнения: {} мс", endTime - startTime);
return result;
}
- Метод sortMatrixRows
- Описание: Сортирует строки матрицы по возрастанию суммы их элементов.
- Логика работы: использует Arrays.sort с компаратором, который сравнивает строки по сумме их элементов.
private void sortMatrixRows(int[][] matrix) {
Arrays.sort(matrix, Comparator.comparingInt(row -> Arrays.stream(row).sum()));
}
- Метод sendToWorkerService
- Описание: Отправляет часть матрицы в MatrixWorkerService.
- Логика работы:
- Использует RestTemplate для отправки POST-запроса.
- Возвращает отсортированную часть матрицы.
private int[][] sendToWorkerService(int[][] matrix) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://192.168.17.118:8081/sort";
return restTemplate.postForObject(url, matrix, int[][].class);
}
MatrixWorkerService
1. Класс MatrixWorkerServiceApplication
Так же, как и класс MatrixMasterServiceApplication, этот класс является точкой входа в приложение. Он запускает Spring Boot приложение на втором контейнере.
@SpringBootApplication
public class MatrixWorkerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MatrixWorkerServiceApplication.class, args);
}
}
2. Класс MatrixController
Этот класс содержит REST-контроллер, который обрабатывает HTTP-запросы (опять-таки по аналогии с классом в первом контейнере).
- Метод sortMatrix
- Описание: Сортирует часть матрицы, полученную от MatrixMasterService.
- Логика работы:
- Получает часть матрицы.
- Сортирует строки по возрастанию суммы их элементов.
- Возвращает отсортированную часть обратно.
@PostMapping("/sort")
public int[][] sortMatrix(@RequestBody int[][] matrix) {
long startTime = System.currentTimeMillis();
logger.info("Получена часть матрицы для сортировки:\n{}", formatMatrix(matrix));
// Сортировка части матрицы
Arrays.sort(matrix, Comparator.comparingInt(row -> Arrays.stream(row).sum()));
logger.info("Сортировка части матрицы завершена:\n{}", formatMatrix(matrix));
// Отправка отсортированной части обратно в MatrixMasterService
logger.info("Отправка отсортированной части матрицы в MatrixMasterService...\n");
long endTime = System.currentTimeMillis();
logger.info("Время выполнения сортировки: {} мс", endTime - startTime);
return matrix;
}
Как запустить программу
1. Создание проекта
В каждом контейнере создается Maven-проект с использованием Spring Boot:
mvn archetype:generate -DgroupId=com.example -DartifactId=matrix-master-service -Dversion=1.0 -Dpackage=com.example.matrixmasterservice -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Для MatrixWorkerService нужно заменить matrix-master-service и matrixmasterservice на matrix-worker-service и matrixworkerservice.
2. Настройка pom.xml:
Добавляем зависимости для Spring Boot и других библиотек в pom.xml каждого проекта.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Родительский POM Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>matrix-master-service</artifactId>
<version>1.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Web (для REST-контроллеров) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok (для упрощения кода) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Starter Test (для тестирования) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven Plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Настройка application.properties:
В директории /src/main/resources каждого проекта создаем файл application.properties, где указываем порты подключения и уровень логирования.
server.port=8080
logging.level.com.example.matrixmasterservice=INFO
Для второго контейнера порт будет 8081-ым.
4. Сборка проекта
В каждом контейнере нужно выполнить команду для сборки проекта:
mvn clean package
5. Запуск приложения
Запускаем каждый сервис в соответствующем контейнере:
mvn spring-boot:run
6. Отправка запроса
Отправляем GET-запрос на MatrixMasterService для генерации и обработки матрицы:
curl http://192.168.17.117:8080/generate-and-process
Результат работы программы
Отправка запроса с хостовой машины
root@vbox:~# curl http://192.168.17.117:8080/generate-and-process
Ответ:
[[36,13,16,24,42,8,68,64],[57,27,84,5,0,66,21,14],[87,62,72,32,30,20,15,17],[86,29,85,16,14,47,62,13],[65,41,85,6,77,13,47,25],[73,41,67,66,0,11,47,74],[28,81,56,87,25,49,33,46],[88,66,44,44,85,31,97,52]]
Сервис 1
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Начало генерации и обработки матрицы
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Сгенерирована матрица:
[87, 62, 72, 32, 30, 20, 15, 17]
[88, 66, 44, 44, 85, 31, 97, 52]
[36, 13, 16, 24, 42, 8, 68, 64]
[86, 29, 85, 16, 14, 47, 62, 13]
[57, 27, 84, 5, 0, 66, 21, 14]
[28, 81, 56, 87, 25, 49, 33, 46]
[65, 41, 85, 6, 77, 13, 47, 25]
[73, 41, 67, 66, 0, 11, 47, 74]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Отправка первой половины матрицы в MatrixWorkerService:
[87, 62, 72, 32, 30, 20, 15, 17]
[88, 66, 44, 44, 85, 31, 97, 52]
[36, 13, 16, 24, 42, 8, 68, 64]
[86, 29, 85, 16, 14, 47, 62, 13]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Сортировка второй половины матрицы в MatrixMasterService:
[57, 27, 84, 5, 0, 66, 21, 14]
[28, 81, 56, 87, 25, 49, 33, 46]
[65, 41, 85, 6, 77, 13, 47, 25]
[73, 41, 67, 66, 0, 11, 47, 74]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Отсортированная вторая половина матрицы:
[57, 27, 84, 5, 0, 66, 21, 14]
[65, 41, 85, 6, 77, 13, 47, 25]
[73, 41, 67, 66, 0, 11, 47, 74]
[28, 81, 56, 87, 25, 49, 33, 46]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Получена отсортированная первая половина матрицы:
[36, 13, 16, 24, 42, 8, 68, 64]
[87, 62, 72, 32, 30, 20, 15, 17]
[86, 29, 85, 16, 14, 47, 62, 13]
[88, 66, 44, 44, 85, 31, 97, 52]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Сортировка двух частей матрицы...
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Итоговая отсортированная матрица:
[36, 13, 16, 24, 42, 8, 68, 64]
[57, 27, 84, 5, 0, 66, 21, 14]
[87, 62, 72, 32, 30, 20, 15, 17]
[86, 29, 85, 16, 14, 47, 62, 13]
[65, 41, 85, 6, 77, 13, 47, 25]
[73, 41, 67, 66, 0, 11, 47, 74]
[28, 81, 56, 87, 25, 49, 33, 46]
[88, 66, 44, 44, 85, 31, 97, 52]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Обработка матрицы завершена. Время выполнения: 10 мс
Сервис 2
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Получена часть матрицы для сортировки:
[87, 62, 72, 32, 30, 20, 15, 17]
[88, 66, 44, 44, 85, 31, 97, 52]
[36, 13, 16, 24, 42, 8, 68, 64]
[86, 29, 85, 16, 14, 47, 62, 13]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Сортировка части матрицы завершена:
[36, 13, 16, 24, 42, 8, 68, 64]
[87, 62, 72, 32, 30, 20, 15, 17]
[86, 29, 85, 16, 14, 47, 62, 13]
[88, 66, 44, 44, 85, 31, 97, 52]
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Отправка отсортированной части матрицы в MatrixMasterService...
2025-03-22 08:02:23 INFO c.e.m.MatrixController - Время выполнения сортировки: 1 мс
Выводы
-
Удалось успешно разделить приложение на два сервиса, которые взаимодействуют через REST API.
-
Алгоритм генерации и сортировки матриц работает корректно (что видно по тестам).
-
Логирование помогло легко отследить выполнение операций и найти ошибки (особенно на ранних этапах работы).
-
Если говорить об эффективности данного метода разработки приложений (Spring Boot), то всплывают все те же минусы (как и у MPI) в виде накладных расходов на создание узлов и коммуникацию между ними.
-
Распределенная межкластерная система это довольно эффективный способ решения задач, которые можно разделить на независимые части. Однако такие системы требуют тщательной настройки и тестирования.