khaliullov_ramil_lab_3 is ready

This commit is contained in:
rakhaliullov
2025-03-24 23:20:04 +04:00
parent fbcc1bcf57
commit bd6cdf7070
10 changed files with 520 additions and 0 deletions

View File

@@ -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

View File

@@ -0,0 +1,11 @@
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,14 @@
package org.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,184 @@
package org.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.text.DecimalFormat;
import java.util.Random;
@RestController
@RequestMapping("/master")
public class MasterController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private ApplicationContext context;
private static final String WORKER2_URL = "http://192.168.28.104:8080/worker/divide";
private static final String WORKER1_URL = "http://192.168.28.106:8080/worker/divide";
// Максимальное количество элементов для логирования
private static final int MAX_LOG_ELEMENTS = 8;
@GetMapping("/generate-matrix")
public ResponseEntity<double[][]> generateAndSendMatrix() {
int[][] matrix = generateMatrix(); // Генерация целочисленной матрицы
double[][] matrixDouble = convertToDoubleMatrix(matrix); // Преобразуем в double для вывода
int size = 8; // хотел добавить пользовательский размер для вывода матрицы (но пофиг)
logMatrixPreview(matrixDouble, "Generated matrix"); // Логируем в формате double
int mid = matrix[0].length / 2; // Половина количества столбцов
int[][] matrixPart1 = copyColumns(matrix, 0, mid);
int[][] matrixPart2 = copyColumns(matrix, mid, matrix[0].length);
long startTime = System.currentTimeMillis();
ResponseEntity<double[][]> response1 = restTemplate.postForEntity(WORKER1_URL, convertToDoubleMatrix(matrixPart1), double[][].class);
ResponseEntity<double[][]> response2 = restTemplate.postForEntity(WORKER2_URL, convertToDoubleMatrix(matrixPart2), double[][].class);
if (response1.getStatusCode().is2xxSuccessful() && response2.getStatusCode().is2xxSuccessful()) {
double[][] sortedMatrix1 = response1.getBody();
double[][] sortedMatrix2 = response2.getBody();
double[][] mergedMatrix = mergeSortedMatrices(sortedMatrix1, sortedMatrix2);
logMatrixPreview(mergedMatrix, "Final Sorted Matrix");
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
System.out.println("Total sorting time: " + elapsedTime + " ms");
// Извлекаем нужную часть матрицы для клиента
double[][] subMatrix = extractSubMatrix(mergedMatrix, size);
// Возвращаем её клиенту
return ResponseEntity.ok(subMatrix);
}
return ResponseEntity.status(500).body(null);
}
// Метод для получения части матрицы
private double[][] extractSubMatrix(double[][] matrix, int size) {
int rows = Math.min(size, matrix.length);
int cols = Math.min(size, matrix[0].length);
double[][] subMatrix = new double[rows][cols];
for (int i = 0; i < rows; i++) {
System.arraycopy(matrix[i], 0, subMatrix[i], 0, cols);
}
return subMatrix;
}
private int[][] copyColumns(int[][] matrix, int startCol, int endCol) {
int[][] subMatrix = new int[matrix.length][endCol - startCol];
for (int i = 0; i < matrix.length; i++) {
System.arraycopy(matrix[i], startCol, subMatrix[i], 0, endCol - startCol);
}
return subMatrix;
}
// Метод для логирования части матрицы с ограничением по числу элементов
private void logMatrixPreview(double[][] matrix, String message) {
StringBuilder preview = new StringBuilder(message + ": \n");
int elementCount = 0;
DecimalFormat df = new DecimalFormat("#.##"); // Форматируем до 2 знаков после запятой
outerLoop:
for (int i = 0; i < Math.min(8, matrix.length); i++) { // Логируем только 8 строк
preview.append("[");
for (int j = 0; j < Math.min(8, matrix[i].length); j++) { // Логируем только 8 столбцов
preview.append(df.format(matrix[i][j])).append(j < Math.min(8, matrix[i].length) - 1 ? ", " : "");
elementCount++;
if (elementCount >= 64) { // 8x8 = 64 элемента
break outerLoop;
}
}
preview.append("]");
if (elementCount < 64) {
preview.append("\n");
}
}
System.out.println(preview.toString()); // Можно использовать логирование через SLF4J, если нужно
}
private double[][] mergeSortedMatrices(double[][] sortedMatrix1, double[][] sortedMatrix2) {
int rows = sortedMatrix1.length;
int cols = sortedMatrix1[0].length + sortedMatrix2[0].length;
double[][] mergedMatrix = new double[rows][cols];
// Слияние по строкам
for (int i = 0; i < rows; i++) {
double[] mergedRow = new double[cols];
int index1 = 0, index2 = 0, mergedIndex = 0;
while (index1 < sortedMatrix1[i].length && index2 < sortedMatrix2[i].length) {
if (sortedMatrix1[i][index1] < sortedMatrix2[i][index2]) {
mergedRow[mergedIndex++] = sortedMatrix1[i][index1++];
} else {
mergedRow[mergedIndex++] = sortedMatrix2[i][index2++];
}
}
// Добавляем оставшиеся элементы из первой части
while (index1 < sortedMatrix1[i].length) {
mergedRow[mergedIndex++] = sortedMatrix1[i][index1++];
}
// Добавляем оставшиеся элементы из второй части
while (index2 < sortedMatrix2[i].length) {
mergedRow[mergedIndex++] = sortedMatrix2[i][index2++];
}
mergedMatrix[i] = mergedRow;
}
// Применяем форматирование для чисел в матрице
DecimalFormat df = new DecimalFormat("#.##"); // Форматируем до 2 знаков после запятой
for (int i = 0; i < mergedMatrix.length; i++) {
for (int j = 0; j < mergedMatrix[i].length; j++) {
mergedMatrix[i][j] = Double.parseDouble(df.format(mergedMatrix[i][j])); // Округляем значение
}
}
return mergedMatrix;
}
private int[][] generateMatrix() {
int rows = 1000;
int cols = 1000;
int[][] matrix = new int[rows][cols];
Random rand = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = rand.nextInt(100); // Случайные числа от 0 до 99
}
}
return matrix;
}
// Метод для преобразования целочисленной матрицы в double[][] для вывода
private double[][] convertToDoubleMatrix(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
double[][] doubleMatrix = new double[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
doubleMatrix[i][j] = matrix[i][j]; // Преобразуем каждый элемент в double
}
}
return doubleMatrix;
}
}

View File

@@ -0,0 +1,2 @@
server.port=8081
spring.codec.max-in-memory-size=10MB

View File

@@ -0,0 +1,123 @@
## Лабораторная работа №3
### Разработка распределенного приложения с использованием фреймворка Spring Boot
#### Описание
Разработано параллельное распределенное приложение. Приложение использует сервис-ориентированную архитектуру и запускается в LXC-контейнерах.
### Вариант
1 Разделить элементы матрицы на наибольший элемент.
#### Архитектура
- **Сервис-управленец (Master)**
- Генерирует матрицу по GET-запросу.
- Делит элементы матрицы на максимальный элемент.
- Отправляет части матрицы двум сервисам-работникам.
- Получает нормализованные части от работников и объединяет их.
- Возвращает результат пользователю в формате JSON.
- **Сервис-работник (Worker)**
- Получает часть матрицы.
- Делит элементы матрицы на максимальный элемент.
- Возвращает нормализованную матрицу.
Сервисы работают на трех контейнерах: в одном запущен мастер, во втором и третьем - работник.
### Какие технологии использовали:
- **Spring Boot** — для создания REST API сервиса.
- **RestTemplate** — для отправки HTTP-запросов между сервисами.
- **CompletableFuture** — асинхронное программирование.
#### Запуск приложения
1. **Сборка jar-файлов**
```bash
mvn clean package
```
Полученные файлы:
- `master-service-1.0.jar`
- `worker-service-1.0.jar`
2. **Запуск сервисов**
```bash
java -jar master-service-1.0.jar
java -jar worker-service-1.0.jar
```
3. **Запрос к мастеру**
```bash
curl http://192.168.28.105:8081/master/generate-matrix
```
#### Выходные данные
Вывод master-service:
```powershell
Generated matrix:
[18, 12, 99, 62, 8, 72, 9, 97]
[71, 16, 73, 61, 92, 51, 1, 2]
[74, 84, 44, 70, 35, 66, 99, 15]
[71, 78, 14, 73, 71, 20, 27, 17]
[53, 76, 43, 9, 31, 77, 79, 48]
[64, 83, 83, 37, 51, 94, 87, 50]
[59, 57, 39, 37, 0, 87, 92, 23]
[25, 73, 39, 33, 15, 98, 0, 67
Final Sorted Matrix:
[0.18, 0.12, 0.45, 0.55, 0.8, 0.61, 0.23, 0.08]
[0.27, 0.16, 0.72, 0.16, 0.74, 0.62, 0.93, 0.52]
[0.31, 0.75, 0.85, 0.44, 0.71, 0.35, 0.67, 0.95]
[0.38, 0.45, 0.02, 0.04, 0.72, 0.79, 0.14, 0.74]
[0.24, 0.06, 0.47, 0.54, 0.77, 0.43, 0.09, 0.31]
[0.65, 0.84, 0.84, 0.37, 0.52, 0.91, 0.91, 0.95]
[0.19, 0.29, 0.49, 0.18, 0.38, 0.6, 0.58, 0.39]
[0.25, 0.74, 0.39, 0.33, 0.15, 0.9, 0.07, 0.76
Total sorting time: 6326 ms
```
Вывод worker-service(1):
```powershell
2025-03-24T08:22:40.109Z INFO 291 --- [nio-8080-exec-1] org.example.WorkerController : Received request to divide matrix elements by max value
2025-03-24T08:22:40.120Z INFO 291 --- [nio-8080-exec-1] org.example.WorkerController : Received matrix:
[18.00, 12.00, 99.00, 62.00, 8.00, 72.00, 9.00, 97.00]
[71.00, 16.00, 73.00, 61.00, 92.00, 51.00, 1.00, 2.00]
[74.00, 84.00, 44.00, 70.00, 35.00, 66.00, 99.00, 15.00]
[71.00, 78.00, 14.00, 73.00, 71.00, 20.00, 27.00, 17.00]
[53.00, 76.00, 43.00, 9.00, 31.00, 77.00, 79.00, 48.00]
[64.00, 83.00, 83.00, 37.00, 51.00, 94.00, 87.00, 50.00]
[59.00, 57.00, 39.00, 37.00, 0.00, 87.00, 92.00, 23.00]
[25.00, 73.00, 39.00, 33.00, 15.00, 98.00, 0.00, 67.00
2025-03-24T08:22:40.142Z INFO 291 --- [nio-8080-exec-1] org.example.WorkerController : Maximum element in matrix: 99.0
2025-03-24T08:22:40.174Z INFO 291 --- [nio-8080-exec-1] org.example.WorkerController : Matrix after dividing by max element:
[0.18, 0.12, 1.00, 0.63, 0.08, 0.73, 0.09, 0.98]
[0.72, 0.16, 0.74, 0.62, 0.93, 0.52, 0.01, 0.02]
[0.75, 0.85, 0.44, 0.71, 0.35, 0.67, 1.00, 0.15]
[0.72, 0.79, 0.14, 0.74, 0.72, 0.20, 0.27, 0.17]
[0.54, 0.77, 0.43, 0.09, 0.31, 0.78, 0.80, 0.48]
[0.65, 0.84, 0.84, 0.37, 0.52, 0.95, 0.88, 0.51]
[0.60, 0.58, 0.39, 0.37, 0.00, 0.88, 0.93, 0.23]
[0.25, 0.74, 0.39, 0.33, 0.15, 0.99, 0.00, 0.68
```
Вывод worker-service(2):
```powershell
:22:42.371Z INFO 336 --- [nio-8080-exec-1] org.example.WorkerController : Received request to divide matrix elements by max value
2025-03-24T08:22:42.384Z INFO 336 --- [nio-8080-exec-1] org.example.WorkerController : Received matrix:
[45.00, 54.00, 79.00, 60.00, 23.00, 8.00, 99.00, 93.00]
[27.00, 16.00, 95.00, 70.00, 25.00, 52.00, 29.00, 0.00]
[31.00, 94.00, 66.00, 32.00, 83.00, 66.00, 5.00, 26.00]
[38.00, 45.00, 2.00, 4.00, 86.00, 82.00, 66.00, 71.00]
[24.00, 6.00, 47.00, 94.00, 25.00, 87.00, 33.00, 99.00]
[90.00, 90.00, 95.00, 14.00, 58.00, 44.00, 56.00, 75.00]
[19.00, 29.00, 49.00, 18.00, 38.00, 91.00, 88.00, 41.00]
[89.00, 7.00, 75.00, 29.00, 23.00, 61.00, 37.00, 44.00
2025-03-24T08:22:42.402Z INFO 336 --- [nio-8080-exec-1] org.example.WorkerController : Maximum element in matrix: 99.0
2025-03-24T08:22:42.437Z INFO 336 --- [nio-8080-exec-1] org.example.WorkerController : Matrix after dividing by max element:
[0.45, 0.55, 0.80, 0.61, 0.23, 0.08, 1.00, 0.94]
[0.27, 0.16, 0.96, 0.71, 0.25, 0.53, 0.29, 0.00]
[0.31, 0.95, 0.67, 0.32, 0.84, 0.67, 0.05, 0.26]
[0.38, 0.45, 0.02, 0.04, 0.87, 0.83, 0.67, 0.72]
[0.24, 0.06, 0.47, 0.95, 0.25, 0.88, 0.33, 1.00]
[0.91, 0.91, 0.96, 0.14, 0.59, 0.44, 0.57, 0.76]
[0.19, 0.29, 0.49, 0.18, 0.38, 0.92, 0.89, 0.41]
[0.90, 0.07, 0.76, 0.29, 0.23, 0.62, 0.37, 0.44
```
### Вывод
В ходе выполнения лабораторной работы я разработал распределенное параллельное приложение на Spring Boot, использующее сервис-ориентированную архитектуру. Приложение успешно запускается в LXC-контейнерах, где мастер-сервис генерирует матрицу, делит её на части и отправляет на обработку работникам, которые выполняют вычисления и возвращают результат. В результате удалось реализовать эффективное распределение нагрузки, однако возможны дальнейшие оптимизации в части асинхронности запросов и объединения данных.

View File

@@ -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

View File

@@ -0,0 +1,11 @@
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,97 @@
package org.example;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.ResponseEntity;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController
public class WorkerController {
private static final Logger logger = LoggerFactory.getLogger(WorkerController.class);
// Максимальное количество элементов, которые мы хотим выводить в логах
private static final int MAX_LOG_ELEMENTS = 64; // 8x8 = 64 элемента
// Endpoint для разделения элементов матрицы на максимальный элемент
@PostMapping("/worker/divide")
public ResponseEntity<double[][]> divideMatrixByMax(@RequestBody double[][] matrix) {
// Логируем получение запроса от клиента
logger.info("Received request to divide matrix elements by max value");
// Логируем часть матрицы с ограничением по числу элементов
logMatrixPreview(matrix, "Received matrix");
// Находим максимальный элемент в матрице
double maxElement = findMaxElement(matrix);
logger.info("Maximum element in matrix: " + maxElement);
// Разделяем все элементы матрицы на максимальное значение
double[][] dividedMatrix = divideMatrixByMax(matrix, maxElement);
// Логируем обработанную матрицу
logMatrixPreview(dividedMatrix, "Matrix after dividing by max element");
// Возвращаем обработанную часть матрицы с HTTP-статусом 200 (OK)
return ResponseEntity.ok(dividedMatrix);
}
// Метод для нахождения максимального элемента в матрице
private static double findMaxElement(double[][] matrix) {
double max = Double.MIN_VALUE;
for (double[] row : matrix) {
for (double element : row) {
if (element > max) {
max = element;
}
}
}
return max;
}
// Метод для деления всех элементов матрицы на максимальный элемент
private static double[][] divideMatrixByMax(double[][] matrix, double maxElement) {
int rows = matrix.length;
int cols = matrix[0].length;
double[][] dividedMatrix = new double[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
dividedMatrix[i][j] = matrix[i][j] / maxElement;
}
}
return dividedMatrix;
}
// Метод для логирования части матрицы с ограничением по числу элементов
private void logMatrixPreview(double[][] matrix, String message) {
StringBuilder preview = new StringBuilder(message + ": \n");
int elementCount = 0;
outerLoop:
for (int i = 0; i < Math.min(8, matrix.length); i++) { // Логируем только 8 строк
preview.append("[");
for (int j = 0; j < Math.min(8, matrix[i].length); j++) { // Логируем только 8 столбцов
preview.append(String.format("%.2f", matrix[i][j])).append(j < Math.min(8, matrix[i].length) - 1 ? ", " : "");
elementCount++;
if (elementCount >= MAX_LOG_ELEMENTS) { // 8x8 = 64 элемента
break outerLoop;
}
}
preview.append("]");
if (elementCount < MAX_LOG_ELEMENTS) {
preview.append("\n");
}
}
logger.info(preview.toString());
}
}

View File

@@ -0,0 +1,2 @@
server.port=8080
spring.codec.max-in-memory-size=10MB