Skip to content
 
 

Repository files navigation

2026-home-work

Build Status Code Style Check Codacy Badge

Домашние задание курса "Распределенные вычисления" 2026 года

Задание 1. HTTP API + хранилище (deadline 1 неделя)

Fork

Форкните проект, склонируйте и добавьте upstream:

$ git clone git@github.com:<username>/2026-home-work.git
Cloning into '2026-home-work'...

...

$ git remote add upstream git@github.com:vk-edu-distrib-compute/2026-home-work.git
$ git fetch upstream
From github.com:vk-edu-distrib-compute/2026-home-work
 * [new branch]      master     -> upstream/master

Test

Так можно запустить тесты:

$ ./gradlew check

Run

А вот так -- сервер:

$ ./gradlew run

Code style checks

$ ./gradlew codeStyleChecks

Develop

Откройте в IDE -- OpenIDE нам будет достаточно.

ВНИМАНИЕ! При запуске тестов или сервера в IDE необходимо передавать Java опцию -Xmx128m.

В своём Java package company.vk.edu.distrib.compute.<username> реализуйте интерфейс KVService и поддержите следующий HTTP REST API протокол:

  • HTTP GET /v0/status -- 200 в нормальной ситуации, 503 в случае проблем.
  • HTTP GET /v0/entity?id=<ID> -- получить данные по ключу <ID>. Возвращает 200 OK и данные или 404 Not Found.
  • HTTP PUT /v0/entity?id=<ID> -- создать/перезаписать (upsert) данные по ключу <ID>. Возвращает 201 Created.
  • HTTP DELETE /v0/entity?id=<ID> -- удалить данные по ключу <ID>. Возвращает 202 Accepted.
  1. Сделать наследника KVServiceFactory в пакете со своим именем/ником.
  2. Ваша реализация интерфейса KVService, возвращаемая из KVServiceFactory, должна запускать HttpServer из JDK.
  3. Ваш KVService должен работать с вашей же реализацией интерфейса Dao и делегировать непосредственную работу с данными хранилища.
  4. В минимальной реализации Dao достаточно хранить данные в памяти. Для первого этапа T в Dao будет byte[].
  5. Добавить своего наследника KVServiceFactory в поле KVServiceFactoryArgumentsProvider.factories

Продолжайте запускать тесты и исправлять ошибки, не забывая подтягивать новые тесты и фиксы из upstream. Если заметите ошибку в upstream, заводите баг и присылайте pull request ;)

Report

Когда всё будет готово, присылайте pull request со своей реализацией на review. Не забывайте отвечать на комментарии в PR и исправлять замечания!

Bonus tasks

Persistent Dao

Cделать Dao, хранящие данные на файловой системе. Если сделали так, напишите коммент об этом к своему PR'у.

Load test

Проведите нагрузочное тестирование с помощью wrk в одно соединение:

  • PUT запросами на стабильной нагрузке (wrk должен обеспечивать заданный с помощью -R rate запросов) наполните базу
  • GET запросами на стабильной нагрузке по наполненной БД
  1. wrk2 можно собрать из исходников, взять в вашем дистре линукса или взять готовый докер, например тут
  2. Для докера инструкция запуска wrk есть прямо по ссылке, помните, что в случае докера надо указать IP вашего сетевого интерфейса созданного докером (обычно это docker0), а не просто localhost
  3. Запускайте со след. параметрами -t1 -c1 -R200 -d30s --latency -s /data/request.lua
  4. Сохраните выведенную статистику (начинается после строчки Detailed Percentile spectrum:) в файл и отобразите здесь
  5. Скрины графиков (PUT, GET, кнопка Export Image на сайте) надо приложить к вашему PR'у

Задание 2. Шардирование

Реализуем горизонтальное масштабирование через поддержку кластерных конфигураций, состоящих из нескольких узлов, взаимодействующих друг с другом через реализованный HTTP API.

Sharding. Test

Так можно запустить тесты:

./gradlew check

Sharding. Run

Запустить сервер в режиме кластера:

./gradlew run --args="cluster"

Sharding. Code style checks

/gradlew codeStyleChecks

Sharding. Develop

  • Кластер распределяет ключи между узлами детерминированным образом.

  • В кластере хранится только одна копия данных.

  • Нода, получившая запрос, проксирует его на узел, отвечающий за обслуживание соответствующего ключа.

  • Таким образом, общая ёмкость кластера равна суммарной ёмкости входящих в него узлов.

  • Реализуйте один из алгоритмов распределения данных между узлами, например, consistent hashing, rendezvous hashing.

  • Используйте свою реализацию KVCluster и KVClusterFactory

  • В качестве хранилища можете либо переиспользовать созданные в первом задании, либо добавить реализацию dao с использованием h2

Sharding. Report

Когда всё будет готово, присылайте pull request со своей реализацией на review. Не забывайте отвечать на комментарии в PR и исправлять замечания!

Sharding. Bonus tasks

Sharding. Additional algorithm

Реализуйте ещё один алгоритм распределения данных. Например, если в основном задании сделали через rendezvous hashing, сделайте через consistent hashing и наоборот.

Sharding. Load test

  • Провести нагрузочное тестирование с помощью wrk2 на распределенный кластер с большим количеством соединений >= 64
  • Запускайте со след. параметрами -t2 -c100 -R200 -d30s --latency -s /data/request.lua
  • Сравнить с предыдущей (монолитной/не распределенной) версией.
  • Результаты и анализ сравнения приложить к PR.

Задание 3. Репликация

Серверная часть

  • В сервис KVService или KVCluster добавить поддержку хранения нескольких копий данных для каждого ключа.
  • Можно реализовать существующий интерфейс ReplicatedService.
  • Фактор репликации n (количество узлов-реплик) настраивается при запуске сервиса (через CLI-аргумент, ENV-переменную или конфиг-файл).
  • В качестве узлов хранения допустимо использовать файлы на диске (по одному файлу на реплику/узел) или массив, где индекс -- это номер узла, а значение -- "узел" в виде хранилища в памяти.

API

  • Добавить query-параметр ack к эндпоинтам чтения/записи. Он определяет, какое число реплик должно успешно подтвердить операцию.
  • Обеспечить полную обратную совместимость с предыдущей версией API (запросы без ack должны обрабатываться корректно, с дефолтным поведением, например ack = 1).
Метод Поведение
GET /v0/entity?id=ID&ack=X Возвращать данные, если подтвердили ответ ≥ ack реплик. Если доступно меньше – возвращать 50x.
PUT /v0/entity?id=ID&ack=X
DELETE /v0/entity?id=ID&ack=X
Ждать подтверждений от ≥ ack реплик. При недоступности нужного числа – возвращать 50x.
Валидация Если ack > n, немедленно возвращать 400 Bad Request.

Интеграционный тест

Если сервис реализует интерфейс ReplicatedService, то основные сценарии можно проверить, запустив интеграционный тест ReplicationTest, который совместим с этим интерфейсом. Допускается написание собственного набора тестов.

Поведение

  • Множество узлов-реплик для конкретного ключа должно определяться детерминировано.
  • Значения по одному и тому же ключу всегда должны попадать на одни и те же реплики.
  • Реализовать корректную синхронизацию данных между репликами при записи/удалении.
  • Обеспечить graceful degradation: система должна корректно обрабатывать запросы при частичной недоступности реплик, соблюдая заданный уровень ack.

Отчёт

С помощью утилиты wrk провести нагрузочное тестирование и сравнить два сценария:

  • Режим с кворумом: ack_w + ack_r > n
  • Режим без кворума: ack_w + ack_r ≤ n Метрики для сравнения:
  • Время выполнения запросов (p50, p95, p99, RPS)
  • Процент актуальности/консистентности данных при чтении (например, доля запросов, вернувших последнюю записанную версию) Когда всё будет готово, присылайте pull request со своей реализацией на review. Не забывайте отвечать на комментарии в PR и исправлять замечания!

Бонусные задания (по желанию)

  • Параллельный I/O: Реализовать асинхронное/параллельное чтение и запись в файлы-реплики.
  • Сбор статистики: Добавить вспомогательные эндпоинты:
    • GET /stats/replica/{id} → количество ключей/данных в конкретной реплике
    • GET /stats/replica/{id}/access → частота обращений на чтение и запись

Допускается хранение статистики в памяти с периодическим сбросом или без него, если не указано иное.

Задание N. GRPC для внутреннего транспорта

Цель - переделать транспорт общения между нодами кластера на gRPC. Переделать нужно только внутренний транспорт, для общения с внешними клиентами транспорт должен остаться прежний - HTTP.

Серверная часть

  • Переделать ваши реализации KVService так, чтобы для проксирования запросов в другие ноды использовался gRPC.
  • Адреса нод кластера, которые возвращаются из KVCluster.getEndpoints, должны содержать информацию о порте, на котором запущен gRPC-сервер ноды. Пример: localhost:8080?grpcPort=9090. Это только пример, сделать можно как вам кажется лучше-удобнее. Так как это внутренние адреса - то внешним клиентам кластера понимать несущественные для них параметры не обязательно.
  • В остальном ничего измениться не должно, все интеграционные тесты должны работать как раньше.

API

  • Нужно разработать gRPC-апи в виде proto-файла способное передавать всю нужную информацию между нодами.
  • Серверные заглушки и gRPC-клиент будут сгенерированы автоматически на основе вашего proto-файла.
  • Не забудьте в вашем proto-файле указать своё имя пакета (сгенерированные файлы будут его использовать), чтобы не мешать другим участникам проекта.

Тесты

Каких-то особенных тестов пока не предполагается, старые должны все работать

Бонусное задание

С помощью утилиты wrk провести нагрузочное тестирование до переделки на HTTP и после и сравнить результаты:

  • На графике должно быть две линии - до и после
  • График должен отображать время выполнения запросов (p50, p95, p99, RPS)

Оценка

  • Основное задание - 8 балов
  • Бонусное - 2 бала

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages