Планируя работу над своим первым проектом, его владелец часто доподлинно не знает, как выстроить правильную архитектуру, какие функции и модули использовать и как настроить их взаимодействие между собой, а также где закладывать участие железа. А ведь ключ к повышению производительности, масштабируемости и долговечности любой системы лежит как раз в продуманной архитектуре.
О ней сегодня и поговорим. Разберем, что такое архитектура веб-приложений и почему она важна, расскажем о популярной сейчас архитектуре микросервисов, а также немного приоткроем завесу, как это работает у нас.
Этот материал пригодится начинающим разработчикам, администраторам и владельцам проектов, которые делают первые шаги на пути к своим первым проектам.
Итак, для начала – несколько слов о том, что вообще такое архитектура веб-приложений.
Архитектура веб-приложений – это подход к их созданию, проектированию и развертыванию. Она включает в себя такие элементы, как серверы приложений, базы данных, фреймворки, системы управления контентом и многое другое.
Почему архитектура – это важно
Сегодня, когда тенденции рынка постоянно меняются, а ожидания пользователей закономерно растут, при разработке веб-сервисов для их стабильности, гибкости, производительности и масштабируемости следует закладывать прочный фундамент – им и является архитектура современных веб-приложений. Непродуманная архитектура, подобно дому с плохо установленными сваями, может привести к тому, что приложение не сможет, например, эффективно справиться с нагрузками.
Архитектурные решения влияют на:
- стоимость разработки и поддержки – более сложная архитектура, которая включает множество компонентов, интеграций и технологий, как правило, требует больше времени и ресурсов на разработку, тестирование и развертывание;
- скорость внесения изменений в систему – например, использование микросервисной архитектуры позволяет быстро и легко вносить изменения в отдельные части системы без необходимости перекомпиляции всего приложения;
- производительность – кэширование, балансировка нагрузки и оптимизация базы данных влияют на скорость отклика и способность приложения справляться с нагрузками;
- безопасность – правильная архитектура предусматривает использование механизмов аутентификации и авторизации, шифрования данных и защиты от атак (например, сервис-ориентированная и микросервисная архитектура позволяют изолировать и защищать критически важные данные);
- пользовательский опыт – продуманная архитектура позволяет минимизировать количество запросов к серверу, обеспечить быструю загрузку веб-страниц и отзывчивость интерфейса
Принцип построения архитектуры веб-приложения
Архитектура веб-приложения может включать различные компоненты в зависимости от выбранной модели. Например, если речь идет о клиентской стороне (Frontend), которая отвечает за взаимодействие с пользователем и отображение данных, то она чаще всего реализуется с помощью HTML, CSS, JavaScript и вспомогательного ПО и скриптов, а если о серверной (Backend), обрабатывающей запросы от клиента, то среди компонентов – веб-сервер, язык программирования, фреймворки, библиотеки и различное ПО.
Разделить ответственность между компонентами приложения помогают слои архитектуры, для наглядности приведем примеры основных из них.
- Презентационный
Назначение: взаимодействие с пользователем и отображение данных
Компоненты: HTML/CSS, JavaScript, а также фреймворки и библиотеки React, Angular, Vue.js
Функции: отображение данных, полученных от серверной стороны, взаимодействие с сервером через HTTP-запросы - Логический
Назначение: выполнение операций
Компоненты: языки (программирование веб-приложений может включать использование Python, Java, JavaScript, Node.js, PHP, Ruby и т. д.), а также фреймворки (Django, Spring, Express, Laravel, Ruby on Rails)
Функции: обработка данных, полученных от презентационного слоя, выполнение бизнес-правил и взаимодействие с базой данных через слой доступа к данным - Слой доступа к данным
Назначение: взаимодействие с базой данных
Компоненты: базы данных: реляционные (MySQL, PostgreSQL) и нереляционные (MongoDB, Cassandra)
Функции: хранение и извлечение данных, поддержка транзакций - Инфраструктурный
Назначение: отвечает за технические аспекты работы приложения: развертывание, мониторинг, безопасность и управление ресурсами
Компоненты: веб-серверы (Apache, Nginx), контейнеризация (Docker), оркестрация контейнеров (Kubernetes), CI/CD-инструменты (Jenkins, GitHub Actions), а также решения для мониторинга и логирования (Prometheus, Grafana, ELK Stack)
Функции: обеспечение стабильности и надежности работы приложения, автоматизация процессов развертывания и обновления, мониторинг состояния и производительности системы
На первичном этапе планирование и разработка архитектуры веб-приложения могут предполагать использование графических элементов.
Например, схема архитектуры веб-приложения может включать:
- сервер приложения;
- веб-сервер;
- балансировщик нагрузки;
- сеть доставки контента;
- базы данных;
- сервисы кэширования.
Выбор слоев зависит от требований проекта – например, если речь идет о веб-приложениях с фронтендом, с вероятностью 99% задействованы будут все слои. В свою очередь, в зависимости от того, как логика приложения распределяется в клиент-серверной архитектуре веб-приложений, существуют разные ее типы.
Чтобы не слишком перегружать эту статью, остановимся поподробнее на самом востребованном сегодня решении, которое частично используем и сами, – микросервисной архитектуре.
Микросервисная архитектура (или просто “микросервисы”) – это подход к разработке и поддержке приложения с использованием набора децентрализованных и независимо развертываемых сервисов. Согласно опросам, именно такую архитектуру выбирают 74% компаний в мире для решения бизнес-задач, а объем ее рынка, по прогнозам, вырастет в 2024 году до 6,41 млрд долл.
В каких случаях подходит микросервисная архитектура
Представьте себе кирпичную стену, возведенную из отдельных блоков, с неразрывно связанными затвердевшим цементом кирпичами. Чтобы изменить такую постройку, без кувалды не обойтись.
И сразу другой пример: популярный конструктор Lego с множеством деталей, которые можно пересобрать в нечто новое или просто заменить без ущерба для остальных элементов.
С точки зрения гибкости и возможности доработки Lego кажется лучше, правда?
Именно поэтому микросервисная архитектура, при которой приложение разбивается на набор автономных сервисов, каждый из которых выполняет одну конкретную функцию, в последние годы и обгоняет по популярности монолитную, состоящую из стандартных компонентов.
Чтобы изменить какой-то один компонент в монолите, придется переделывать всё приложение, тогда как микросервисы отличаются гибкостью. Обновлять логику в этом случае предельно легко – достаточно просто изменить нужный блок. И при этом даже останавливать работу веб-приложения не нужно.
Вот почему такую архитектуру выбирают в том числе технологические гиганты вроде Amazon, Netflix, SoundCloud, eBay, Uber и т. д., а 84% пользователей согласны с тем, что использование микросервисов облегчает работу сотрудников.
Где конкретно могут применяться микросервисы? По правде сказать, где угодно.
Вот лишь несколько наглядных примеров:
- Мобильное приложение для планирования путешествий с частыми обновлениями – микросервисная архитектура обеспечивает независимость развертывания, позволяя развертывать обновления отдельных сервисов (например, поиска рейсов или бронирования отелей) без необходимости перезагружать всё приложение.
- Медиа-платформа с различными форматами контента – каждый микросервис может быть разработан с использованием подходящих технологий (например, обработка видео может быть написана на C++, а система рекомендаций – на Python с использованием машинного обучения).
- Соцсеть с миллионами пользователей – отказ какого-то одного микросервиса (например, модуля уведомлений) в этом случае не приводит к остановке всего приложения, другие сервисы (лента новостей, чат и проч.) продолжают работать бесперебойно.
- Облачное приложение для управления проектами – микросервисная архитектура делит приложение на небольшие независимые части, что значительно упрощает тестирование и отладку каждого сервиса по отдельности, обнаружить и исправить ошибку в конкретном сервисе можно без анализа всего приложения.
Словом, микросервисная архитектура подходит для приложений с такими требованиями, как масштабируемость, гибкость и отказоустойчивость.
Теперь – о том, как упростить использование микросервисной архитектуры.
Для чего нужны контейнеры
Чтобы упростить перенос микросервисов из среды разработки туда, где им предстоит функционировать, используется контейнеризация – эта технология позволяет писать приложения один раз и запускать их где угодно.
Впервые технология контейнеров была представлена в 1979 году в Unix версии 7 и системе Chroot, а сейчас, в 2024 году, объем рынка контейнеров для приложений оценивается в 5,45 млрд долл. и, по прогнозам, достигнет 19,41 млрд долл. к 2029 г.
Сегодня более 70 тысяч компаний используют инструменты контейнеризации, а самой популярной в мире платформой для разработки и запуска контейнерных веб-приложений является Docker, охватывающая 82,65% рынка. Docker позволяет создавать контейнеры, автоматизировать их запуск и развертывание, а также управляет жизненным циклом.
Docker пригодится при:
- разработке и тестировании – можно создавать изолированные среды, запускать и тестировать код, чтобы избежать проблем с зависимостями и точно знать, что приложение будет работать одинаково на различных платформах;
- масштабировании – Docker упрощает процесс развертывания приложений в тестовых, предварительных и производственных средах, позволяет оперативно добавлять/удалять контейнеры по мере необходимости;
- непрерывной интеграции (CI) и непрерывном развертывании (CD) – благодаря интеграции Docker с инструментами CI/CD (Jenkins, CircleCI, Travis CI и т. д.) можно автоматизировать процессы сборки, тестирования и развертывания приложений.
Словом, любое приложение можно обернуть в контейнер, чтобы оно спокойно работало в изолированном окружении. Подобная упаковка защищает приложение и исключает сюрпризы, вроде тех, когда во время теста сервис работает, а при переносе в рабочую среду – внезапно перестает.
При этом в зависимости от текущей нагрузки в таком случае легко добавлять новые экземпляры приложения в виде контейнера (если есть нагрузка) и убирать уже запущенные (если нагрузки нет), а для того чтобы запускать на сервере готовые контейнеры и связывать их между собой, можно использовать веб-интерфейсы – например, Portainer, который позволяет управлять средами Docker, Docker Swarm, Kubernetes и ACI с помощью удобного графического интерфейса и/или обширного API.
А если проект будет расти
Обычно с ростом популярности веб-приложения его поддержка неизбежно начинает нуждаться в больших ресурсах. Безусловно, с нагрузкой можно справляться путем оптимизации алгоритмов, однако если всё, что можно было оптимизировать, уже оптимизировано, а приложение всё равно не справляется, на помощь приходит масштабирование.
Под этим термином понимается возможность системы повышать свою производительность при увеличении количества выделяемых ей ресурсов.
Существует два способа масштабирования:
- вертикальное – увеличение вычислительной мощности, памяти, хранилища на существующих серверах веб-приложений (например, миграция с сервера с 4 ядрами и 8 Гб ОЗУ на сервер с 8 ядрами и 16 Гб ОЗУ для приложения с высокой нагрузкой на вычисления);
- горизонтальное – добавление новых серверов/ресурсов для распределения нагрузки (например, развертывание дополнительных экземпляров веб-сервера за счет балансировки нагрузки для высоконагруженных приложений с большим количеством одновременных пользователей).
На первый взгляд вертикальное масштабирование (то есть обновление железа – процессора, диска и т. д.) может показаться проще ввиду отсутствия необходимости в доработке приложения, однако в долгосрочной перспективе, когда такое масштабирование достигнет своего предела, единственным возможным решением может стать выбор горизонтального масштабирования.
Приведем пример, как мы решаем вопрос масштабирования в рамках архитектуры веб-приложений у себя.
В разработке существуют понятия холодного и теплого кэша. Теплый кэш содержит ранее загруженные данные, которые можно использовать повторно, а холодный – не содержит.
Для горячего кэша мы и создаем отдельные сервисы – заранее собираем с серверов различные метрики, которые видны пользователям в панели управления, но сбор которых “по требованию” будет достаточно долгим и отразится на отзывчивости интерфейса. К примеру, информация о занятом дисковом пространстве файлами пользователя изначально берется с конечного сервера, ее получение может занимать много времени, поэтому если каждый раз запрашивать такую информацию напрямую, возникнет ряд сложностей.
Во-первых, будет много запросов на конечный сервер, т. к. пользователям такая информация требуется довольно часто. Во-вторых, ее сбор каждый раз заново занимает больше времени, чем необходимо для плавной работы интерфейса. И, наконец, в-третьих, если на сервере возникает нагрузка или он оказывается недоступен, такую информацию попросту не получить.
А ведь она нужна 🙂
Вот почему мы постоянно со всех серверов транслируем эти показатели в отдельный сервис, который, в свою очередь, обеспечивает их быструю и бесперебойную отдачу пользователям.
Чек-лист: что продумать при планировании архитектуры
- Цели и требования – какие проблемы должно решить приложение, какие в нем должны быть функции, сколько пользователей будет использовать приложение и какие задачи они будут выполнять (например, если ожидается высокая нагрузка на серверы, нужно предусмотреть соответствующую мощность и выявить потенциальные пиковые нагрузки).
- Тип архитектуры – компоненты приложения могут быть связаны либо разделены на независимые сервисы или, быть может, приложению подойдет гибридная архитектура. Тип архитектуры влияет на выбор железа: монолит требует мощных серверов для поддержки всего приложения в одном месте, а микросервисы – гибкого подхода с возможностью масштабирования отдельных компонентов.
- Железо – важно определить количество ядер и частоту процессора в зависимости от вычислительной нагрузки, рассчитать объем памяти, необходимый для эффективной работы приложения и обработки данных, выбрать тип и объем хранилища (SSD лучше подходит для быстрого доступа, а HDD – для больших объемов данных), а также учесть пропускную способность и требования к надежности сети, особенно если приложение будет работать с большим объемом данных в реальном времени. При выборе железа важно обращать внимание на производительность, масштабируемость, надежность и совместимость: например, для веб-приложения в сфере e-commerce основными требованиями может быть поддержка 10 тысяч одновременных пользователей, быстрая обработка транзакций, высокая доступность и надежность – и в таком случае можно использовать 8 серверов с процессорами Intel Xeon, 64 ГБ RAM и NVMe SSD, коммутаторы с пропускной способностью 10 гигабайт в секунду и балансировщики нагрузки, а также сетевое хранилище RAID 10.
- Логика – определите основные части (модули, сервисы и т. д.) компонентов системы и визуализируйте взаимодействие между ними, продумайте, какие слои будут у приложения.
- Технологии и инструменты – языки программирования (Python, JavaScript, Java и др.), фреймворки (Django, React, Spring и др.), DevOps-инструменты (Docker, Kubernetes, Jenkins и др.), а также выбор базы данных (MySQL, PostgreSQL, MongoDB и др.) и ее схемы (таблицы, их поля и связи между ними).
- Проектирование API – при планировании архитектуры веб-приложения важно определить тип (например, RESTful, GraphQL) и методы (GET, POST, PUT, DELETE) API.
- Безопасность – аутентификация и авторизация (OAuth, JWT, двухфакторная аутентификация), защита данных (шифрование, SSL/TLS).
- Пользовательский интерфейс – подготовьте визуальные прототипы с учетом UX/UI-принципов (удобство, простота, последовательность, иерархия, дистанцирование, выравнивание).
- Интеграция и развертывание – CI/CD и среда (облако или локальные серверы).
- Тестирование – юнит-тесты (для тестирования отдельных модулей), интеграционные тесты (для проверки взаимодействия между модулями), нагрузочные тесты (для проверки работы под нагрузкой), а также автоматизация тестирования (использование Selenium, Cypress, Pytest и других инструментов для автоматизации тестов).
- Мониторинг и логирование – в этом могут помочь системы мониторинга (Prometheus, Grafana) и логирования (ELK stack, Splunk), а также настройка алертов.
Заключение
Чтобы завоевать доверие пользователей в современном высококонкурентном мире, недостаточно просто создать качественный продукт – во главу угла сегодня возведено то, как он будет доставляться клиентам.
Веб-приложения с адаптивной архитектурой, позволяющей интегрировать новые функции, устранять угрозы безопасности и оптимизировать производительность, не нарушая основной функциональности приложения, дают возможность приспособиться к постоянно меняющемуся ландшафту ожиданий пользователей и технологических достижений.
На этом всё, выстраивайте архитектуру веб-приложений – и пусть ваш проект развивается не по дням, а по часам 🙂
Если у вас возникли какие-либо вопросы, свяжитесь с нами удобным для вас способом – и мы обязательно ответим. Также ждем вас в нашем официальном Telegram-канале, а обсудить архитектуру веб-приложений или просто пообщаться с коллегами по цеху и сотрудниками Бегета вы можете в нашем чате.