This commit is contained in:
2025-03-04 22:04:34 +04:00
commit 2c6bed7589
15 changed files with 524 additions and 0 deletions

59
main/pom.xml Normal file
View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>matrix-main-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>matrix-main-service</name>
<description>Main service for distributed matrix minimum search</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

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

View File

@@ -0,0 +1,28 @@
package com.example.matrix.client;
import com.example.matrix.model.Matrix;
import com.example.matrix.model.MinResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Service
public class WorkerServiceClient {
private final WebClient webClient;
public WorkerServiceClient(@Value("${worker.service.url}") String workerServiceUrl) {
this.webClient = WebClient.builder()
.baseUrl(workerServiceUrl)
.build();
}
public Mono<MinResult> findMinimum(Matrix matrix) {
return webClient.post()
.uri("/matrix/min")
.bodyValue(matrix)
.retrieve()
.bodyToMono(MinResult.class);
}
}

View File

@@ -0,0 +1,66 @@
package com.example.matrix.controller;
import com.example.matrix.model.Matrix;
import com.example.matrix.model.MinResult;
import com.example.matrix.service.MatrixService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.ExecutionException;
@RestController
@RequestMapping("/matrix")
@RequiredArgsConstructor
public class MatrixController {
private final MatrixService matrixService;
@PostMapping("/generate")
public Matrix generateMatrix(@RequestParam int rows, @RequestParam int cols) {
return matrixService.generateMatrix(rows, cols);
}
@PostMapping("/min/sequential")
public MinResult findMinimumSequential(@RequestBody Matrix matrix) {
return matrixService.findMinimumSequential(matrix);
}
@PostMapping("/min/parallel")
public MinResult findMinimumParallel(@RequestBody Matrix matrix) throws ExecutionException, InterruptedException {
return matrixService.findMinimumParallel(matrix);
}
// Простой эндпоинт для замера времени выполнения
@PostMapping("/benchmark")
public String benchmark(@RequestParam int rows, @RequestParam int cols, @RequestParam int iterations) throws ExecutionException, InterruptedException {
Matrix matrix = matrixService.generateMatrix(rows, cols);
long totalSequentialTime = 0;
long totalParallelTime = 0;
for (int i = 0; i < iterations; i++) {
MinResult sequentialResult = matrixService.findMinimumSequential(matrix);
MinResult parallelResult = matrixService.findMinimumParallel(matrix);
totalSequentialTime += sequentialResult.getProcessingTimeMs();
totalParallelTime += parallelResult.getProcessingTimeMs();
// Проверка корректности результатов
if (sequentialResult.getMinValue() != parallelResult.getMinValue()) {
return "Error: different minimum values found. Sequential: " +
sequentialResult.getMinValue() + ", Parallel: " + parallelResult.getMinValue();
}
}
double avgSequentialTime = (double) totalSequentialTime / iterations;
double avgParallelTime = (double) totalParallelTime / iterations;
double speedup = avgSequentialTime / avgParallelTime;
return String.format("Benchmark results (average over %d iterations):\n" +
"Matrix size: %dx%d\n" +
"Sequential execution time: %.2f ms\n" +
"Parallel execution time: %.2f ms\n" +
"Speedup: %.2fx",
iterations, rows, cols, avgSequentialTime, avgParallelTime, speedup);
}
}

View File

@@ -0,0 +1,45 @@
package com.example.matrix.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Matrix {
private int[][] data;
private int rows;
private int cols;
public Matrix(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.data = new int[rows][cols];
}
// Метод для заполнения матрицы случайными значениями
public void fillRandom(int min, int max) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
data[i][j] = min + (int) (Math.random() * (max - min + 1));
}
}
}
// Получение подматрицы (части матрицы)
public Matrix getSubMatrix(int startRow, int endRow) {
if (startRow < 0 || endRow > rows || startRow >= endRow) {
throw new IllegalArgumentException("Invalid row range");
}
int subRows = endRow - startRow;
Matrix subMatrix = new Matrix(subRows, cols);
for (int i = 0; i < subRows; i++) {
System.arraycopy(data[startRow + i], 0, subMatrix.data[i], 0, cols);
}
return subMatrix;
}
}

View File

@@ -0,0 +1,22 @@
package com.example.matrix.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MinResult {
private int minValue;
private int row;
private int col;
private long processingTimeMs;
public MinResult(int minValue) {
this.minValue = minValue;
this.row = -1;
this.col = -1;
this.processingTimeMs = 0;
}
}

View File

@@ -0,0 +1,104 @@
package com.example.matrix.service;
import com.example.matrix.client.WorkerServiceClient;
import com.example.matrix.model.Matrix;
import com.example.matrix.model.MinResult;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Service
@RequiredArgsConstructor
public class MatrixService {
private final WorkerServiceClient workerServiceClient;
// Метод для генерации матрицы заданного размера
public Matrix generateMatrix(int rows, int cols) {
Matrix matrix = new Matrix(rows, cols);
matrix.fillRandom(-100, 100); // Заполняем случайными значениями от -100 до 100
return matrix;
}
// Поиск минимального элемента в матрице (последовательный алгоритм для сравнения)
public MinResult findMinimumSequential(Matrix matrix) {
long startTime = System.currentTimeMillis();
int minValue = Integer.MAX_VALUE;
int minRow = -1;
int minCol = -1;
for (int i = 0; i < matrix.getRows(); i++) {
for (int j = 0; j < matrix.getCols(); j++) {
if (matrix.getData()[i][j] < minValue) {
minValue = matrix.getData()[i][j];
minRow = i;
minCol = j;
}
}
}
long processingTime = System.currentTimeMillis() - startTime;
return new MinResult(minValue, minRow, minCol, processingTime);
}
// Параллельный поиск минимума с использованием двух сервисов
public MinResult findMinimumParallel(Matrix matrix) throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
// Разделяем матрицу на две части
int halfRows = matrix.getRows() / 2;
Matrix firstHalf = matrix.getSubMatrix(0, halfRows);
Matrix secondHalf = matrix.getSubMatrix(halfRows, matrix.getRows());
// Находим минимум в первой половине локально
CompletableFuture<MinResult> localFuture = CompletableFuture.supplyAsync(() -> {
int minValue = Integer.MAX_VALUE;
int minRow = -1;
int minCol = -1;
for (int i = 0; i < firstHalf.getRows(); i++) {
for (int j = 0; j < firstHalf.getCols(); j++) {
if (firstHalf.getData()[i][j] < minValue) {
minValue = firstHalf.getData()[i][j];
minRow = i;
minCol = j;
}
}
}
return new MinResult(minValue, minRow, minCol, 0);
});
// Находим минимум во второй половине через Worker Service
CompletableFuture<MinResult> remoteFuture = workerServiceClient.findMinimum(secondHalf)
.map(result -> {
// Корректируем индекс строки (добавляем смещение)
if (result.getRow() >= 0) {
result.setRow(result.getRow() + halfRows);
}
return result;
})
.toFuture();
// Ждем завершения обоих вычислений и выбираем минимальный результат
CompletableFuture<MinResult> combinedFuture = localFuture.thenCombine(remoteFuture, (local, remote) -> {
if (local.getMinValue() <= remote.getMinValue()) {
return local;
} else {
return remote;
}
});
MinResult result = combinedFuture.get();
long processingTime = System.currentTimeMillis() - startTime;
result.setProcessingTimeMs(processingTime);
return result;
}
}

View File

@@ -0,0 +1,2 @@
server.port=8080
worker.service.url=http://worker-vm:8081

55
worker/pom.xml Normal file
View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>matrix-worker-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>matrix-worker-service</name>
<description>Worker service for distributed matrix minimum search</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

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

View File

@@ -0,0 +1,23 @@
package com.example.matrix.controller;
import com.example.matrix.model.Matrix;
import com.example.matrix.model.MinResult;
import com.example.matrix.service.WorkerService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/matrix")
@RequiredArgsConstructor
public class WorkerController {
private final WorkerService workerService;
@PostMapping("/min")
public MinResult findMinimum(@RequestBody Matrix matrix) {
return workerService.findMinimum(matrix);
}
}

View File

@@ -0,0 +1,45 @@
package com.example.matrix.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Matrix {
private int[][] data;
private int rows;
private int cols;
public Matrix(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.data = new int[rows][cols];
}
// Метод для заполнения матрицы случайными значениями
public void fillRandom(int min, int max) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
data[i][j] = min + (int) (Math.random() * (max - min + 1));
}
}
}
// Получение подматрицы (части матрицы)
public Matrix getSubMatrix(int startRow, int endRow) {
if (startRow < 0 || endRow > rows || startRow >= endRow) {
throw new IllegalArgumentException("Invalid row range");
}
int subRows = endRow - startRow;
Matrix subMatrix = new Matrix(subRows, cols);
for (int i = 0; i < subRows; i++) {
System.arraycopy(data[startRow + i], 0, subMatrix.data[i], 0, cols);
}
return subMatrix;
}
}

View File

@@ -0,0 +1,22 @@
package com.example.matrix.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MinResult {
private int minValue;
private int row;
private int col;
private long processingTimeMs;
public MinResult(int minValue) {
this.minValue = minValue;
this.row = -1;
this.col = -1;
this.processingTimeMs = 0;
}
}

View File

@@ -0,0 +1,30 @@
package com.example.matrix.service;
import com.example.matrix.model.Matrix;
import com.example.matrix.model.MinResult;
import org.springframework.stereotype.Service;
@Service
public class WorkerService {
public MinResult findMinimum(Matrix matrix) {
long startTime = System.currentTimeMillis();
int minValue = Integer.MAX_VALUE;
int minRow = -1;
int minCol = -1;
for (int i = 0; i < matrix.getRows(); i++) {
for (int j = 0; j < matrix.getCols(); j++) {
if (matrix.getData()[i][j] < minValue) {
minValue = matrix.getData()[i][j];
minRow = i;
minCol = j;
}
}
}
long processingTime = System.currentTimeMillis() - startTime;
return new MinResult(minValue, minRow, minCol, processingTime);
}
}

View File

@@ -0,0 +1 @@
server.port=8081