Hitech logo

Кейсы

Современные подходы к созданию высокопроизводительных веб-приложений: инструменты и практики

TODO:
Катя Литвинова17 августа 2023 г., 08:04

 По мере роста популярности веб-приложения в интернете, на него растет нагрузка. Понятие «высоконагруженный сервис» является относительным, без четких критериев. И сегодня опытный эксперт и разработчик ПО Ринат Юнусов поделился с нами ответом на вопрос, почему высоконагруженный проект должен быть высокопроизводительным? В этой статье мы поговорим о том, какие инструменты, практики и технологии могут помочь сделать веб-сервис настолько высокопроизводительным, насколько это возможно. Собранная здесь информация может помочь проектам с растущей популярностью преодолеть технический кризис, связанный с ростом нагрузки на веб-приложение.

Самые интересные технологические и научные новости выходят в нашем телеграм-канале Хайтек+. Подпишитесь, чтобы быть в курсе.

Как отметил Ринат, очевидно, что проблемы «Вконтакте», чья система обрабатывает 11 миллиардов запросов к базе данных в день и фасилитирует 200 миллионов личных сообщений за сутки, будет отличаться от реальности не очень популярного сайта. А вот еще один факт: около 50% пользователей ждут, что при открытии в браузере страница станет доступна в течение 2 секунд и менее. Если страница «грузилась» за 3 секунды, то половина пользователей этого сайта уйдут во время или после загрузки.

По мнению Юнусова, высоконагруженный продукт должен быть высокопроизводительным, если хочет выжить. А как быстро загружаются It-сервисы вашего бизнеса? Вы можете проверить это самостоятельно в бесплатном сервисе от Google.

High Load и технология сетей доставки контента

Если в вашем UI/UX интерфейсе стоит задача обработки 1000 хитов пользователей в секунду, то помочь ускорить их работу может подгрузка части данных из CDN (Content Delivery Network). Это географически распределённая сетевая инфраструктура, позволяющая оптимизировать дистрибуцию контента веб-страниц пользователям. На практике это означает, что часть операций во «фронтовой», пользовательской части ресурса можно перепоручить «обсчитывать» облачным сторонним сервисам, вроде Cloudflare, Akamai, AWS CloudFront.

Это специальные сервисы по технологии CDN, помогающие распределить нагрузку на «фронт» приложений. Преимущество не только в снятии нагрузки и ускорении собственной инфраструктуры, но и в повышенной устойчивости к скачкам посещаемости. Распределять по CDN можно как статический, так и динамический контент. Юнусов отметил, что сервисы, принимающие нагрузку:

— распределяют ее на географически удаленные друг от друга сервера;

— кэшируют контент в нескольких средах сразу.

Это дает возможность интерфейсам, оптимизированным с помощью CDN, необыкновенно быстро приспосабливаться к резким изменениям ситуации. Существуют бонусы в области безопасности. Подключаемые CDN-сервисы предлагают услуги дополнительной защиты от хакерских атак, DDoS, утечек за счет шифрования SSL/TLS.

Кэширование всех видов

Сделать сервис более производительным помогает кэширование, то есть сохранение ранее полученной информации для того, чтобы ее не потребовалось получать заново. Другое дело, что обо всех возможностях в этой сфере осведомлены далеко не все. Вот виды кэширования для веб-приложений, в которых может скрываться потенциал повышения производительности:

— кэширование в памяти: банальное сохранение в памяти полученной информации для ее повторного использования. Такое практикует, например, база данных Redis. Минус в том, что загруженность памяти тоже может стать причиной торможения. Превышение плюсов над минусами в этом деле зависит от специфики ситуации, в которой находится сервис;

— кэширование в браузере: настройте серверы, которые вы используете, nginx или Apache, чтобы они отдавали браузерам HTTP-заголовки, разрешающие сохранение сохранение на стороне обозревателя CSS, JS и других элементов, чтобы их не нужно было загружать повторно;

— кэширование в приложении: с помощью специальных фреймворков можно организовать кэширование в самом веб-сервисе. Кэш будет храниться в его же базе данных и отдаваться более быстро, чем при обычном чтении или компиляции кода.

SQL и NoSQL: повышаем производительность на каждом запросе к базе данных

Выбор используемых баз данных обычно делается в начале разработки сервиса, так как ревизия таких решений в то время, когда проект накопил огромные объемы legacy-кода (и запросов) будет чрезвычайно трудным решением. Тем не менее, как рассказал Ринат Юнусов, иногда даже в этих условиях  стоит «все переписать», учитывая выигрыш от оптимизации. NoSQL-технология представлена в виде таких конкретных баз данных, как Redis, Cassandra, MongoDB, на которых можно построить «бэк» веб-приложения. SQL — это привычные MySQL, Postgres и ряд других.

Основное преимущество NoSQL, по мнению Рината, в автоматизации многих процессов взаимодействия «фронта» и «бэка». Например, MongoDB в полуавтоматическом режиме выполняет репликацию и шардинг (горизонтальное разделение данных). Это часто приходится делать при масштабировании проекта. С традиционным SQL на реализацию этого уходит гораздо больше человеческих и аппаратных ресурсов. Как с любой автоматикой, она плохо работает, когда речь идет об особенно тонкой или уникальной работе. Поэтому если веб-приложение предполагает сложные SQL-запросы, то традиционные SQL-базы подойдут лучше. Ну, а NoSQL поможет там, где речь скорее о стандартных операциях. Дополнительно ускорить запросы даже с использованием NoSQL может помочь их спарка с ORM-инструментами (Object-Rational Mapping). Среди сервисов этого типа можно перечислить Sequelize и Mongoose.

Языки программирования «на фронте»: самые производительные фреймворки

Можно ли разработать веб-приложение за 24 часа? Настоящую революцию в разработке произвели ряд библиотек на основе JavaScript (JS) и TypeScript, которые, с одной стороны, используют компонентный подход, то есть позволяют строить и развивать приложение из коллекции компонентов, незначительно меняя которые можно «надстраивать» новую функциональность и изменять существующую. Помимо скорости разработки эти фреймворки отличаются высокой производительностью. Перечислим самые успешные из них:

— React: за счет технологии виртуализации DOM-объектов фреймворк обрабатывает быстро большое количество данных (сокращается время на повторный рендеринг). Являясь более производительным, чем другие библиотеки (способен давать скорость 60 кадров в секунду и более);

— Angular: поддерживается Google. Его главная оптимизация по отношению редкой на сегодня разработке на чистом TypeScript заключается в двусторонней привязке данных. Попросту говоря, разработчик не должен управлять вручную всеми переменными приложения, поскольку фреймворк после формирования UI/UX интерфейса ретроспективно меняет модель данных под новую пользовательскую часть. Тем самым исключаются много неоптимальностей и сервис становистя быстрее. Модель DOM является не виртуальной, как у React, а инкрементной. То есть рендеринг затруднен. С другой стороны, такая модель позволяет экономить расходуемую память и за счет этого Angular тоже может разгоняться до 60 кадров и более в секунду;

— Vue.js: по потенциальной скорости не уступает другим вариантам. Критерии, в которых он расходится с остальными, связаны не столько со скоростью, сколько с другими особенностями. Например, Vue не настолько вынуждает подключать дополнительные библиотеки, как React, а React появился раньше и обладает гораздо большим комьюнити и кодовой базой, написанной на нем.

Производительный back-end

Логика приложения, скрытая от пользователя и общающаяся с базами данных традиционно пишется на таких языках, как Java, PHP, Python. Однако на сегодняшний день вариантов гораздо больше. В некоторых случаях выбор в их пользу может повлиять на производительность приложения, поскольку пользовательская часть приложения, о которой мы только что говорили, получает информацию от «бэка» и он вносит свою лепту в то «как долго загружается сайт». Вот возможные альтернативы тому же Python, который, как отметил разработчик Юнусов, работает примерно в 8 раз медленнее, чем любой компилируемый язык, вроде того же JavaScript:

— Node.js: написан на JS, компилируемом языке, следовательно, выигрывает по скорости у всех традиционных языков back-end. вдобавок, на Node.js можно написать сразу как «бэк», так и «фронт». Однако экспертами рекомендуется в основном для «бэка» сетевых сервисов с постоянной и большой нагрузкой онлайн. По сравнению с тем же PHP, в котором плохо реализована даже многопоточность, он может быстро и хорошо поддерживать множество параллельных подключений;

— Django: это фреймворк к языку Python, на котором можно очень быстро сделать фронтовую часть приложения. По производительности проигрывает тому же Node.js, но имеет много других преимуществ, за что любим большим комьюнити разработчиков;

— Ruby on Rails: также ускоряет процесс разработки, а по производительности проигрывает Node.js.

Если подводить итоги раздела о «бэке», то наилучшим решением с точки зрения производительности сегодня будет Node.js для веб-сервисов с постоянной онлайн нагрузкой и Java, PHP, Python для более традиционных проектов, так как за годы использования в качестве языков «бэка» в них предусмотрено немало более удобных решений тех или иных проблем, чем в Node.js. Вместе с тем, для традиционных веб-приложений, например, контентных сайтов, за некоторым исключением проблема производительности не стоит так остро.

Архитектура, практики разработки, тестирование: другие пути оптимизации производительности

Ринат также поделился, что долю ответственности за низкую производительность веб-приложения несет несовершенная архитектура. Быстрее всего при больших нагрузках будут работать сервисы, где «бэк» реализован в виде API, к которому обращается «фронт», а код построен на модульном, микросервисном подходе. Модули стандартно и без неоптимальных задержек взаимодействуют между собой, обеспечивая скорость. Также, при прочих равных будет эффективна архитектура, распределенная по контейнерам, например, с помощью Docker, WebAssembly, Kubernetes. Понятие контейнеризации тесно связано с микросервисами. В двух словах ее можно описать так: каждый элемент подгружается, фактически, из своей операционной системы (своего Linux) и изолирован от остальных. Тем самым нагрузка распределяется между огромным количеством ОС, установленных в облаке. В результате веб-приложение работает быстрее. В самих принципах чистого кода заложена быстрота его обработки. Особенно важны с этой точки зрения следующие принципы:

— минимизация HTTP-запросов;

— отсутствие повторов в коде (принцип DRY);

— использование асинхронности там, где это возможно;

— рефакторинг циклов и условий.

В области тестирования можно посоветовать проводить нагрузочное тестирование (load testing), в том числе автоматическое, чтобы выявить конкретные элементы в сервисе, которые не дают ему отрабатывать быстро. Техническим менеджерам стоит активнее использовать потенциал Google Analytics, New Relic. С их помощью можно фиксировать отклонения по нагрузке и выявлять причины того, что веб-приложение срабатывает не так, как следовало бы. Иногда проблемы с производительностью вызваны проблемами с «деплоем» нового кода в продакшн, то есть в сам веб-сервис из тестовой среды. Решением может стать привлечение такого специалиста, как DevOps. Если у вас ранее никто специально не отвечал за CI/CD, то есть непрерывное развертывание изменений в «боевом коде», то в этом процессе могли накопиться неоптимальности, которые и привели к накоплению в проекте тормозящего мусора и ошибок. Профессиональный DevOps поможет расчистить эти авгиевы конюшни. Наконец, такую же роль может сыграть привлечение в команду UI/UX дизайнера, который может сделать интерфейс более привлекательным с точки зрения пользователей, но в том же время, более эргономичным по требованиям к системе. Так что оптимизация производительности может прийти и со стороны дизайна.

В заключение Ринат Юнусов вспомнил спор владельца соцсети X Илона Маска с team-lead-ом ее мобильной версии Эриком Фронхофером. Его причиной стала как раз низкая скорость (производительность) приложения на Android. Маск поинтересовался, что было сделано, для того, чтобы этого избежать. По мере развития дискуссии между Маском и Фронхофером прямо на страницах социальной сети указал на причины низкой производительности: долгое ожидание сетевых ответов (network response), технический долг и переизбыток функций в соцсети, которыми никто не пользуется. Дискуссия, в результате которой Фронхофер был уволен прямо в переписке продемонстрировала, какой системной по своей сути является проблема низкой производительности высоконагруженных приложений. Исправлять ситуацию тоже нужно системой мер, а не одним каким-либо инструментом. В этой статье мы перечислили только часть того, что можно предпринять усилиями back-end и front-end разработчиков, менеджеров, дизайнеров и системных администраторов.