Инфраструктурные методы оптимизации производительности веб-приложений

Иллюстрация инфраструктурной оптимизации веб-приложений с серверами, CDN, балансировщиком нагрузки, контейнерами, облачной инфраструктурой и мониторингом

Навигация

5.1 Общие положения инфраструктурной оптимизации

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

Существует точка зрения по поводу инфраструктурных способов оптимизации производительности приложений, которая кардинально отличается от классической. Например, по мнению Мартина Фаулера, использовать более новое оборудование зачастую просто выгоднее, нежели заставлять программу «крутиться» на устаревшей технике. Если корпоративное приложение поддается масштабированию, добавить несколько серверов дешевле, чем приобрести услуги нескольких программистов1. Основу этой позиции составляет экономическое обоснование оптимизации производительности, что также часто влияет на принятие решений по поводу определения инженерных решений.

Важное место в системе инфраструктурных методов оптимизации занимает веб-сервер. Согласно официальной документации, Nginx представляет собой один из наиболее распространенных и производительных HTTP-серверов в мире2. Nginx широко применяется для обслуживания статического контента, работы в качестве обратного прокси, балансировщика нагрузки и системы кэширования. Основная функциональность HTTP-сервера включает: обработку входящих HTTP-запросов; передачу статических файлов; проксирование запросов к backend-приложению; управление соединениями; обеспечение безопасности и устойчивости под нагрузкой.

Рисунок 7 ¾ Доля сайтов в Интернете, которые работают на конкретном веб‑сервере3

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

Оптимизация производительности любого типа сервера или приложения всегда зависит от множества переменных факторов, таких как, помимо прочего, среда, сценарий использования, требования и задействованные физические компоненты. Часто используется метод оптимизации, основанный на поиске «узких мест», то есть тестирование до тех пор, пока не будет найдено «узкое место», определение этого «узкого места», настройка с учетом ограничений и повторение процесса до достижения желаемой производительности4.

В литературе выделяют множество способов оптимизации производительности Nginx, например: 1) автоматизация тестов с помощью драйверов загрузки; 2) управление кэшем в браузере; 3) поддержание открытых соединений с клиентами; 4) поддержание открытых соединений с исходящим каналом; 5) буферизация ответов; 6) буферизация журналов доступа; 7) настройка ОС5.

Основу инфраструктурной части приложения будет составлять широко распространенный LEMP-стек (Linux, Nginx, MySQL, PHP). Обработка PHP-кода будет осуществляться менеджером процессов PHP-FPM, обеспечивающим эффективное управление нагрузкой и стабильную работу приложений.

5.2 Настройка кэширования статических ресурсов

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

location ~* \.(css|js)$ {

expires 1y;

add_header Cache-Control "public";

}

Этот блок location указывает, что клиент может кэшировать содержимое файлов CSS и JavaScript. Директива expires сообщает клиенту, что кэшированный ресурс перестанет быть действительным через год. Директива add_header добавляет заголовок HTTP-ответа Cache-Control со значением public, что позволяет любому кэширующему серверу кэшировать ресурс. Если указано private, кэшировать значение может только клиент6.

В результате можно обеспечить: уменьшение числа запросов к серверу; ускорение повторной загрузки страниц; снижение сетевого трафика; улучшение пользовательского опыта. Производительность кэша зависит от множества факторов, и скорость диска занимает одно из первых мест в этом списке. В конфигурации Nginx предусмотрено много способов улучшить производительность кэша. Один из вариантов – настроить заголовки ответа таким образом, чтобы клиент фактически кэшировал ответ и вообще не отправлял запрос в Nginx, а просто обслуживал его из собственного кэша7.

5.3 Сжатие данных (Gzip и Brotli)

Передача несжатых данных увеличивает время загрузки страниц. Сжатие позволяет существенно уменьшить объем передаваемой информации.

Gzip – наиболее распространенный алгоритм сжатия HTTP-ответов. Пример настройки:

gzip on;

gzip_types text/plain text/css application/json application/javascript;

gzip_min_length 1000;

Brotli обеспечивает более высокую степень сжатия по сравнению с Gzip и поддерживается современными браузерами.

brotli on;

brotli_types text/plain text/css application/javascript;

Использование сжатия особенно эффективно для текстовых ресурсов: HTML; CSS; JavaScript; JSON.

5.4 Оптимизация параметров соединений

Keep-alive позволяет использовать одно TCP-соединение для нескольких HTTP-запросов, что снижает накладные расходы на установление соединений. Например: keepalive_timeout 65;.

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

В литературе рекомендуется использовать директивы keepalive_requests и keepalive_timeout для изменения количества запросов, которые могут быть выполнены в рамках одного соединения, и времени, в течение которого могут оставаться открытыми неактивные соединения:

http {

keepalive_requests 320;

keepalive_timeout 300s;

# ...

}

Директива keepalive_requests по умолчанию имеет значение 100, а директива keepalive_timeout – 75 секунд. Как правило, количество запросов по одному соединению по умолчанию удовлетворяет потребностям клиента, поскольку современные браузеры могут открывать несколько соединений с одним сервером для каждого полного доменного имени (FQDN). Количество параллельных открытых соединений с доменом обычно ограничено числом менее 10, поэтому в этом отношении будет происходить много запросов по одному соединению. Один из способов, часто используемых сетями доставки контента в HTTP/1.1, заключается в создании нескольких доменных имен, указывающих на сервер контента, и чередовании используемых доменных имен в коде, чтобы позволить браузеру открывать больше соединений. Эти оптимизации соединений могут оказаться полезными, если фронтенд-приложение постоянно опрашивает бэкенд-приложение на наличие обновлений, поскольку открытое соединение, позволяющее отправлять больше запросов и остающееся открытым дольше, ограничит количество необходимых соединений8.

По умолчанию Nginx может: открыть соединение к backend (upstream); отправить запрос; закрыть соединение. Создание нового TCP-соединения каждый раз – это: лишний handshake; задержка; дополнительная нагрузка на CPU; большее количество сокетов. Если запросов много – это заметно влияет на производительность.

Для повышения производительности необходимо поддерживать открытые соединения с вышестоящими серверами для повторного использования. В литературе рекомендуется использовать директиву keepalive в контексте upstream, чтобы поддерживать соединения с серверами upstream открытыми для повторного использования9:

proxy_http_version 1.1;

proxy_set_header Connection "";

upstream backend {

server 10.0.0.0;

server 10.0.0.1;

keepalive 32;

}

Директива keepalive 32 свидетельствует о том, что каждый worker Nginx может держать до 32 idle (свободных, но открытых) соединений к backend-серверам. Когда приходит новый запрос Nginx не открывает новое соединение, а берет одно из уже открытых idle-соединений. Это ускоряет обработку запросов.

Директива proxy_http_version 1.1 указывается потому, что HTTP/1.0 не поддерживает полноценную работу постоянных соединений (keep-alive). Использование HTTP/1.1 позволяет передавать несколько запросов и ответов в рамках одного соединения, что снижает накладные расходы и повышает производительность.

Директива proxy_set_header Connection "" используется потому, что по умолчанию Nginx может отправлять заголовок: Connection: close. Этот заголовок заставляет бэкенд закрывать соединение. Указанная строка убирает этот заголовок, чтобы соединение оставалось открытым.

Важно отметить, что idle-соединения не равно все соединения: 1) keepalive 32 – это 32 свободных соединения на одного worker; 2) активных соединений может быть больше; если количество workers 4, то максимум 128 idle соединений. По этой причине значение должно быть разумным, чтобы не «забить» бэкенд открытыми сокетами. Указанная методика оптимизации заключается в том, что без keepalive каждый запрос создает новое соединение, keepalive–соединения используются повторно, меньше latency, меньше нагрузки, выше производительность.

Директива keepalive в контексте upstream активирует кэш соединений, которые остаются открытыми для каждого рабочего процесса Nginx. Директива обозначает максимальное количество неактивных соединений, которые должны оставаться открытыми для каждого рабочего процесса. Директивы модуля proxy, используемые выше блока upstream, необходимы для корректной работы директивы keepalive для соединений с серверами upstream. Директива proxy_http_version указывает модулю proxy использовать HTTP версии 1.1, что позволяет выполнять несколько запросов последовательно по одному соединению, пока оно открыто. Директива proxy_set_header указывает модулю прокси-сервера удалить заголовок по умолчанию close, позволяя соединению оставаться открытым.

Необходимо поддерживать открытыми соединения с вышестоящими серверами, чтобы сократить время, необходимое для установления соединения, позволяя рабочему процессу вместо этого напрямую перейти к отправке запроса через неактивное соединение. Важно отметить, что количество открытых соединений может превышать количество соединений, указанных в директиве keepalive, поскольку открытые и неактивные соединения – это не одно и то же.

Количество соединений keepalive должно быть достаточно небольшим, чтобы обеспечить возможность обработки других входящих соединений с вашим вышестоящим сервером. Соответствующая настройка Nginx может сэкономить ресурсы и повысить производительность10. Параметры worker_processes и worker_connections определяют, сколько запросов сервер способен обрабатывать параллельно.

worker_processes auto;

events {

worker_connections 1024;

}

Правильная настройка позволяет максимально эффективно использовать ресурсы процессора и оперативной памяти.

5.5 Микрокэширование

Микрокэширование – это кэширование динамических страниц на очень короткое время (например, 1-10 секунд). Даже такой небольшой интервал позволяет значительно снизить нагрузку при большом количестве однотипных запросов.

Пример настройки proxy_cache:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=microcache:10m inactive=60m;

location / {

proxy_pass http://backend;

proxy_cache microcache;

proxy_cache_valid 200 5s;

}

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

5.6 Результаты инфраструктурной оптимизации

Практические результаты оптимизации на уровне серверной инфраструктуры рассмотрим на примере сжатия Gzip и Brotli. На рисунке 8 представлена вкладка «Сеть» панели разработчика браузера исходной страницы (без применения каких-либо алгоритмов сжатия), которую мы возьмем за основу при определении эффективности сжатия рассматриваемых алгоритмов.

Рисунок 8 ¾ Исходная страница (без применения алгоритмов сжатия)

На рисунках 9 и 10 представлена аналогичная страница с применением алгоритмов Gzip и Brotli, соответственно. На представленных рисунках нас интересует столбец «Размер», в котором содержится размер загружаемых файлов.

Рисунок 9 ¾ Сжатие с использованием алгоритма Gzip

Для сжатия с помощью алгоритма Gzip использовалась следующая конфигурация Nginx:

gzip on;

gzip_comp_level 5;

gzip_min_length 256;

gzip_vary on;

gzip_proxied any;

gzip_disable "msie6";

gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/x-javascript;

Рисунок 10 ¾ Сжатие с использованием алгоритма Brotli

Для сжатия с помощью алгоритма Brotli использовалась следующая конфигурация Nginx:

brotli on;

brotli_static on;

brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

brotli_comp_level 5;

Консолидированные данные, демонстрирующие сравнение алгоритмов сжатия Gzip и Brotli представлены в таблице 4.

Таблица 4 ¾ Сравнение алгоритмов сжатия Gzip и Brotli в процентах от исходного размера

**Название**

файла

**Исходный размер (КБ)** **Gzip (КБ)** **Gzip % сжатия** **Brotli (КБ)** **Brotli % сжатия**
bootstrap.css 281 35 87,5 % 30,8 89,0 %
site.css 1,8 0,9 50,0 % 0,8 55,6 %
jquery.js 286 85,8 70,0 % 80 72,0 %
yii.js 21,2 6,2 70,8 % 5,8 72,6 %
bootstrap.bundle.js 208 45,9 77,9 % 41,9 79,9 %

Процент сжатия рассчитывается по формуле (1).

![](file:////Users/alexey/Library/Group%20Containers/UBF8T346G9.Office/TemporaryItems/msohtmlclip/clip_image005.emz) (1)

где исходный размер – размер файла до применения алгоритма сжатия (в КБ или МБ);

размер после сжатия – размер файла после применения алгоритма сжатия (в тех же единицах измерения).

С учетом изложенного можно отметить, что применение алгоритмов сжатия позволяет существенно уменьшить размер передаваемых файлов (до 87-89 %). Алгоритм сжатия Brotli более эффективен, чем Gzip. В среднем Brotli сжимает файлы эффективнее на 2-5 %, по сравнению с Gzip в зависимости от конкретного файла.


  1. Фаулер М. Шаблоны корпоративных приложений. Пер. с англ. – М.: ООО «И.Д. Вильямс», 2016. 

  2. Nginx: документация. – [Электронный ресурс]. – URL: https://nginx.org/ru/docs/ (дата обращения: 14.01.2026). 

  3. Netcraft. Доля сайтов в Интернете, которые работают на конкретном веб‑сервере. [Электронный ресурс]. – URL: https://www.netcraft.com/blog/january-2026-web-server-survey (дата обращения: 10.03.2026). 

  4. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  5. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  6. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  7. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  8. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  9. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024. 

  10. DeJonghe D. Nginx Cookbook: Advanced Recipes for High Performance Load Balancing. – 3rd ed. – Sebastopol: O’Reilly Media, 2024.