diff --git a/pupkov_alexey_lab_3/README.md b/pupkov_alexey_lab_3/README.md new file mode 100644 index 0000000..5346515 --- /dev/null +++ b/pupkov_alexey_lab_3/README.md @@ -0,0 +1,32 @@ +# Лабораторная работа №3 - REST API, шлюз и синхронный обмен данными между микросервисами + +## Задание + +### Цель: +Изучение принципов проектирования с использованием паттерна шлюза, организации синхронной передачи данных между микросервисами и применения архитектурного стиля RESTful API. + +### Задачи: +1. Создание двух микросервисов, которые реализуют операции CRUD для связанных сущностей. +2. Реализация механизма синхронного обмена данными между микросервисами. +3. Настройка шлюза на базе Nginx в качестве прозрачного прокси-сервера. + +### Микросервисы: +1. book_service — сервис, который управляет информацией о книгах. +2. subscription_service — сервис, который обрабатывает данные о подспиках, которым принадлежащих книги. + +## Описание работы: + +Для разработки микросервисов был выбран язык программирования Python. + +### Синхронный обмен данными +Сервис book_service отправляет HTTP-запросы к subscription_service при выполнении определенных операций CRUD. Это позволяет получать актуальную информацию о предметах, связанных с конкретными героями. + +### Docker Compose +Конфигурационный файл docker-compose.yml представляет собой многоконтейнерное приложение, которое включает в себя три сервиса: book_service, subscription_service и nginx. Функция маршрутизации возложена на сервер Nginx, который обрабатывает запросы и перенаправляет их на соответствующие микросервисы. + +### Nginx +Конфигурационный файл Nginx определяет настройки веб-сервера и обратного прокси, который управляет входящими запросами и направляет их на соответствующие сервисы. + +## Видео ВК + + [Ссылка на демонстрацию работы программы](https://vk.com/video547368103_456239604?list=ln-6CV0kolsFgPBdGrKz7) diff --git a/pupkov_alexey_lab_3/docker-compose.yaml b/pupkov_alexey_lab_3/docker-compose.yaml new file mode 100644 index 0000000..d4a4b7d --- /dev/null +++ b/pupkov_alexey_lab_3/docker-compose.yaml @@ -0,0 +1,25 @@ +version: '3.8' +networks: + default: + name: my_network + +services: + subscription-service: + build: ./services/subscription + ports: + - "5000:5000" + + book-service: + build: ./services/book + ports: + - "5001:5001" + + gateway: + image: nginx:latest + volumes: + - ./gateway/nginx.conf:/etc/nginx/nginx.conf + ports: + - "80:80" + depends_on: + - subscription-service + - book-service diff --git a/pupkov_alexey_lab_3/gateway/nginx.conf b/pupkov_alexey_lab_3/gateway/nginx.conf new file mode 100644 index 0000000..f5828d7 --- /dev/null +++ b/pupkov_alexey_lab_3/gateway/nginx.conf @@ -0,0 +1,32 @@ +events { + worker_connections 1024; +} + +http { + sendfile on; + server { + listen 80; + listen [::]:80; + server_name localhost; + + # Прокси для сервиса подписок + location /api/subscriptions/ { + proxy_pass http://subscription-service:5000/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + } + + # Прокси для сервиса книг + location /api/books/ { + proxy_pass http://book-service:5001/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + } + } +} diff --git a/pupkov_alexey_lab_3/services/book/Dockerfile b/pupkov_alexey_lab_3/services/book/Dockerfile new file mode 100644 index 0000000..d479577 --- /dev/null +++ b/pupkov_alexey_lab_3/services/book/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.10-slim +WORKDIR /app +COPY . . +RUN pip install flask flask-restful requests +CMD ["python", "app.py"] diff --git a/pupkov_alexey_lab_3/services/book/app.py b/pupkov_alexey_lab_3/services/book/app.py new file mode 100644 index 0000000..7d90ec0 --- /dev/null +++ b/pupkov_alexey_lab_3/services/book/app.py @@ -0,0 +1,63 @@ +from flask import Flask, request, jsonify +import uuid +import requests + +app = Flask(__name__) + +# Хранилище данных +books = [] + +SUBSCRIPTION_SERVICE_URL = "http://subscription-service:5000/api/subscriptions/" + +@app.route('/api/books/', methods=['GET']) +def get_books(): + return jsonify(books), 200 + +@app.route('/api/books/', methods=['GET']) +def get_book(uuid): + book = next((b for b in books if b['uuid'] == str(uuid)), None) + if not book: + return jsonify({'error': 'Book not found'}), 404 + + subscription_uuid = book['subscriptionUuid'] + subscription = requests.get(f"{SUBSCRIPTION_SERVICE_URL}{subscription_uuid}").json() + book['subscriptionInfo'] = subscription + + return jsonify(book), 200 + +@app.route('/api/books/', methods=['POST']) +def create_book(): + data = request.json + book = { + 'uuid': str(uuid.uuid4()), + 'author': data['author'], + 'subject': data['subject'], + 'year': data['year'], + 'subscriptionUuid': data['subscriptionUuid'] + } + books.append(book) + return jsonify(book), 201 + +@app.route('/api/books/', methods=['PUT']) +def update_book(uuid): + data = request.json + book = next((b for b in books if b['uuid'] == str(uuid)), None) + if not book: + return jsonify({'error': 'Book not found'}), 404 + + book.update({ + 'author': data['author'], + 'subject': data['subject'], + 'year': data['year'], + 'subscriptionUuid': data['subscriptionUuid'] + }) + return jsonify(book), 200 + +@app.route('/api/books/', methods=['DELETE']) +def delete_book(uuid): + global books + books = [b for b in books if b['uuid'] != str(uuid)] + return '', 204 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001) diff --git a/pupkov_alexey_lab_3/services/subscription/Dockerfile b/pupkov_alexey_lab_3/services/subscription/Dockerfile new file mode 100644 index 0000000..4078349 --- /dev/null +++ b/pupkov_alexey_lab_3/services/subscription/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.10-slim +WORKDIR /app +COPY . . +RUN pip install flask flask-restful +CMD ["python", "app.py"] diff --git a/pupkov_alexey_lab_3/services/subscription/app.py b/pupkov_alexey_lab_3/services/subscription/app.py new file mode 100644 index 0000000..894bbcc --- /dev/null +++ b/pupkov_alexey_lab_3/services/subscription/app.py @@ -0,0 +1,53 @@ +from flask import Flask, request, jsonify +import uuid + +app = Flask(__name__) + +# Хранилище данных +subscriptions = [] + +@app.route('/api/subscriptions/', methods=['GET']) +def get_subscriptions(): + return jsonify(subscriptions), 200 + +@app.route('/api/subscriptions/', methods=['GET']) +def get_subscription(uuid): + subscription = next((sub for sub in subscriptions if sub['uuid'] == str(uuid)), None) + if not subscription: + return jsonify({'error': 'Subscription not found'}), 404 + return jsonify(subscription), 200 + +@app.route('/api/subscriptions/', methods=['POST']) +def create_subscription(): + data = request.json + subscription = { + 'uuid': str(uuid.uuid4()), + 'number': data['number'], + 'fullName': data['fullName'], + 'issued': data['issued'] + } + subscriptions.append(subscription) + return jsonify(subscription), 201 + +@app.route('/api/subscriptions/', methods=['PUT']) +def update_subscription(uuid): + data = request.json + subscription = next((sub for sub in subscriptions if sub['uuid'] == str(uuid)), None) + if not subscription: + return jsonify({'error': 'Subscription not found'}), 404 + + subscription.update({ + 'number': data['number'], + 'fullName': data['fullName'], + 'issued': data['issued'] + }) + return jsonify(subscription), 200 + +@app.route('/api/subscriptions/', methods=['DELETE']) +def delete_subscription(uuid): + global subscriptions + subscriptions = [sub for sub in subscriptions if sub['uuid'] != str(uuid)] + return '', 204 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) diff --git a/pupkov_alexey_lab_5/README.md b/pupkov_alexey_lab_5/README.md new file mode 100644 index 0000000..8a4b1cd --- /dev/null +++ b/pupkov_alexey_lab_5/README.md @@ -0,0 +1,70 @@ +# Пупков Алексей ИСЭбд-41 +# Отчет по умножению матриц +## Описание + +В данной лабораторной работе реализованы два алгоритма для умножения больших квадратных матриц: последовательный и параллельный. Для параллельного вычисления используется библиотека concurrent.futures в Python. Программа позволяет задавать количество процессов, что позволяет наблюдать за изменением производительности при увеличении числа потоков. + +## Как работает код: + +1. Импорт библиотек +- concurrent.futures помогает запускать параллельные задачи с использованием потоков +- time используется для измерения времени выполнения алгоритмов +- numpy используется для работы с матрицами и для вычислений +- argparse для обработки аргументов командной строки + +2. Функция matrix_multiply_sequential(A, B) +- Выполняет последовательное умножение двух матриц A и B. + +3. Функция worker(A, B, C, start_row, end_row) +- Выполняет умножение для части строк матрицы, параметры start_row и end_row определяют диапазон строк, которые нужно вычислить + +4. Функция matrix_multiply_parallel(A, B, num_threads) +- Реализует параллельное умножение матриц + +5. Функция benchmark(matrix_sizes, num_threads_list) + +- Выполняет бенчмаркинг (измерение времени выполнения) для обоих методов умножения + +## Результаты + +Размер матриц: 100x100 +Последовательное умножение заняло: 0.0558 секунд + +Параллельное умножение с 2 потоками заняло: 0.0886 секунд + +Параллельное умножение с 4 потоками заняло: 0.0876 секунд + +Параллельное умножение с 8 потоками заняло: 0.0868 секунд + +Параллельное умножение с 16 потоками заняло: 0.0914 секунд + +Размер матриц: 300x300 +Последовательное умножение заняло: 1.6149 секунд + +Параллельное умножение с 2 потоками заняло: 2.4936 секунд + +Параллельное умножение с 4 потоками заняло: 2.4383 секунд + +Параллельное умножение с 8 потоками заняло: 2.4458 секунд + +Параллельное умножение с 16 потоками заняло: 2.4899 секунд + +Размер матриц: 500x500 +Последовательное умножение заняло: 7.9416 секунд + +Параллельное умножение с 2 потоками заняло: 11.8896 секунд + +Параллельное умножение с 4 потоками заняло: 11.8901 секунд + +Параллельное умножение с 8 потоками заняло: 12.0230 секунд + +Параллельное умножение с 16 потоками заняло: 11.8548 секунд + + +## Выводы +Во всех случаях параллельный алгоритм выполняется дольше, чем последовательный. На рассматриваемых матрицах (100x100, 300x300, 500x500) последовательное умножение оказывается более выгодным. Это связано с тем, что накладные расходы на параллельное исполнение и синхронизацию между потоками превышают время, которое можно сэкономить за счёт многопоточности. + +## Запуск +Python main.py – threads 2 4 8 16 + +[Ссылка на демонстрацию работы программы](https://vk.com/video547368103_456239605?list=ln-ZAsjrYkuwZp6I4ghXC) \ No newline at end of file diff --git a/pupkov_alexey_lab_5/main.py b/pupkov_alexey_lab_5/main.py new file mode 100644 index 0000000..a46d05e --- /dev/null +++ b/pupkov_alexey_lab_5/main.py @@ -0,0 +1,92 @@ +from concurrent.futures import ThreadPoolExecutor +import time +import numpy as np +import argparse + +# Последовательное умножение +def matrix_multiply_sequential(A, B): + n = len(A) + C = [[0] * n for _ in range(n)] + + # Транспонируем матрицу B для оптимального доступа по строкам + B_T = [[B[j][i] for j in range(n)] for i in range(n)] + + for i in range(n): + A_row = A[i] + for j in range(n): + B_col = B_T[j] + sum_ij = 0 + for k in range(n): + sum_ij += A_row[k] * B_col[k] + C[i][j] = sum_ij + + return C + +# Вычисляет подматрицу C +def worker(A, B, C, start_row, end_row): + n = len(A) + for i in range(start_row, end_row): + for j in range(n): + sum_ij = 0 + for k in range(n): + sum_ij += A[i][k] * B[k][j] + C[i][j] = sum_ij + +# Параллельное умножение матриц +def matrix_multiply_parallel(A, B, num_threads): + n = len(A) + C = [[0] * n for _ in range(n)] + + # Разбиваем строки между потоками + rows_per_thread = n // num_threads + extra_rows = n % num_threads + row_splits = [rows_per_thread + (1 if i < extra_rows else 0) for i in range(num_threads)] + row_indices = [sum(row_splits[:i]) for i in range(num_threads + 1)] + + # Параллельно выполняем умножение подматриц + with ThreadPoolExecutor(max_workers=num_threads) as executor: + futures = [ + executor.submit(worker, A, B, C, row_indices[i], row_indices[i+1]) + for i in range(num_threads) + ] + for future in futures: + future.result() + + return C + +def benchmark(matrix_sizes, num_threads_list): + for size in matrix_sizes: + A = [[1] * size for _ in range(size)] # Матрицы, заполненные единицами для упрощения теста + B = [[1] * size for _ in range(size)] + print(f"\nРазмер матриц: {size}x{size}") + + # Бенчмарк для последовательного алгоритма + start_time = time.time() + C_seq = matrix_multiply_sequential(A, B) + sequential_time = time.time() - start_time + print(f"Последовательное умножение заняло: {sequential_time:.4f} секунд") + + # Бенчмарк для параллельного алгоритма + for num_threads in num_threads_list: + start_time = time.time() + C_par = matrix_multiply_parallel(A, B, num_threads) + parallel_time = time.time() - start_time + print(f"Параллельное умножение с {num_threads} потоками заняло: {parallel_time:.4f} секунд") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Запуск бенчмарков для умножения матриц.") + parser.add_argument( + "--threads", + type=int, + nargs="+", + required=True, + help="Список количества потоков для параллельного алгоритма (например, --threads 1 2 4 8)" + ) + args = parser.parse_args() + + # Задание размеров матриц для тестов + matrix_sizes = [100, 300, 500] + num_threads_list = args.threads # Получаем список потоков из аргументов командной строки + + # Запуск бенчмарка + benchmark(matrix_sizes, num_threads_list)