Files
SSPR_25/lyakhov_timofey_lab_3
2025-03-24 10:45:49 +04:00
..
2025-03-02 17:30:36 +04:00
2025-03-02 17:30:36 +04:00
2025-03-24 10:45:49 +04:00

Отчет по лабораторной работе

Описание программы

Этот проект состоит из двух микросервисов, которые выполняют асинхронные вычисления для матриц. Каждый сервис обрабатывает строку матрицы, выполняя умножение всех элементов строки или их сумму в зависимости от сервиса. Для работы используются технологии Spring Boot и асинхронные вычисления с использованием CompletableFuture.

Как запустить программу

  1. Клонируйте репозиторий:

    git clone https://github.com/ваш-репозиторий.git
    
  2. Перейдите в каталог каждого проекта:

    cd client1
    
  3. Соберите проекты: Для обоих проектов выполните команду:

    mvn package
    
  4. Построение Docker-образов:

    • Для проекта client1:
      docker build -t client1 -f .dockerfile .
      
    • Для проекта client2:
      docker build -t client2 -f .dockerfile .
      
  5. Переместите образы в контейнеры: Docker образы должны быть запущены на разных узлах:

    • Образ client1 должен быть запущен на узле с IP 192.168.9.*, кроме 192.168.9.11 и 192.168.9.12.
    • Образ client2 должен быть запущен на узлах с IP 192.168.9.11 и 192.168.9.12.
  6. Узлы должны быть настроены так, чтобы они могли обмениваться данными друг с другом.

Используемые технологии

  • Язык программирования: Java 21
  • Фреймворк: Spring Boot
  • Асинхронное программирование: CompletableFuture
  • Для взаимодействия между сервисами используется Feign Client
  • Для контейнеризации используется Docker

Client 1 описание кода


@FeignClient(name ="Client2", url = "http://192.168.9.11:8080") 
public interface Client2F {
    // Feign клиент чтобы не строить запросы ручками
    @PostMapping("/async")
    long getAsync(@RequestBody int[][] matrix);
}

--------

@Service
@Slf4j
@RequiredArgsConstructor
public class ServiceTask { // Класс распределения

    private final Client2F feignClient1; // Объекты заинжектятся через конструктор 
    private final Client3F feignClient2;

    @Async // Объект таски
    public CompletableFuture<Long> calculateProductAsync(int[] row, int i) {
        try {
            // Обращение к сервисам
            if (i % 2 == 0) {
                return CompletableFuture.completedFuture(feignClient1.getAsync(new int[][]{row}));
            } else {
                return CompletableFuture.completedFuture(feignClient2.getAsync(new int[][]{row}));
            }
        }
        catch (Exception ex){
            log.info(ex.getMessage());
            System.exit(0);
        }
        return CompletableFuture.completedFuture(0L);
    }

    @Async // Результирующий объект
    public CompletableFuture<Long> calculateSumOfRowWithAsync(int[][] matrix) throws ExecutionException, InterruptedException {
        long sum = 0;
        int f = 0;
        // Распределение по строкам
        List<CompletableFuture<Long>> futures = new ArrayList<>();
        for (int[] row : matrix) {
            f = (f + 1) % 2;
            futures.add(calculateProductAsync(row, f));
        }
        
        for (CompletableFuture<Long> future : futures) {
            try {
                sum += future.get();
            } catch (ExecutionException | InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
        return CompletableFuture.completedFuture(sum);
    }
}

Client 2 описание кожа

    private final ServiceTask serviceTask;

    @PostMapping("/async") // Контроллер принятия данных
    public long getAsync(@RequestBody int[][] map) throws ExecutionException, InterruptedException, JsonProcessingException {
        System.out.println("Матрица размером " + map.length);
        var res = serviceTask.calculateSumOfRowWithAsync(map);
        log.info(Thread.currentThread().getName() + " Результат: " + res.get());
        return res.get();
    }


    -----

 
public class ServiceTask {


    @Async
    public CompletableFuture<Integer> calculateProductAsync(int[] row) { // Вычисление
        int product = 1;
        for (int value : row) {
            product *= value;
        }
        return CompletableFuture.completedFuture(product);
    }

    @Async // Распределение вычислений
    public CompletableFuture <Integer> calculateSumOfRowWithAsync(int[][] matrix) throws ExecutionException, InterruptedException {
        int sum = 0;
        List<CompletableFuture<Integer>> futures = new ArrayList<>();
        for (int[] row : matrix) {
            futures.add(calculateProductAsync(row));
        }

        for (CompletableFuture<Integer> future : futures) {
            try {
                sum += future.get();
            } catch (ExecutionException | InterruptedException e) {
                System.out.println(e.getMessage());
            }
        }
        return CompletableFuture.completedFuture(sum);
    }
}

Описание работы программы

В проекте два сервиса с асинхронной обработкой данных:

  1. ServiceTask: Этот класс предоставляет два метода для асинхронных вычислений:

    • calculateProductAsync: вычисляет произведение всех элементов в строке матрицы.
    • calculateSumOfRowWithAsync: асинхронно вычисляет сумму произведений всех строк матрицы.
  2. В проекте client2 используется дополнительный класс Client2F, который через Feign Client взаимодействует с другим сервисом и вызывает вычисления в нем, в зависимости от номера строки.

Структура кода:

  • ServiceTask:

    • Основной класс, отвечающий за вычисления с матрицами.
    • Использует @Async для выполнения вычислений асинхронно.
    • Метод calculateProductAsync выполняет умножение для каждой строки матрицы.
    • Метод calculateSumOfRowWithAsync собирает все асинхронные вычисления и возвращает суммарный результат.
  • Client2F:

    • Feign Client, который асинхронно взаимодействует с другим сервисом для выполнения вычислений.

Примеры тестов

Вывод

  • Client1

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)

2025-03-02T13:48:37.474Z  INFO 1 --- [           main] org.urlshort.App                         : Starting App v1.0-SNAPSHOT using Java 21 with PID 1 (/app.jar started by root in /)
2025-03-02T13:48:37.499Z  INFO 1 --- [           main] org.urlshort.App                         : No active profile set, falling back to 1 default profile: "default"
2025-03-02T13:48:38.887Z  INFO 1 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=ceae2d3b-8dc4-30da-9da6-f9b9bc608a4c
2025-03-02T13:48:39.282Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-03-02T13:48:39.308Z  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-03-02T13:48:39.308Z  INFO 1 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.26]
2025-03-02T13:48:39.365Z  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-03-02T13:48:39.367Z  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1631 ms
2025-03-02T13:48:40.048Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-03-02T13:48:40.087Z  INFO 1 --- [           main] org.urlshort.App                         : Started App in 3.622 seconds (process running for 7.345)
Введите размер матрицы (от 2 до 1000): 10
2025-03-02T13:48:54.348Z  INFO 1 --- [           main] org.urlshort.TaskRun                     : Матрица создана  ----------------------------------------
2025-03-02T13:48:54.847Z  INFO 1 --- [           main] org.urlshort.TaskRun                     : Вычисления выполнены за: 497800181
  • Client2.1 (для client2.2 вывод аналогичен)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.2)

2025-03-02T13:44:44.725Z  INFO 1 --- [           main] org.urlshort.App                         : Starting App v1.0-SNAPSHOT using Java 21 with PID 1 (/app.jar started by root in /)
2025-03-02T13:44:44.732Z  INFO 1 --- [           main] org.urlshort.App                         : No active profile set, falling back to 1 default profile: "default"
2025-03-02T13:44:46.111Z  INFO 1 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=cbd0db31-b26c-3fb9-8542-dcebb5489091
2025-03-02T13:44:46.626Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2025-03-02T13:44:46.669Z  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2025-03-02T13:44:46.670Z  INFO 1 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.26]
2025-03-02T13:44:46.736Z  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2025-03-02T13:44:46.737Z  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1840 ms
2025-03-02T13:44:47.288Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2025-03-02T13:44:47.320Z  INFO 1 --- [           main] org.urlshort.App                         : Started App in 3.431 seconds (process running for 4.727)
2025-03-02T13:48:54.627Z  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-03-02T13:48:54.627Z  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2025-03-02T13:48:54.629Z  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
Матрица размером 1
2025-03-02T13:48:54.694Z  INFO 1 --- [nio-8080-exec-1] org.urlshort.Cont                        : http-nio-8080-exec-1 Результат: 1214715904
Матрица размером 1
2025-03-02T13:48:54.733Z  INFO 1 --- [nio-8080-exec-2] org.urlshort.Cont                        : http-nio-8080-exec-2 Результат: -134498304
Матрица размером 1
2025-03-02T13:48:54.755Z  INFO 1 --- [nio-8080-exec-4] org.urlshort.Cont                        : http-nio-8080-exec-4 Результат: 0
Матрица размером 1
2025-03-02T13:48:54.793Z  INFO 1 --- [nio-8080-exec-5] org.urlshort.Cont                        : http-nio-8080-exec-5 Результат: 0
Матрица размером 1
2025-03-02T13:48:54.838Z  INFO 1 --- [nio-8080-exec-6] org.urlshort.Cont                        : http-nio-8080-exec-6 Результат: 0

Выводы по лабораторной работе

В данной лабораторной работе были реализованы два асинхронных сервиса . Основным инструментом для асинхронных вычислений стал CompletableFuture. Также был использован Feign Client для взаимодействия между сервисами.

Довольно интересно поднимать rest api, но есть ощущение что выполнять математические праспределения с помощью spring не слишком нужно

Больше подходит для распределение бизнес логики