diff --git a/pyzhov_egor_lab_4/.gitignore b/pyzhov_egor_lab_4/.gitignore new file mode 100644 index 0000000..d048d4b --- /dev/null +++ b/pyzhov_egor_lab_4/.gitignore @@ -0,0 +1,40 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +!conf.xml +!myConf.xml +!pom.xml +### 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 \ No newline at end of file diff --git a/pyzhov_egor_lab_4/conf.xml b/pyzhov_egor_lab_4/conf.xml new file mode 100644 index 0000000..8cd816d --- /dev/null +++ b/pyzhov_egor_lab_4/conf.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyzhov_egor_lab_4/myConf.xml b/pyzhov_egor_lab_4/myConf.xml new file mode 100644 index 0000000..8273f6f --- /dev/null +++ b/pyzhov_egor_lab_4/myConf.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + 192.168.17.117:47500 + 192.168.17.118:47500 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pyzhov_egor_lab_4/pom.xml b/pyzhov_egor_lab_4/pom.xml new file mode 100644 index 0000000..8d3acda --- /dev/null +++ b/pyzhov_egor_lab_4/pom.xml @@ -0,0 +1,50 @@ + + 4.0.0 + + org.urlshort + sspr4 + 1.0-SNAPSHOT + jar + + lab4 + http://maven.apache.org + + + UTF-8 + + + + + org.apache.ignite + ignite-core + 2.17.0 + + + org.apache.ignite + ignite-indexing + 2.17.0 + + + org.apache.ignite + ignite-spring + 2.17.0 + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.7.18 + + + + repackage + + + + + + + diff --git a/pyzhov_egor_lab_4/readme.md b/pyzhov_egor_lab_4/readme.md new file mode 100644 index 0000000..fa68117 --- /dev/null +++ b/pyzhov_egor_lab_4/readme.md @@ -0,0 +1,171 @@ +# Лабораторная работа 4 + +## Задание + +Разработка распределенного приложения с использованием платформы Apache Ignite. +Необходимо разработать параллельный вариант алгоритма с применением подхода Grid +Gain и платформа Apache Ignite, замерить время его работы. + +**Вариант:** "Упорядочить строки матрицы по убыванию первых элементов." + +## Описание работы программы + +1. **Инициализация Ignite:** Запускает Ignite-кластер, используя конфигурационный файл `conf.xml`. +2. **Генерация матрицы:** Создает квадратную матрицу заданного размера (из аргументов командной строки). +3. **Распределенная сортировка матрицы:** + * Использует Ignite для распределенного выполнения задачи `MatrixSortingTask`. + * Задача `MatrixSortingTask` разделяет работу на подзадачи (`MatrixSortingJob`), распределяя обработку строк матрицы между узлами кластера. +4. **Разделение задачи(`split`)** + * Игнайт автоматически определяет количество узлов (gridSize). + * Матрица разбивается на блоки строк, каждый из которых обрабатывается отдельной подзадачей (MatrixSortingJob). +5. **Параллельная сортировка (`execute`)** + * Каждый узел получает свой диапазон строк, сортирует их по первому элементу (по убыванию) и возвращает результат. +6. **Объединение результатов (`reduce`)** + * Главный узел собирает все отсортированные блоки и выполняет финальную сортировку для получения итоговой матрицы. +7. **Вывод результата:** + * Если размер матрицы меньше 10x10, выводит отсортированную матрицу в консоль. + * В противном случае выводит сообщение о завершении сортировки. + * Замеряет и выводит время выполнения (duration). +## Описание кода +```java +public static void main(String[] args) { + String workingDir = System.getProperty("user.dir") + File.separator + "conf.xml"; + Path path = Paths.get(workingDir); + int size = Integer.parseInt(args[args.length - 1]); + + try (Ignite ignite = Ignition.start(workingDir)) { + int[][] matrix = new int[size][size]; + Random r = new Random(); + } +``` +Основной метод программы, который: +* Загружает конфигурацию Ignite из файла conf.xml +* Получает размер матрицы из аргументов командной строки +* Инициализирует Ignite-кластер +* Создает матрицу заданного размера и заполняет случайными числами + + +```java +public static class MatrixSortingTask extends ComputeTaskSplitAdapter { + @Override + protected List split(int gridSize, int[][] matrix) { + List jobs = new ArrayList<>(); + int batchSize = Math.max(1, matrix.length / gridSize); +``` +Класс задачи, который Разделяет матрицу на части по количеству доступных узлов (gridSize) и создает подзадачи (MatrixSortingJob) для обработки каждой части. + +```java +public static class MatrixSortingJob implements ComputeJob { + @Override + public int[][] execute() { + List rows = new ArrayList<>(); + for (int[] row : part) { + rows.add(row); + } + Collections.sort(rows, (row1, row2) -> Integer.compare(row2[0], row1[0])); +``` +Класс подзадачи, который получает часть для обработки, сортирует и возвращает отсортированную часть. + +```java +@Override +public int[][] reduce(List results) { + List sortedRows = new ArrayList<>(); + for (ComputeJobResult res : results) { + int[][] part = res.getData(); + Collections.sort(sortedRows, (row1, row2) -> Integer.compare(row2[0], row1[0])); + } + return sortedRows.toArray(new int[0][]); +} +``` +Метод получающий результаты со всех узлов, выполняет финальную сортировку объединенной матрицы. + + +## Запуск приложения +1) На обоих контейнерах должен быть установлен Apache Ignite. + ```bush + wget https://dlcdn.apache.org/ignite/2.17.0/apache-ignite-2.17.0-bin.zip + unzip apache-ignite-2.17.0-bin.zip + ``` +2) На первом контейнере должен быть jar файл в одной папке с conf.xml, на втором в apache-ignite-2.17.0-bin/config должен находиться наш myConf.xml +3) Переходим на второй контейнер, который без jar файла и переходим в директорию apache-ignite-2.17.0-bin/bin, выполняем следующую команду: + ```bash + ignite.sh -i + ``` + Выбираем myConf.xml +4) На контейнере с jar файлом запускаем программу + ```bash + java -jar sspr4-1.0-SNAPSHOT.jar SIZE + ``` + +## Основные технологии + +- **Maven** +- **Apache Ignite** +- **Java 11** + +## Результат работы программы +Запуск: +```bash +java -jar sspr4-1.0-SNAPSHOT.jar 5 +``` + +Вывод в первом контейнере: +``` +Original matrix: +29 75 96 81 52 +21 97 49 1 72 +51 66 20 60 71 +0 20 30 70 66 +49 72 49 91 11 +[MAIN] Created job for rows 0 to 1 +[MAIN] Created job for rows 2 to 4 +[Node-52c56677] Processing rows 0 to 1 +[Node-52c56677] Part before sorting: +29 75 96 81 52 +21 97 49 1 72 +[Node-52c56677] Part after sorting: +29 75 96 81 52 +21 97 49 1 72 + +Sorted matrix (by first element in descending order): +51 66 20 60 71 +49 72 49 91 11 +29 75 96 81 52 +21 97 49 1 72 +0 20 30 70 66 +Execution time: 109 ms +[12:04:46] Ignite node stopped OK [name=my-cluster, uptime=00:00:00.327] +``` + +Вывод в втором контейенере: +``` +[Node-85bfc0d0] Processing rows 2 to 4 +[Node-85bfc0d0] Part before sorting: +51 66 20 60 71 +0 20 30 70 66 +49 72 49 91 11 +[Node-85bfc0d0] Part after sorting: +51 66 20 60 71 +49 72 49 91 11 +0 20 30 70 66 +``` + + +Были проведены замеры работы программы на разных объёмах данных: + +Замеры с использованием двух узлов: +- size 1000: 171 ms +- size 3000: 967 ms +- size 5000: 1881 ms +- size 7000: 4744 ms + +Замеры с выполнением на одном узле: +- size 1000: 32 ms +- size 3000: 29 ms +- size 5000: 50 ms +- size 7000: 68 ms + +## Вывод + +Из полученных результатов можно сделать вывод, что в нашем случае, распределение вычислений между контейенерами привело к значительному замедлению во всех случаях. Накладные расходы на координацию между узлами занимают гораздо большее время, чем сам процесс сортировки. + diff --git a/pyzhov_egor_lab_4/src/main/java/MatrixApp.java b/pyzhov_egor_lab_4/src/main/java/MatrixApp.java new file mode 100644 index 0000000..8798c51 --- /dev/null +++ b/pyzhov_egor_lab_4/src/main/java/MatrixApp.java @@ -0,0 +1,156 @@ +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteException; +import org.apache.ignite.Ignition; +import org.apache.ignite.compute.ComputeTaskSplitAdapter; +import org.apache.ignite.compute.ComputeJob; +import org.apache.ignite.compute.ComputeJobResult; +import org.apache.ignite.resources.IgniteInstanceResource; +import org.apache.ignite.cluster.ClusterNode; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Random; +import java.util.UUID; + +public class MatrixApp { + public static void main(String[] args) { + String workingDir = System.getProperty("user.dir") + File.separator + "conf.xml"; + Path path = Paths.get(workingDir); + int size = Integer.parseInt(args[args.length - 1]); + + try (Ignite ignite = Ignition.start(workingDir)) { + int[][] matrix = new int[size][size]; + Random r = new Random(); + + System.out.println("Original matrix:"); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + matrix[i][j] = r.nextInt(100); + System.out.print(matrix[i][j] + "\t"); + } + System.out.println(); + } + + long start = System.currentTimeMillis(); + int[][] sortedMatrix = ignite.compute().execute(new MatrixSortingTask(), matrix); + long duration = System.currentTimeMillis() - start; + + System.out.println("\nSorted matrix (by first element in descending order):"); + for (int[] row : sortedMatrix) { + for (int value : row) { + System.out.print(value + "\t"); + } + System.out.println(); + } + + System.out.println("Execution time: " + duration + " ms"); + } catch (IgniteException e) { + System.err.println("Ignite Exception: " + e.getMessage()); + e.printStackTrace(); + } catch (Exception e) { + System.err.println("General Exception: " + e.getMessage()); + e.printStackTrace(); + } + } + + public static class MatrixSortingTask extends ComputeTaskSplitAdapter { + @IgniteInstanceResource + private Ignite ignite; + + @Override + protected List split(int gridSize, int[][] matrix) { + List jobs = new ArrayList<>(); + int batchSize = Math.max(1, matrix.length / gridSize); + + for (int i = 0; i < gridSize; i++) { + int start = i * batchSize; + int end = (i == gridSize - 1) ? matrix.length : (i + 1) * batchSize; + + if (start < matrix.length) { + jobs.add(new MatrixSortingJob(matrix, start, end)); + System.out.println("[MAIN] Created job for rows " + start + " to " + (end - 1)); + } + } + + return jobs; + } + + @Override + public int[][] reduce(List results) { + List sortedRows = new ArrayList<>(); + + for (ComputeJobResult res : results) { + int[][] part = res.getData(); + for (int[] row : part) { + sortedRows.add(row); + } + } + + Collections.sort(sortedRows, (row1, row2) -> Integer.compare(row2[0], row1[0])); + + return sortedRows.toArray(new int[0][]); + } + } + + public static class MatrixSortingJob implements ComputeJob { + @IgniteInstanceResource + private Ignite ignite; + + private final int[][] matrix; + private final int start; + private final int end; + + public MatrixSortingJob(int[][] matrix, int start, int end) { + this.matrix = matrix; + this.start = start; + this.end = end; + } + + @Override + public int[][] execute() { + ClusterNode node = ignite.cluster().localNode(); + UUID nodeId = node.id(); + String nodeName = "Node-" + nodeId.toString().substring(0, 8); + + System.out.println("[" + nodeName + "] Processing rows " + start + " to " + (end - 1)); + + int[][] part = new int[end - start][]; + System.arraycopy(matrix, start, part, 0, end - start); + + System.out.println("[" + nodeName + "] Part before sorting:"); + for (int[] row : part) { + for (int value : row) { + System.out.print(value + "\t"); + } + System.out.println(); + } + + List rows = new ArrayList<>(); + for (int[] row : part) { + rows.add(row); + } + + Collections.sort(rows, (row1, row2) -> Integer.compare(row2[0], row1[0])); + + System.out.println("[" + nodeName + "] Part after sorting:"); + for (int[] row : rows) { + for (int value : row) { + System.out.print(value + "\t"); + } + System.out.println(); + } + + return rows.toArray(new int[0][]); + } + + @Override + public void cancel() { + System.out.println("Job was cancelled"); + } + } +} \ No newline at end of file