Хранение данных приложения #

Васильев Андрей Михайлович, 2024

Версии презентации

Архитектура приложения #

diagram

Жёлтым обозначены физические (виртуальные) машины, зелёным — составляющие веб-приложения, синим — важные компоненты системы

  • Веб-сервер обслуживает множество клиентов
  • Клиентам необходимо множество документов, для получения которых выполняется несколько HTTP-запросов
  • HTML-документ с данными для отображения
  • CSS-документы с описанием классов для стилизации HTML
  • JS-документы для выполнения динамических действий на стороне клиента
  • Для формирования документов серверу недостаточно данных, которые хранятся в его оперативной памяти
  • Необходимо обратиться к хранилищу данных (СУБД или другая система хранения) за динамическими данными: список товаров, их количество, данные пользователя
  • Необходимо обратиться к внутренним ресурсам для получения статической информации: CSS/JS-документы, шаблоны страниц
  • Клиентам необходимо обратиться за документами, которые были загружены или сформированы приложением: изображения, архивы, PDF-документы

Максимальное использование локальных ресурсов #

diagram

  • Современные системы предоставляют множество процессоров, способных независимо друг от друга обрабатывать данные
  • HTTP-запросы легко обрабатывать на нескольких потоках, т.к. каждый запрос не зависит от других запросов
  • HTTP-сервера обычно запускают множество процессов (и потоков), которые используют разные процессоры
  • Потоки имеют доступ к общим данным:
    • Файловая система
    • Ресурсы приложения
    • Данные в оперативной памяти
  • Для изменяемых данных необходимо аккуратно подходить к задаче редактирования общих данных: данные в оперативной памяти и на файловой системе
  • Библиотека http4k по умолчанию запускает несколько процессов

Балансировка запросов между компьютерами #

diagram

  • Для обработки большого числа запросов от клиентов мощностей одного компьютера может не хватать
  • Можно организовать обработку запросов с помощью множества одинаковых приложений, запущенных на нескольких компьютерах
  • Выводы из данной архитектуры:
    • Файловая система не может служить подходящим средством для хранения общих бинарных данных
    • Все данные приложения должны находится в единых системах хранения: кластере СУБД-серверов, серверах хранения больших данных и т.д.
    • Приложение должно считывать конфигурацию из сетевой службы.
    • Невозможно организовать доступ к общим данным в оперативной памяти, необходимо использовать специализированные инструменты
  • При разработке локального приложения стоит изначально рассматривать сложности перехода к запуску нескольких приложений на нескольких серверах

Локальные данные приложения #

Рассмотрим следующие источники данных, доступные JVM-приложениям:

  • Ресурсы приложения
  • Файловая система

Общие свойства #

  • Предоставляют данные в виде файлов
  • Предоставляют данные в иерархической структуре каталогов
  • Для построения путей к файлам можно использовать абсолютные и относительные пути

Отличия #

  • Данные внутри ресурсов доступны только на чтение
  • Ресурсы поставляются вместе с исполняемым кодом приложения
  • Файлы поставляются отдельно
  • Абсолютные пути внутри ресурсов будут работать на любом компьютере для файлов стоит использовать относительные

Работа с данными без СУБД #

СУБД решает много вопросов разработки веб-приложений: проблемы надёжного хранения данных, проблемы совместного доступа, проблемы управления большим объёмом данных

Без СУБД будем считывать и записывать все данные приложения с файловой системы

  1. При старте приложение считывает информацию из файловой системы
  2. Во время работы приложение изменяет данные в оперативной памяти
  3. При завершении работы приложение сохраняет данные на файловую систему

Ключевые проблемы:

  • Возникновение коллизий в данных в оперативной памяти в случае редактирования в нескольких потоках
  • Надёжное сохранение данных в случае завершения работы приложения (приложению могут не дать корректно завершить работу)

Жизненный цикл JVM-приложения #

  1. Создаётся процесс внутри операционной системы, в рамках которой работает первый JVM-процесс
  2. Запускается функция main(), порождающая множество JVM-процессов
  3. По завершении работы последнего JVM-процесса выполняется вызов обработчиков завершения работы
  4. После выполнения всех задач по обработке запроса основной процесс ОС завершает свою работу

Жизненный цикл 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)
  • Автоматическое выполнение обработчика остановки приложения

Такое приложение также корректно будет обрабатывать сигнал остановки