Базовый проект для практики по курсу "Программная инженерия больших данных".
Здесь находятся решения команды Charmed BDSE fans в составе:
- Лапшин Дмитрий (@LDVSOFT),
- Валин Глеб (@the7winds),
- Третьякова Елизаветта (@LizaTretyakova).
-
Структура приложения несколько разнесена, чтобы можно было запускать Spring Boot приложение с выбранной реализацией хранилища с помощью профилей. В данный момент профилей два:
in-memory
: хранилище в памяти из предоставленного кода.postgres
: хранилище на основе СУБД PostgreSQL, связка с которым осуществляется на основе Spring Data и JPA.
-
Несмотря на название
PostgresKeyValueApi
, возможно расширение реализации на любую другую базу, с которой можно связать JPA: в решении не используется SQL. -
Сама нода пакуется в контейнер
charmed-bdse-fans/bdse-node
. -
В следствие реализации выше, приложение ожидает, что необходимая СУБД будет уже запущена к моменту запуска приложения. Для запуска всего приложения потребуется, например, Docker Compose (см.
in-memory-docker-compose.yaml
иpostgres-docker-compose.yaml
). -
В тестах применяются следующие подходы:
- запуск базы данных с помощью
@ClassRule
, с последующим локальным поднятиемSpringRunner
ом всего необходимого контекста приложения, подключающегося к этой базе; - запуск приложения и его базы данных в отдельных контейнерах, само тестирование
идёт через REST API (
KeyValueApiHttpClient
).
В силу такой архитектуры, команд выше хватает для корректного запуска всех тестов.
- запуск базы данных с помощью
- Мы реализовали API про включение-выключение ноды заглушечно, поскольку по нашей архитектуре приложение не управляет базой данных. Мы считаем, что оно возымеет смысл при реализации кластерного взаимодействия.
- Возникла проблема реализации теста персистентности хранения, поскольку для этого нужно запустить приложение, убить и перезапустить на тех же данных. Для этого достаточно при создании БД указать подключаемый носитель (volume), но выставляемый библиотекой testcontainers API несколько скуден, и мы вместе (по крайней мере, на данный момент) не смогли через него надёжно выразить желаемые операции.
Данные хранятся в формате json
(см. пример ниже), при этом первая версия приложения работает только с первыми тремя полями и не знает о существовании extension
, вторая версия приложения работает с полным вариантом.
{
'first name': 'John',
'second name': 'Doe',
'phone': +79211234567,
'extension': {
'nickname': 'SomeAweSomeNickName',
'phones': ['666666',],
}
}
Эти данные хранятся в основной таблице. Также для поддержания поиска по отношению 'фамилии / никнеймы -- телефоны' (many-to-many
) создаются таблицы индексов фамилия-id
и никнейм-id
.
Пользователь общается с приложением через клиент PhoneBookHttpClient
(для каждой версии приложения сделана своя реализация, хотя основная функцияональность
реализована в общем базовом классе), который форвардит запросы уже непосредственно
KeyValuePhoneBookApi
, работающему с базой данных.
Реализованы KeyValueApi c разрешением конфликтов по timestamp.
KVApi теперь обращается всегда к координируемому интерфейсу, который затем пробрасывает
запросы к репликам через /internal/
KeyValueApi.
Для запуска конфигруации используется Spring-профиль kvnode-coordinated
, который при включении
оборачивает настроенное другими профилями KeyValueApi до скоординированного, используя
свойства kvnode.coordination.{rcl,wcl,timeout,remoets}
. При этом сохраняется возможность
запуска координатора как лидера: достаточно не указывать профиль,
локального хранилища не будет, указываем только удалённые реплики.
Для удобной реализации координатора очень не хвататло Java 9 с её CompletableFuture.orTimeout
.
По API скоординированное API вернёт в том числе удалённые ключи, что ломает один тест, пришлось воткнуть игнорирование.
Реализовано PartitionedKeyValueApi, который по большому счёту проксирует все запросы на нужные шарды. Релизованы тесты с in-memory storage. Старый клиент был нормальным, поэтому новый добавлять не пришлось.
Не обнаружены