Аналог приложения TikTok, Vk видео и YouTube Shorts. Часть 4
Всем привет!
Тут я подумал... а почему бы не рассказать о сервере? Предупреждаю сразу: будет много сложного и непонятного текста!
Немного о сервере
Сервер — это Maven-проект (кто понял, тот понял). Maven — это не просто фреймворк, а целая экосистема, которая включает в себя огромное количество инструментов. Он также выполняет роль сборщика.
Главный конфигурационный файл проекта — pom.xml. В него добавляются библиотеки, фреймворки и прочие зависимости. Помимо Spring Boot и его компонентов, я добавил:
PostgreSQL — база данных, в которой хранится огромное количество таблиц.
Firebase — гугловая библиотека для отправки сообщений.
OkHttp3 — для выполнения HTTP-запросов на сторонние сервисы, такие как Firebase и Яндекс.
Quartz Scheduler — для работы с таймерами. Раньше использовался для отслеживания времени жизни SMS.
Lombok — значительно упрощает код, убирая необходимость вручную писать геттеры и сеттеры.
Flyway — для управления миграциями базы данных. Например, при переносе на другой сервер или создании новой таблицы можно не писать SQL-запросы вручную, а просто выполнить команду, и Flyway сам всё сделает.
Hibernate — облегчает работу с базой данных, избавляя от необходимости писать SQL-запросы вручную и разбираться, почему что-то не работает из-за новой колонки или неправильного запроса.
Миграции
На данный момент у меня 36 миграций. Они включают в себя создание новых таблиц и обновление старых.
Первый блок — init: здесь просто инициализируется схема базы данных. Затем добавляются таблицы.
Структура проекта
В проекте есть несколько пакетов (или папок, кому как удобнее):
secure — всё, что связано с защитой: конфигурация, токены и прочее.
controllers — здесь находятся Java-классы-контроллеры. Каждому классу даю название по принципу функционал + Controller, например:
FileController — отвечает за работу с файлами.
MessageController — управляет обработкой сообщений.
Это основные моменты, остальные параметры можно считать стандартными.
DTO (Data Transfer Object) — объект передачи данных между клиентом и сервером.
По сути, у меня там всего один enum, который содержит две подкатегории:
Request — запрос
Response — ответ
Думаю, логика понятна: Request используется для отправки данных на сервер, а Response — для получения ответа.
Конечно, можно разбить это на несколько отдельных файлов для каждой категории, чтобы было проще искать нужные классы. Но пока такой структуры хватает.
Entity — таблицы для Hibernate
В проекте есть несколько Entity-классов, которые описывают структуру таблиц в базе данных.
Есть две абстрактные сущности:
AbstractEntity — содержит стандартные параметры, которые есть в каждой таблице:
id — первичный ключ
Переопределённые методы, такие как equals() и hashCode()
DatedEntity — расширяет AbstractEntity и добавляет два поля:
createdAt — время создания записи (например, когда был создан пользователь)
updatedAt — время последнего обновления записи (например, когда сообщение было прочитано)
Таким образом, сущности наследуются друг от друга:
➡ DatedEntity наследует AbstractEntity
➡ Другие классы наследуются от DatedEntity
В результате при создании новой таблицы мне не нужно каждый раз вручную добавлять id, createdAt и updatedAt — они уже есть в базовом классе. Удобно и меньше дублирования кода! 🚀
Repository — репозитории для работы с БД
Если просто, то для каждой таблицы создаётся свой репозиторий, в котором прописаны запросы к базе данных. У меня их 24, значит, и таблиц тоже 24.
В большинстве случаев Hibernate отлично справляется с работой, но иногда бывают ситуации, когда нужен сложный SQL-запрос, и тогда стандартных возможностей недостаточно. В таких случаях приходится писать запрос вручную.
Service — бизнес-логика приложения
Сервисные классы отвечают за взаимодействие между слоями приложения. Здесь происходит:
Взаимодействие с базой данных через репозитории
Взаимодействие между различными компонентами приложения
Логика обработки данных перед отправкой клиенту
Выполнение различных проверок и преобразований
По сути, сервисный слой — это мост между контроллерами и базой данных. В зависимости от ситуации в сервисах может быть простая логика или более сложные механизмы, например, кэширование, валидация данных или работа с внешними API.
Дополнительные моменты и распределение нагрузки
Думаю, основные вещи я описал, но есть ещё несколько дополнительных компонентов, которые взаимодействуют между собой.
Почему я не использую WebSocket?
Кто-то может спросить про WebSocket... но я его пока не реализовывал. Причина проста — текущее железо не потянет. Даже если в будущем будет более мощный сервер, всё равно есть ограничения на количество подключений к одному серверу.
К тому же WebSocket реально нужен только для отображения статуса "пользователь онлайн" (в моем случае). Но это излишняя нагрузка, которая мне не нужна.
Масштабирование сервера
Поскольку при хорошем раскладе нужен не один, а десятки серверов, я сразу проектирую приложение с возможностью множественного запуска на разных машинах и централизованной базой данных.
Я прикинул примерную архитектуру серверов:
Сервер мониторинга — отслеживает состояние всех остальных серверов.
Сервер бэкапов — отвечает за сохранение резервных копий данных.
Два сервера для видеозвонков — работаю над полноценной WebRTC-реализацией, без использования сторонних сервисов.
С первого взгляда это может показаться сложным и непонятным 🤯, но на самом деле всё логично и продумано. 🚀
Proxy и масштабируемость
Proxy будет равномерно распределять запросы между серверами. Их количество не ограничено, поскольку все они работают с одной базой данных. Таким образом, если нагрузка возрастёт, можно просто добавить новые серверы, и система продолжит работать без проблем.
То же самое касается серверов-хранилищ — их тоже можно масштабировать до бесконечности. Правда, используется принцип пара-зеркало: один сервер — основной, второй — резервный, на случай отказа основного.
Отдельные серверы для видеозвонков вынесены отдельно, чтобы они не занимали соединения на основных серверах. Количество подключений ограничено, поэтому такой подход позволяет сохранить баланс нагрузки.
Про видеозвонки расскажу подробнее позже, когда придет время и когда протестирую.
я тут подумал. оставлю свой телеграм для связи, мало ли, может какие нибудь предложения поступят. @ilyaPlotkin_vzhoohApp
Ну, как-то так. Всем спасибо за внимание! 🚀