diff --git a/chernyshov_nikita_lab_2/README.md b/chernyshov_nikita_lab_2/README.md new file mode 100644 index 0000000..d1b8854 --- /dev/null +++ b/chernyshov_nikita_lab_2/README.md @@ -0,0 +1,22 @@ +## Лабораторная работа №2 + + +**App 1: Программа 4 - Количество символов в именах файлов из каталога /var/data** + +- Формирует файл /var/result/data.txt так, что каждая строка файла - количество символов в именах файлов из каталога /var/data. + +**App 2: Программа 3 - Количество чисел в последовательности** + +- Ищет набольшее число из файла /var/result/data.txt и сохраняет количество таких чисел из последовательности в /var/result/result.txt. + +**Структура проекта:** + +1. В папках app_1, app_2 лежат выполняемые файлы .py и Dockerfile с нужным кодом. +2. В папке generator_of_data лежат выполняемые файлы для создания данных. +3. В папке data лежат файлы, длину имен которых нужно посчитать. +4. В папке result лежат файлы с результатами выполнения программ. data.txt - результат выполнения main.py (app_1), result.txt - результат выполнения main.py (app_2). Данные в result рассчитываются из данных data. +5. docker-compose.yml - для определения и управления контейнерами Docker. + +**Команда для запуска** - docker-compose up + +**Ссылка на видео:** https://vkvideo.ru/video286865610_456239225?list=ln-Xqg7SupM1CohXsGRZK \ No newline at end of file diff --git a/chernyshov_nikita_lab_2/app_1/Dockerfile b/chernyshov_nikita_lab_2/app_1/Dockerfile new file mode 100644 index 0000000..0690732 --- /dev/null +++ b/chernyshov_nikita_lab_2/app_1/Dockerfile @@ -0,0 +1,20 @@ +# Используем образ Python 3.9-slim как основу для нашего контейнера. +# slim-версия образа более компактная, что делает контейнер меньше. +FROM python:3.9-slim +# Устанавливаем рабочую директорию в контейнере как /app. +# Все последующие команды будут выполняться в этой директории. +WORKDIR /app +# Копируем файл main.py из текущей директории в директорию /app в контейнере. +COPY . /app +# Определяем команду, которая будет выполняться при запуске контейнера. +# В данном случае запускается Python-скрипт main.py. +CMD ["python", "main.py"] + + + + + + + + + diff --git a/chernyshov_nikita_lab_2/app_1/main.py b/chernyshov_nikita_lab_2/app_1/main.py new file mode 100644 index 0000000..5e945ea --- /dev/null +++ b/chernyshov_nikita_lab_2/app_1/main.py @@ -0,0 +1,38 @@ +import os + +def get_file_with_most_lines(directory): + max_lines = 0 + target_file = "" + + for filename in os.listdir(directory): + filepath = os.path.join(directory, filename) + if os.path.isfile(filepath): + with open(filepath, 'r') as f: + line_count = sum(1 for _ in f) + if line_count > max_lines: + max_lines = line_count + target_file = filename + + return target_file + +def copy_file(src_directory, dest_directory, filename): + src_filepath = os.path.join(src_directory, filename) + dest_filepath = os.path.join(dest_directory, 'data.txt') + + os.makedirs(dest_directory, exist_ok=True) + + with open(src_filepath, 'r') as src_file: + with open(dest_filepath, 'w') as dest_file: + dest_file.write(src_file.read()) + +def main(): + src_directory = '/var/data' + dest_directory = '/var/result' + + target_file = get_file_with_most_lines(src_directory) + if target_file: + copy_file(src_directory, dest_directory, target_file) + print(f"File {target_file} copied to {dest_directory}/data.txt") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/chernyshov_nikita_lab_2/app_2/Dockerfile b/chernyshov_nikita_lab_2/app_2/Dockerfile new file mode 100644 index 0000000..946d3a7 --- /dev/null +++ b/chernyshov_nikita_lab_2/app_2/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.9-slim + +WORKDIR /app + +COPY . /app + +CMD ["python", "main.py"] \ No newline at end of file diff --git a/chernyshov_nikita_lab_2/app_2/main.py b/chernyshov_nikita_lab_2/app_2/main.py new file mode 100644 index 0000000..b25deb9 --- /dev/null +++ b/chernyshov_nikita_lab_2/app_2/main.py @@ -0,0 +1,25 @@ +import os + +def get_largest_number_from_file(filepath): + with open(filepath, 'r') as f: + numbers = [int(line.strip()) for line in f.readlines()] + return max(numbers) + +def save_square_of_number(number, output_filepath): + result = number ** 2 + with open(output_filepath, 'w') as f: + f.write(str(result)) + +def main(): + input_filepath = '/var/result/data.txt' + output_filepath = '/var/result/result.txt' + + if os.path.exists(input_filepath): + largest_number = get_largest_number_from_file(input_filepath) + save_square_of_number(largest_number, output_filepath) + print(f"Largest number squared: {largest_number}^2 saved to {output_filepath}") + else: + print(f"Input file {input_filepath} not found!") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/chernyshov_nikita_lab_2/docker-compose.yml b/chernyshov_nikita_lab_2/docker-compose.yml new file mode 100644 index 0000000..5f2cb34 --- /dev/null +++ b/chernyshov_nikita_lab_2/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' +services: + generator_of_data: + build: + context: ./generator_of_data + volumes: + - ./data:/var/data + app_1: + build: + context: ./app_1 + volumes: + - ./data:/var/data + - ./result:/var/result + depends_on: + - generator_of_data + app_2: + build: + context: ./app_2 + volumes: + - ./result:/var/result + depends_on: + - app_1 diff --git a/chernyshov_nikita_lab_2/generator_of_data/Dockerfile b/chernyshov_nikita_lab_2/generator_of_data/Dockerfile new file mode 100644 index 0000000..9ce2be9 --- /dev/null +++ b/chernyshov_nikita_lab_2/generator_of_data/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.9-slim + +WORKDIR /app + +COPY . /app + +CMD ["python", "generate_data.py"] \ No newline at end of file diff --git a/chernyshov_nikita_lab_2/generator_of_data/generate_data.py b/chernyshov_nikita_lab_2/generator_of_data/generate_data.py new file mode 100644 index 0000000..913ba85 --- /dev/null +++ b/chernyshov_nikita_lab_2/generator_of_data/generate_data.py @@ -0,0 +1,27 @@ +import os +import random + +def generate_random_files(directory, num_files, num_lines_per_file, min_value, max_value): + os.makedirs(directory, exist_ok=True) + + for i in range(num_files): + file_path = os.path.join(directory, f"file_{i + 1}.txt") + with open(file_path, 'w') as f: + for _ in range(num_lines_per_file): + random_number = random.randint(min_value, max_value) + f.write(f"{random_number}\n") + print(f"Generated file: {file_path}") + +def main(): + data_directory = '/var/data' + num_files = 10 + num_lines_per_file = 12 + min_value = 1 + max_value = 100 + + generate_random_files(data_directory, num_files, num_lines_per_file, min_value, max_value) + print(f"Generated {num_files} files in {data_directory}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/README.md b/chernyshov_nikita_lab_3/README.md new file mode 100644 index 0000000..c097b0f --- /dev/null +++ b/chernyshov_nikita_lab_3/README.md @@ -0,0 +1,36 @@ + +## Лабораторная работа №3 + +### Цель: +* Реализовать два микросервиса, которые взаимодействуют друг с другом через синхронный обмен сообщениями (HTTP-запросы). Для доступа к микросервисам используется шлюз Nginx, реализованный с помощью Docker Compose. + +### Технологии: + +* Python: Язык программирования для реализации микросервисов. +* Flask: Фреймворк Python для создания веб-приложений, использован для создания REST API микросервисов. +* requests: Библиотека Python для отправки HTTP-запросов, использован для синхронного обмена сообщениями между микросервисами. +* flask_cors: Расширение Flask, которое позволяет микросервисам получать доступ к данным из других доменов. +* Docker: Технология контейнеризации для упаковки и запуска микросервисов. +* Docker Compose: Инструмент для определения и управления многоконтейнерными приложениями, использован для запуска микросервисов и шлюза Nginx. +* Nginx: Сетевой прокси-сервер, использован как шлюз для доступа к микросервисам. + +### Функциональность: + +#### Микросервис games-service: +* Реализует CRUD операции для игр (GET, POST, PUT, DELETE). +* Сохраняет данные о играх в памяти (в словаре games). +* Получает информацию о жанре из микросервиса genres-service через HTTP-запрос. +* Включает информацию о жанре в ответ JSON для игры. +#### Микросервис genres-service: +* Реализует CRUD операции для жанров (GET, POST, PUT, DELETE). +* Сохраняет данные о жанре в памяти (в словаре genres). +#### Шлюз Nginx: +* Перенаправляет HTTP-запросы на соответствующие микросервисы. +* Предоставляет единую точку входа для доступа к микросервисам. + +### Запуск программы: + +* Запуск команды docker-compose up --build + +### Ссылка на видео: +https://vkvideo.ru/video286865610_456239226?list=ln-U577n85GB3sBxUtF34 \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/docker-compose.yml b/chernyshov_nikita_lab_3/docker-compose.yml new file mode 100644 index 0000000..4c732d2 --- /dev/null +++ b/chernyshov_nikita_lab_3/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + games_service: + build: + context: ./games_service + dockerfile: Dockerfile + ports: + - "5000:5000" + + genres_service: + build: + context: ./genres_service + dockerfile: Dockerfile + ports: + - "5001:5001" + + nginx: + image: nginx:latest + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf + ports: + - "80:80" + depends_on: + - games_service + - genres_service diff --git a/chernyshov_nikita_lab_3/games_service/Dockerfile b/chernyshov_nikita_lab_3/games_service/Dockerfile new file mode 100644 index 0000000..851c5df --- /dev/null +++ b/chernyshov_nikita_lab_3/games_service/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["python", "main.py"] \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/games_service/main.py b/chernyshov_nikita_lab_3/games_service/main.py new file mode 100644 index 0000000..3bf68bf --- /dev/null +++ b/chernyshov_nikita_lab_3/games_service/main.py @@ -0,0 +1,53 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +games = {} + + +@app.route('/games', methods=['GET']) +def get_games(): + return jsonify(list(games.values())) + +@app.route('/games/', methods=['GET']) +def get_game(game_uuid): + game = games.get(str(game_uuid)) + if game: + return jsonify(game) + return jsonify({'error': 'Not found'}), 404 + +@app.route('/games', methods=['POST']) +def create_game(): + data = request.get_json() + game_uuid = str(uuid.uuid4()) + game = { + 'uuid': game_uuid, + 'name': data['name'], + 'developer': data['developer'], + 'genres': data.get('genres', []) # List of genre UUIDs + } + games[game_uuid] = game + return jsonify(game), 201 + +@app.route('/games/', methods=['PUT']) +def update_game(game_uuid): + game = games.get(str(game_uuid)) + if not game: + return jsonify({'error': 'Not found'}), 404 + data = request.get_json() + game['name'] = data['name'] + game['developer'] = data['developer'] + game['genres'] = data.get('genres', []) + return jsonify(game) + +@app.route('/games/', methods=['DELETE']) +def delete_game(game_uuid): + if str(game_uuid) in games: + del games[str(game_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/games_service/requirements.txt b/chernyshov_nikita_lab_3/games_service/requirements.txt new file mode 100644 index 0000000..2077213 --- /dev/null +++ b/chernyshov_nikita_lab_3/games_service/requirements.txt @@ -0,0 +1 @@ +Flask \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/genres_service/Dockerfile b/chernyshov_nikita_lab_3/genres_service/Dockerfile new file mode 100644 index 0000000..851c5df --- /dev/null +++ b/chernyshov_nikita_lab_3/genres_service/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["python", "main.py"] \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/genres_service/main.py b/chernyshov_nikita_lab_3/genres_service/main.py new file mode 100644 index 0000000..f652c60 --- /dev/null +++ b/chernyshov_nikita_lab_3/genres_service/main.py @@ -0,0 +1,51 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +genres = {} + + +@app.route('/genres', methods=['GET']) +def get_genres(): + return jsonify(list(genres.values())) + +@app.route('/genres/', methods=['GET']) +def get_genre(genre_uuid): + genre = genres.get(str(genre_uuid)) + if genre: + return jsonify(genre) + return jsonify({'error': 'Not found'}), 404 + +@app.route('/genres', methods=['POST']) +def create_genre(): + data = request.get_json() + genre_uuid = str(uuid.uuid4()) + genre = { + 'uuid': genre_uuid, + 'name': data['name'], + 'description': data['description'] + } + genres[genre_uuid] = genre + return jsonify(genre), 201 + +@app.route('/genres/', methods=['PUT']) +def update_genre(genre_uuid): + genre = genres.get(str(genre_uuid)) + if not genre: + return jsonify({'error': 'Not found'}), 404 + data = request.get_json() + genre['name'] = data['name'] + genre['description'] = data['description'] + return jsonify(genre) + +@app.route('/genres/', methods=['DELETE']) +def delete_genre(genre_uuid): + if str(genre_uuid) in genres: + del genres[str(genre_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001) \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/genres_service/requirements.txt b/chernyshov_nikita_lab_3/genres_service/requirements.txt new file mode 100644 index 0000000..2077213 --- /dev/null +++ b/chernyshov_nikita_lab_3/genres_service/requirements.txt @@ -0,0 +1 @@ +Flask \ No newline at end of file diff --git a/chernyshov_nikita_lab_3/nginx/nginx.conf b/chernyshov_nikita_lab_3/nginx/nginx.conf new file mode 100644 index 0000000..d3cc7f0 --- /dev/null +++ b/chernyshov_nikita_lab_3/nginx/nginx.conf @@ -0,0 +1,11 @@ +server { + listen 80; + + location /games { + proxy_pass http://games_service:5000; + } + + location /genres { + proxy_pass http://genres_service:5001; + } +} \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/Consumer1.py b/chernyshov_nikita_lab_4/Consumer1.py new file mode 100644 index 0000000..f7b6596 --- /dev/null +++ b/chernyshov_nikita_lab_4/Consumer1.py @@ -0,0 +1,30 @@ +import pika +import time + + +def callback(ch, method, properties, body): + print(f'Consumer 1 получил сообщение: {body.decode()}') + + # Время задержки по условию + time.sleep(2) + + print('Consumer 1 закончил обработку') + + +def consume_events_1(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + + # Создание очереди + channel.queue_declare(queue='consumer1_queue') + # Привязка очереди + channel.queue_bind(exchange='beauty_salon_events', queue='consumer1_queue') + + channel.basic_consume(queue='consumer1_queue', on_message_callback=callback, auto_ack=True) + + print('Consumer 1 начал ожидать сообщения...') + channel.start_consuming() + + +if __name__ == "__main__": + consume_events_1() diff --git a/chernyshov_nikita_lab_4/Consumer2.py b/chernyshov_nikita_lab_4/Consumer2.py new file mode 100644 index 0000000..df4f950 --- /dev/null +++ b/chernyshov_nikita_lab_4/Consumer2.py @@ -0,0 +1,28 @@ +import pika + + +def callback(ch, method, properties, body): + print(f'Consumer 2 получил сообщение: {body.decode()}') + + # Обработка "нон-стопом" + print('Consumer 2 закончил обработку') + + +def consume_events_2(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + + # Создание очереди + channel.queue_declare(queue='consumer2_queue') + + # Привязка очереди + channel.queue_bind(exchange='beauty_salon_events', queue='consumer2_queue') + + channel.basic_consume(queue='consumer2_queue', on_message_callback=callback, auto_ack=True) + + print('Consumer 2 начал ожидать сообщения...') + channel.start_consuming() + + +if __name__ == "__main__": + consume_events_2() diff --git a/chernyshov_nikita_lab_4/Publisher.py b/chernyshov_nikita_lab_4/Publisher.py new file mode 100644 index 0000000..9d53bb2 --- /dev/null +++ b/chernyshov_nikita_lab_4/Publisher.py @@ -0,0 +1,28 @@ +import pika +import time + + +def publish_events(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + + # Создание exchange типа fanout + channel.exchange_declare(exchange='beauty_salon_events', exchange_type='fanout') + + events = [ + "Test1", + "Test2", + "Test3", + "Test4", + "Test5" + ] + + while True: + event = events[int(time.time()) % len(events)] + channel.basic_publish(exchange='beauty_salon_events', routing_key='', body=event) + print(f'Отправлено: {event}') + time.sleep(1) + + +if __name__ == "__main__": + publish_events() diff --git a/chernyshov_nikita_lab_4/README.md b/chernyshov_nikita_lab_4/README.md new file mode 100644 index 0000000..fb1fc86 --- /dev/null +++ b/chernyshov_nikita_lab_4/README.md @@ -0,0 +1,56 @@ +### Лабораторная работа №4 + +#### Задание + +1. Установить брокер сообщений RabbitMQ. +2. Пройти уроки 1, 2 и 3 из RabbitMQ Tutorials на любом языке программирования. +3. Продемонстрировать работу брокера сообщений. + +#### Описание работы программы: + +- **Класс Publisher** успешно осуществляет отправку сообщений своим клиентам. + +- **Класс Consumer1** принимает и обрабатывает сообщения с задержкой в 3 секунды, что можно заметить на видео. + +- **Класс Consumer2** мгновенно принимает и обрабатывает сообщения. + +#### Уроки + +1. lesson1 + +![lesson1.png](lesson1.png) + +2. lesson2 + +![lesson2.png](lesson2.png) + +3. lesson3 + +![lesson3.png](lesson3.png) + +## Работа с RabbitMQ Management UI + +![img1.png](img1.png) + +## Показания очереди queue_1 при одном запущенном экземпляре Consumer_1 + +![img2.png](img2.png) + +## Показания очереди queue_2 + +![img3.png](img3.png) + +## Показания очереди queue_1 при двух запущенных экземплярах Consumer_1 +![img4.png](img4.png) + +## Показания очереди queue_1 при трех запущенных экземплярах Consumer_1 + +![img5.png](img5.png) + +## Диспетчер задач + +![img6.png](img6.png) + +## Видео + +https://vkvideo.ru/video286865610_456239227?list=ln-EUw7H8FIzc8ZwX8rG7 \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/img1.png b/chernyshov_nikita_lab_4/img1.png new file mode 100644 index 0000000..f050868 Binary files /dev/null and b/chernyshov_nikita_lab_4/img1.png differ diff --git a/chernyshov_nikita_lab_4/img2.png b/chernyshov_nikita_lab_4/img2.png new file mode 100644 index 0000000..e2b729c Binary files /dev/null and b/chernyshov_nikita_lab_4/img2.png differ diff --git a/chernyshov_nikita_lab_4/img3.png b/chernyshov_nikita_lab_4/img3.png new file mode 100644 index 0000000..f119a44 Binary files /dev/null and b/chernyshov_nikita_lab_4/img3.png differ diff --git a/chernyshov_nikita_lab_4/img4.png b/chernyshov_nikita_lab_4/img4.png new file mode 100644 index 0000000..f8dbbfa Binary files /dev/null and b/chernyshov_nikita_lab_4/img4.png differ diff --git a/chernyshov_nikita_lab_4/img5.png b/chernyshov_nikita_lab_4/img5.png new file mode 100644 index 0000000..03624e9 Binary files /dev/null and b/chernyshov_nikita_lab_4/img5.png differ diff --git a/chernyshov_nikita_lab_4/img6.png b/chernyshov_nikita_lab_4/img6.png new file mode 100644 index 0000000..f2288b8 Binary files /dev/null and b/chernyshov_nikita_lab_4/img6.png differ diff --git a/chernyshov_nikita_lab_4/lesson1.png b/chernyshov_nikita_lab_4/lesson1.png new file mode 100644 index 0000000..9b434d6 Binary files /dev/null and b/chernyshov_nikita_lab_4/lesson1.png differ diff --git a/chernyshov_nikita_lab_4/lesson1/receive.py b/chernyshov_nikita_lab_4/lesson1/receive.py new file mode 100644 index 0000000..f118e0a --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson1/receive.py @@ -0,0 +1,25 @@ +import pika, sys, os + +def main(): + connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) + channel = connection.channel() + + channel.queue_declare(queue='hello') + + def callback(ch, method, properties, body): + print(f" [x] Received {body}") + + channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True) + + print(' [*] Waiting for messages. To exit press CTRL+C') + channel.start_consuming() + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + print('Interrupted') + try: + sys.exit(0) + except SystemExit: + os._exit(0) \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/lesson1/send.py b/chernyshov_nikita_lab_4/lesson1/send.py new file mode 100644 index 0000000..41cfff2 --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson1/send.py @@ -0,0 +1,11 @@ +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.queue_declare(queue='hello') + +channel.basic_publish(exchange='', routing_key='hello', body='Hello World!') +print(" [x] Sent 'Hello World!'") +connection.close() \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/lesson2.png b/chernyshov_nikita_lab_4/lesson2.png new file mode 100644 index 0000000..01a8c97 Binary files /dev/null and b/chernyshov_nikita_lab_4/lesson2.png differ diff --git a/chernyshov_nikita_lab_4/lesson2/newtask.py b/chernyshov_nikita_lab_4/lesson2/newtask.py new file mode 100644 index 0000000..a2444e0 --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson2/newtask.py @@ -0,0 +1,19 @@ +import pika +import sys + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.queue_declare(queue='task_queue', durable=True) + +message = ' '.join(sys.argv[1:]) or "Hello World!" +channel.basic_publish( + exchange='', + routing_key='task_queue', + body=message, + properties=pika.BasicProperties( + delivery_mode=pika.DeliveryMode.Persistent + )) +print(f" [x] Sent {message}") +connection.close() \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/lesson2/worker.py b/chernyshov_nikita_lab_4/lesson2/worker.py new file mode 100644 index 0000000..34cb8f7 --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson2/worker.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +import pika +import time + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.queue_declare(queue='task_queue', durable=True) +print(' [*] Waiting for messages. To exit press CTRL+C') + + +def callback(ch, method, properties, body): + print(f" [x] Received {body.decode()}") + time.sleep(body.count(b'.')) + print(" [x] Done") + ch.basic_ack(delivery_tag=method.delivery_tag) + + +channel.basic_qos(prefetch_count=1) +channel.basic_consume(queue='task_queue', on_message_callback=callback) + +channel.start_consuming() \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/lesson3.png b/chernyshov_nikita_lab_4/lesson3.png new file mode 100644 index 0000000..8e8a3c2 Binary files /dev/null and b/chernyshov_nikita_lab_4/lesson3.png differ diff --git a/chernyshov_nikita_lab_4/lesson3/emitlog.py b/chernyshov_nikita_lab_4/lesson3/emitlog.py new file mode 100644 index 0000000..45b6989 --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson3/emitlog.py @@ -0,0 +1,13 @@ +import pika +import sys + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', exchange_type='fanout') + +message = ' '.join(sys.argv[1:]) or "info: Hello World!" +channel.basic_publish(exchange='logs', routing_key='', body=message) +print(f" [x] Sent {message}") +connection.close() \ No newline at end of file diff --git a/chernyshov_nikita_lab_4/lesson3/receivelogs.py b/chernyshov_nikita_lab_4/lesson3/receivelogs.py new file mode 100644 index 0000000..60d881d --- /dev/null +++ b/chernyshov_nikita_lab_4/lesson3/receivelogs.py @@ -0,0 +1,22 @@ +import pika + +connection = pika.BlockingConnection( + pika.ConnectionParameters(host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='logs', exchange_type='fanout') + +result = channel.queue_declare(queue='', exclusive=True) +queue_name = result.method.queue + +channel.queue_bind(exchange='logs', queue=queue_name) + +print(' [*] Waiting for logs. To exit press CTRL+C') + +def callback(ch, method, properties, body): + print(f" [x] {body}") + +channel.basic_consume( + queue=queue_name, on_message_callback=callback, auto_ack=True) + +channel.start_consuming() \ No newline at end of file diff --git a/chernyshov_nikita_lab_5/README.md b/chernyshov_nikita_lab_5/README.md new file mode 100644 index 0000000..6801207 --- /dev/null +++ b/chernyshov_nikita_lab_5/README.md @@ -0,0 +1,58 @@ +# Лабораторная работа 5: Умножение матриц + +## Описание + +**Цель работы** – реализовать и сравнить производительность последовательного и параллельного алгоритмов умножения матриц на больших массивах данных. + +### Задачи: +1. Разработать последовательный алгоритм умножения матриц. +2. Реализовать параллельный алгоритм с возможностью настройки числа потоков. +3. Провести тестирование обоих подходов на матрицах размером 100x100, 300x300 и 500x500. +4. Выполнить анализ производительности, изучив зависимость времени выполнения от размера матриц и количества потоков, и сформулировать выводы. + +## Теоретическое обоснование + +Операция умножения матриц широко применяется в задачах вычислительного характера, таких как обработка изображений, машинное обучение и физическое моделирование. Сложность умножения матриц размером +N×N составляет O(N^3), что приводит к резкому росту времени вычислений с увеличением размера матриц. Для ускорения работы можно использовать параллельные алгоритмы, распределяющие вычисления между несколькими потоками. + +## Реализация + +1. **Последовательный алгоритм:** Реализован в модуле sequential.py. Алгоритм вычисляет каждый элемент результирующей матрицы поэлементно, складывая произведения соответствующих элементов строк и столбцов исходных матриц. + +2. **Параллельный алгоритм:** Представлен в модуле parallel.py. Он использует многопоточность, разделяя вычисления на несколько потоков, где каждый поток обрабатывает определённый блок строк результирующей матрицы. Пользователь может задавать количество потоков для оптимизации производительности с учётом размера матриц и доступных ресурсов. + +## Результаты тестирования + +Тестирование проводилось на матрицах размером 100x100, 300x300 и 500x500 с различным числом потоков. Было проанализировано влияние количества потоков на производительность алгоритма. + +## Скриншоты результатов + +### Результат бенчамарка при 1 потоке: +![img1.png](img1.png) + +### Результат бенчамарка при 2 потоках: +![img2.png](img2.png) + +### Результат бенчамарка при 4 потоках: +![img3.png](img3.png) + +### Результат бенчамарка при 8 потоках: +![img4.png](img4.png) + +## Выводы + +1. **Эффективность параллельного алгоритма**: Использование многопоточности в параллельном алгоритме показало значительное ускорение по сравнению с последовательным методом, особенно на матрицах больших размеров. Например, для матриц размером 500x500 параллельный алгоритм с 4 потоками оказался более чем вдвое быстрее последовательного. + +2. **Влияние количества потоков**: Увеличение числа потоков сокращает время выполнения, но этот эффект ограничен. Для небольших матриц (100x100) использование более 2 потоков практически не улучшает производительность. На матрицах среднего и большого размера (300x300 и 500x500) оптимальный результат достигался при использовании 4 потоков, так как это позволяло равномерно распределить вычислительную нагрузку. + +3. **Закономерности и ограничения**: Эффективность параллельного умножения матриц ограничена накладными расходами на управление потоками. Для небольших задач эти расходы могут нивелировать преимущества параллелизации. Однако на больших данных задача лучше масштабируется, что делает параллельный подход значительно более выгодным. + +4. **Рекомендации по использованию**: Для работы с большими матрицами в реальных задачах рекомендуется использовать параллельные алгоритмы, подбирая оптимальное число потоков в зависимости от объёма задачи и доступных вычислительных ресурсов. + +## Заключение + +Выполнение лабораторной работы показало, что параллельные алгоритмы значительно ускоряют умножение матриц на больших данных. Однако для достижения максимальной эффективности важно учитывать размер задачи и оптимально выбирать количество потоков. Полученные результаты подтверждают, что параллельный подход предпочтителен для работы с крупными матрицами, тогда как для небольших задач затраты на управление потоками могут свести его преимущества на нет. + +## Видео + +https://vkvideo.ru/video286865610_456239228?list=ln-RciNpMoyWby0uMIZoa \ No newline at end of file diff --git a/chernyshov_nikita_lab_5/benchmark.py b/chernyshov_nikita_lab_5/benchmark.py new file mode 100644 index 0000000..7aa0c07 --- /dev/null +++ b/chernyshov_nikita_lab_5/benchmark.py @@ -0,0 +1,27 @@ +import time +import random +from matrix_multiplication.sequential import matrix_multiply_sequential +from matrix_multiplication.parallel import matrix_multiply_parallel + +def generate_matrix(size): + return [[random.randint(0, 10) for _ in range(size)] for _ in range(size)] + +def benchmark(matrix_size, num_threads): + A = generate_matrix(matrix_size) + B = generate_matrix(matrix_size) + + start = time.time() + matrix_multiply_sequential(A, B) + sequential_time = time.time() - start + + start = time.time() + matrix_multiply_parallel(A, B, num_threads) + parallel_time = time.time() - start + + print(f"Размер матрицы: {matrix_size}x{matrix_size}") + print(f"Последовательное время: {sequential_time:.5f} сек") + print(f"Параллельное время ({num_threads} потоков): {parallel_time:.5f} сек") + +if __name__ == "__main__": + for size in [100, 300, 500]: + benchmark(size, num_threads=8) diff --git a/chernyshov_nikita_lab_5/img1.png b/chernyshov_nikita_lab_5/img1.png new file mode 100644 index 0000000..00b4f2b Binary files /dev/null and b/chernyshov_nikita_lab_5/img1.png differ diff --git a/chernyshov_nikita_lab_5/img2.png b/chernyshov_nikita_lab_5/img2.png new file mode 100644 index 0000000..e40dafd Binary files /dev/null and b/chernyshov_nikita_lab_5/img2.png differ diff --git a/chernyshov_nikita_lab_5/img3.png b/chernyshov_nikita_lab_5/img3.png new file mode 100644 index 0000000..aa4d45e Binary files /dev/null and b/chernyshov_nikita_lab_5/img3.png differ diff --git a/chernyshov_nikita_lab_5/img4.png b/chernyshov_nikita_lab_5/img4.png new file mode 100644 index 0000000..1242ac8 Binary files /dev/null and b/chernyshov_nikita_lab_5/img4.png differ diff --git a/chernyshov_nikita_lab_5/matrix_multiplication/parallel.py b/chernyshov_nikita_lab_5/matrix_multiplication/parallel.py new file mode 100644 index 0000000..7bf60a0 --- /dev/null +++ b/chernyshov_nikita_lab_5/matrix_multiplication/parallel.py @@ -0,0 +1,21 @@ +from concurrent.futures import ThreadPoolExecutor + +def matrix_multiply_parallel(A, B, num_threads=1): + n = len(A) + result = [[0] * n for _ in range(n)] + + def worker(start, end): + for i in range(start, end): + for j in range(n): + result[i][j] = sum(A[i][k] * B[k][j] for k in range(n)) + + chunk_size = n // num_threads + with ThreadPoolExecutor(max_workers=num_threads) as executor: + futures = [ + executor.submit(worker, i * chunk_size, (i + 1) * chunk_size) + for i in range(num_threads) + ] + for future in futures: + future.result() + + return result diff --git a/chernyshov_nikita_lab_5/matrix_multiplication/sequential.py b/chernyshov_nikita_lab_5/matrix_multiplication/sequential.py new file mode 100644 index 0000000..f4f3daa --- /dev/null +++ b/chernyshov_nikita_lab_5/matrix_multiplication/sequential.py @@ -0,0 +1,9 @@ +def matrix_multiply_sequential(A, B): + n = len(A) + result = [[0] * n for _ in range(n)] + + for i in range(n): + for j in range(n): + result[i][j] = sum(A[i][k] * B[k][j] for k in range(n)) + + return result diff --git a/chernyshov_nikita_lab_6/README.md b/chernyshov_nikita_lab_6/README.md new file mode 100644 index 0000000..73c78e6 --- /dev/null +++ b/chernyshov_nikita_lab_6/README.md @@ -0,0 +1,36 @@ +# Лабораторная работа 6: Определение детерминанта матрицы с помощью параллельных вычислений + +## Описание + +В лабраторной работе программа вычисляет определитель матрицы двумя способами: параллельным методом с использованием нескольких процессов и последовательным методом, а также сравнивает их производительность. Функция determinant_block вычисляет детерминант переданного блока матрицы с помощью функции np.linalg.det из библиотеки NumPy. Функция determinant_parallel разделяет исходную матрицу на блоки (строго по строкам и столбцам) в зависимости от количества процессов, заданного аргументом num_processes. После этого каждый блок обрабатывается отдельным процессом в пуле процессов (Pool), и вычисленные детерминанты блоков перемножаются, чтобы получить общий детерминант матрицы. Функция benchmark генерирует случайную квадратную матрицу заданного размера, измеряет время выполнения параллельного и последовательного вычисления детерминанта, а затем выводит результаты. Основная часть программы запускается, если файл выполняется напрямую. Используется модуль argparse для получения аргумента командной строки --processes, который задает количество процессов для параллельного вычисления (по умолчанию 4). В цикле for функция benchmark выполняется для матриц размеров 100x100, 300x300 и 500x500, сравнивая производительность последовательного и параллельного подходов. + +## Результаты + +В процессе тестирования были получены следующие результаты: + +### Скриншоты результатов + +#### Результат бенчамарка при 1 процессе: +![img1.png](img1.png) + +#### Результат бенчамарка при 2 процессах: +![img2.png](img2.png) + +#### Результат бенчамарка при 3 процессах: +![img3.png](img3.png) + +#### Результат бенчамарка при 4 процессах: +![img4.png](img4.png) + + + +## Выводы + +1. **Производительность**: Для небольших матриц (например, 100x100) параллельное вычисление демонстрирует замедление по сравнению с последовательным методом из-за накладных расходов на создание и управление процессами. + +2. **Эффективность**: С увеличением размера матриц (300x300 и 500x500) время выполнения параллельного алгоритма также растёт, что свидетельствует о снижении его эффективности при использовании большего числа процессов. В некоторых тестах, например, для матрицы 500x500 при использовании 3 и 4 процессов, параллельный алгоритм оказался медленнее последовательного. + + + +## Ссылка на видео +https://vkvideo.ru/video286865610_456239229?list=ln-59QwPscwM3KZRLxg1E \ No newline at end of file diff --git a/chernyshov_nikita_lab_6/application.py b/chernyshov_nikita_lab_6/application.py new file mode 100644 index 0000000..384ff55 --- /dev/null +++ b/chernyshov_nikita_lab_6/application.py @@ -0,0 +1,50 @@ +import numpy as np +from multiprocessing import Pool +import time +import argparse + + +def determinant_block(matrix_block): + return np.linalg.det(matrix_block) + + +def determinant_parallel(matrix, num_processes): + size = matrix.shape[0] + step = size // num_processes + + blocks = [] + for i in range(num_processes): + start_row = i * step + end_row = start_row + step if i < num_processes - 1 else size + blocks.append(matrix[start_row:end_row, start_row:end_row]) + + pool = Pool(processes=num_processes) + dets = pool.map(determinant_block, blocks) + pool.close() + pool.join() + + return np.prod(dets) + + +def benchmark(size, num_processes): + matrix = np.random.rand(size, size) + + start = time.time() + det_parallel = determinant_parallel(matrix, num_processes) + end = time.time() + print(f"Матрица {size}x{size} с {num_processes} процессами заняла {end - start:.5f} сек (Параллельно)") + + start = time.time() + det_seq = determinant_block(matrix) + end = time.time() + print(f"Матрица {size}x{size} последовательный вычисление заняло {end - start:.5f} сек (Последовательно)") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Вычисление детерминанта с параллельной обработкой") + parser.add_argument("--processes", type=int, default=4) + args = parser.parse_args() + + sizes = [100, 300, 500] + for size in sizes: + benchmark(size, args.processes) diff --git a/chernyshov_nikita_lab_6/img1.png b/chernyshov_nikita_lab_6/img1.png new file mode 100644 index 0000000..2222439 Binary files /dev/null and b/chernyshov_nikita_lab_6/img1.png differ diff --git a/chernyshov_nikita_lab_6/img2.png b/chernyshov_nikita_lab_6/img2.png new file mode 100644 index 0000000..539af97 Binary files /dev/null and b/chernyshov_nikita_lab_6/img2.png differ diff --git a/chernyshov_nikita_lab_6/img3.png b/chernyshov_nikita_lab_6/img3.png new file mode 100644 index 0000000..9f0c841 Binary files /dev/null and b/chernyshov_nikita_lab_6/img3.png differ diff --git a/chernyshov_nikita_lab_6/img4.png b/chernyshov_nikita_lab_6/img4.png new file mode 100644 index 0000000..2a11f58 Binary files /dev/null and b/chernyshov_nikita_lab_6/img4.png differ diff --git a/chernyshov_nikita_lab_7/README.md b/chernyshov_nikita_lab_7/README.md new file mode 100644 index 0000000..091a798 --- /dev/null +++ b/chernyshov_nikita_lab_7/README.md @@ -0,0 +1,27 @@ +# Лабораторная работа 7: Балансировка нагрузки в распределённых системах при помощи открытых технологий на примерах + +### Задание +Написать небольшое эссе (буквально несколько абзацев) своими словами (пожалуйста не пользуйтесь гуглом :). + +  1. Какие алгоритмы и методы используются для балансировки нагрузки? + +  2. Какие открытые технологии существуют для балансировки нагрузки? + +  3. Как осуществляется балансировка нагрузки на базах данных? + +  4. Реверс-прокси как один из элементов балансировки нагрузки. +*** + +# Эссе: + +## **Балансировка нагрузки в распределённых системах** + +**Балансировка нагрузки** — это способ распределить работу между серверами так, чтобы система не тормозила, даже если пользователей или задач становится много. Чтобы всё работало плавно, используются разные алгоритмы. Например, Round Robin, где запросы распределяются по серверам по очереди, или алгоритмы, которые выбирают самый свободный сервер. Такие штуки помогают не перегружать систему, особенно когда нагрузки становится больше. + +Сейчас есть много готовых инструментов, которые помогают с этим справляться, например, NGINX, HAProxy и другие. Они автоматически берут на себя задачу распределения запросов, чтобы каждый сервер получал свою долю нагрузки. Это удобно, потому что самому разбираться с этим с нуля было бы долго и сложно. + +Если речь идёт о базах данных, то там балансировка ещё важнее, потому что базы всегда под большой нагрузкой. Чтобы ускорить работу, данные либо разбивают на части (шарды), либо делают копии (реплики). Это позволяет, например, отправлять запросы на чтение в одну копию, а на запись — в другую, чтобы сервера не загружались одновременно всем подряд. + +**Реверс-прокси** — это важный элемент балансировки. Он как посредник: принимает запросы от пользователей и перенаправляет их на нужные сервера. Но на этом его роль не заканчивается. Реверс-прокси может также кэшировать часто запрашиваемые данные, сжимать их для ускорения передачи и даже защищать систему от перегрузок, например, от DDoS-атак. + +Всё это делает систему устойчивой и помогает ей работать быстрее. Балансировка — это, по сути, способ справляться с увеличением нагрузки без потери производительности и стабильности. \ No newline at end of file diff --git a/chernyshov_nikita_lab_8/README.md b/chernyshov_nikita_lab_8/README.md new file mode 100644 index 0000000..c2ec904 --- /dev/null +++ b/chernyshov_nikita_lab_8/README.md @@ -0,0 +1,29 @@ +# Лабораторная работа 8. Как Вы поняли, что называется распределенной системой и как она устроена? + +## Задание +Написать небольшое эссе (буквально несколько абзацев) своими словами (пожалуйста не пользуйтесь гуглом :) на тему "Устройство распределенных систем". + +  1. Зачем сложные системы (например, социальная сеть ВКонтакте) пишутся в "распределенном" стиле, где каждое отдельное приложение (или сервис) функционально выполняет только ограниченный спектр задач? + +  2. Для чего были созданы системы оркестрации приложений? Каким образом они упрощают / усложняют разработку и сопровождение распределенных систем? + +  3. Для чего нужны очереди обработки сообщений и что может подразумеваться под сообщениями? + +  4. Какие преимущества и недостатки распределенных приложений существуют на Ваш взгляд? + +  5. Целесообразно ли в сложную распределенную систему внедрять параллельные вычисления? Приведите примеры, когда это действительно нужно, а когда нет. +*** + +# Эссе: + +## **Что называется распределенной системой и как она устроена** + +**Распределённые системы** создаются, чтобы справляться с большим количеством задач и пользователей, не теряя в производительности. Например, если взять социальную сеть вроде ВКонтакте, то там есть сообщения, новости, фото, видео и многое другое. Чтобы всё это работало быстро, каждую задачу обрабатывает отдельный сервис. Один сервис отвечает за отправку сообщений, другой — за хранение фото, третий — за рекомендации. Это позволяет системе быть масштабируемой: если нагрузка на какой-то конкретный сервис растёт, его можно отдельно усилить, не трогая остальные. + +Системы оркестрации, такие как **Kubernetes**, помогают управлять распределёнными приложениями. Они автоматизируют запуск, мониторинг и масштабирование сервисов, что сильно упрощает жизнь разработчиков и администраторов. Вместо того чтобы вручную следить за каждым сервисом, оркестратор сам запускает нужное количество экземпляров, распределяет их по серверам и перезапускает, если что-то пошло не так. Но есть и обратная сторона: освоение таких систем требует времени и опыта, что может усложнить начальную разработку. + +Очереди обработки сообщений — это инструмент, который помогает сервисам взаимодействовать друг с другом. Представьте, что один сервис должен отправить задачу другому, но тот пока занят. В этом случае задача помещается в очередь и ждёт своей обработки. Сообщениями может быть всё, что угодно: от запроса на отправку письма до информации о новом заказе в интернет-магазине. Очереди делают системы более устойчивыми, потому что даже при перегрузке задачи не теряются. + +У распределённых приложений есть как плюсы, так и минусы. Среди плюсов — высокая надёжность (если один сервис выйдет из строя, остальные продолжат работать), лёгкость масштабирования и возможность использовать разные технологии для каждого сервиса. Минусы — это сложность разработки и сопровождения, а также необходимость мониторинга и обеспечения безопасности всех частей системы. + +**Параллельные вычисления** в сложных распределённых системах часто необходимы. Например, при обработке большого объёма данных, как в системах рекомендаций или аналитике, где параллельные алгоритмы ускоряют процесс. Однако для простых задач, вроде проверки логина и пароля, параллельность может быть избыточной и усложнить систему без реальной выгоды. Всё зависит от того, какую именно задачу нужно решить. \ No newline at end of file