Хранение данных приложения #
Васильев Андрей Михайлович, 2024
Версии презентации
Архитектура приложения #
Жёлтым обозначены физические (виртуальные) машины, зелёным — составляющие веб-приложения, синим — важные компоненты системы
- Веб-сервер обслуживает множество клиентов
- Клиентам необходимо множество документов, для получения которых выполняется несколько HTTP-запросов
- HTML-документ с данными для отображения
- CSS-документы с описанием классов для стилизации HTML
- JS-документы для выполнения динамических действий на стороне клиента
- Для формирования документов серверу недостаточно данных, которые хранятся в его оперативной памяти
- Необходимо обратиться к хранилищу данных (СУБД или другая система хранения) за динамическими данными: список товаров, их количество, данные пользователя
- Необходимо обратиться к внутренним ресурсам для получения статической информации: CSS/JS-документы, шаблоны страниц
- Клиентам необходимо обратиться за документами, которые были загружены или сформированы приложением: изображения, архивы, PDF-документы
Максимальное использование локальных ресурсов #
- Современные системы предоставляют множество процессоров, способных независимо друг от друга обрабатывать данные
- HTTP-запросы легко обрабатывать на нескольких потоках, т.к. каждый запрос не зависит от других запросов
- HTTP-сервера обычно запускают множество процессов (и потоков), которые используют разные процессоры
- Потоки имеют доступ к общим данным:
- Файловая система
- Ресурсы приложения
- Данные в оперативной памяти
- Для изменяемых данных необходимо аккуратно подходить к задаче редактирования общих данных: данные в оперативной памяти и на файловой системе
- Библиотека http4k по умолчанию запускает несколько процессов
Балансировка запросов между компьютерами #
- Для обработки большого числа запросов от клиентов мощностей одного компьютера может не хватать
- Можно организовать обработку запросов с помощью множества одинаковых приложений, запущенных на нескольких компьютерах
- Выводы из данной архитектуры:
- Файловая система не может служить подходящим средством для хранения общих бинарных данных
- Все данные приложения должны находится в единых системах хранения: кластере СУБД-серверов, серверах хранения больших данных и т.д.
- Приложение должно считывать конфигурацию из сетевой службы.
- Невозможно организовать доступ к общим данным в оперативной памяти, необходимо использовать специализированные инструменты
- При разработке локального приложения стоит изначально рассматривать сложности перехода к запуску нескольких приложений на нескольких серверах
Локальные данные приложения #
Рассмотрим следующие источники данных, доступные JVM-приложениям:
- Ресурсы приложения
- Файловая система
Общие свойства #
- Предоставляют данные в виде файлов
- Предоставляют данные в иерархической структуре каталогов
- Для построения путей к файлам можно использовать абсолютные и относительные пути
Отличия #
- Данные внутри ресурсов доступны только на чтение
- Ресурсы поставляются вместе с исполняемым кодом приложения
- Файлы поставляются отдельно
- Абсолютные пути внутри ресурсов будут работать на любом компьютере для файлов стоит использовать относительные
Работа с данными без СУБД #
СУБД решает много вопросов разработки веб-приложений: проблемы надёжного хранения данных, проблемы совместного доступа, проблемы управления большим объёмом данных
Без СУБД будем считывать и записывать все данные приложения с файловой системы
- При старте приложение считывает информацию из файловой системы
- Во время работы приложение изменяет данные в оперативной памяти
- При завершении работы приложение сохраняет данные на файловую систему
Ключевые проблемы:
- Возникновение коллизий в данных в оперативной памяти в случае редактирования в нескольких потоках
- Надёжное сохранение данных в случае завершения работы приложения (приложению могут не дать корректно завершить работу)
Жизненный цикл JVM-приложения #
- Создаётся процесс внутри операционной системы, в рамках которой работает первый JVM-процесс
- Запускается функция main(), порождающая множество JVM-процессов
- По завершении работы последнего JVM-процесса выполняется вызов обработчиков завершения работы
- После выполнения всех задач по обработке запроса основной процесс ОС завершает свою работу
Жизненный цикл http4k-приложения #
- Функция start() создаёт столько JVM-процессов, сколько есть процессоров в системе
- Во время инициализации приложения функции по созданию фильтров вызываются 1 раз на каждый процессор
- Есть функция stop(), которая завершит работу всех потоков
Написание обработчика завершения работы приложения #
public void addShutdownHook(Thread hook)
Обработчик завершения работы JVM-приложения — это объект, реализующий интерфейс Thread, который описывает отдельный поток выполнения
Kotlin предоставляет удобную функцию для создания объектов, реализующих поток:
fun thread(
start: Boolean = true,
...
block: () -> Unit
): Thread
- Аргумент
start
указывает надо ли сразу запускать данный поток на исполнение - Аргумент
block
содержит код, который надо выполнять в рамках потока
Обработчики остановки приложения не должны запускаться в момент создания, а в блоке кода должна находиться логика по сохранению данных
Это должно позволить приложению сохранять данные, которые пользователь ввёл за время работы с приложением
Ручная корректная остановка работы приложения #
Ввиду того, что обработчик завершения JVM-процесса может не всегда сработать (например при остановке приложения из IDEA в Windows), можно реализовать остановку приложения по отправке команды из командного интерфейса
- При старте приложения выполняется считывание данных в оперативную память
- Выполняется создание обработчиков HTTP-запроса
- Создание обработчика остановки JVM-процесса, чтобы можно было обработать остановку JVM-процесса
- Запуск HTTP-сервера и всех процессов-обработчиков
- Блокировка основного потока приложения на считывание данных из стандартного потока ввода
- Остановка сервера (данный шаг выполнится, если пользователь ввёл данные и нажал Enter)
- Автоматическое выполнение обработчика остановки приложения
Такое приложение также корректно будет обрабатывать сигнал остановки