Настройка Gzip/Brotli сжатия на веб-сервере

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

Сжатие gzip nginx: где теряется скорость и трафик

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

Второй класс проблем — охват. Список типов содержимого по умолчанию узкий: стили, скрипты, векторная графика, JSON в него не попадают. Одни ответы сжимаются на лету при каждом запросе, другие отдаются сжатыми повторно — и клиент распаковывает то, что выгоднее было получить как есть. Проверяется это только по заголовкам: смотрит ли сервер на поддерживаемые клиентом форматы и что реально лежит в теле ответа.

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

Ниже разбираем, как это закрывается: где именно теряется сжатие, какие правила это ловят и как отдавать подготовленные архивы вместо работы на каждый запрос.

Что даёт правильное сжатие: время отклика и объём

Объём передачи

Сжимаются текстовые ресурсы: разметка, стили, скрипты, ответы API в JSON. На типовом фронтенде это 60–80% веса страницы, и после настройки они уходят в 3–5 раз меньшим потоком. Картинки, видео и шрифты уже сжаты форматом — их из политики исключают, чтобы не тратить процессор впустую.

Время отклика

Меньше байт на провод — быстрее первый отрисованный экран, особенно на мобильных сетях и в дальних регионах. Brotli на статике отдаёт заметно меньший объём, чем gzip на том же уровне: разница в размере достигает 15–25% на стилях и скриптах. Для динамики включают сжатие на лету с умеренным уровнем — выигрыш по времени перевешивает стоимость.

Нагрузка на процессор

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

Устойчивость под нагрузкой

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

Что проверяем после настройки

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

Где включать компрессию: варианты и ограничения

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

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

Вариант Когда подходит Ограничения
Сжатие на веб-сервере Смешанный трафик: статика и ответы приложения идут через один сервер, нужны гибкие правила по типам Список типов и порог длины задаются вручную; ошибка в правилах даёт либо несжатый ответ, либо лишнюю нагрузку
Сжатие на обратном прокси Несколько сервисов за одним входом, нужны единые правила и кэш сжатых ответов Сжимает по заголовкам, содержимое не видит; при кэшировании варианты надо разделять по Accept-Encoding
Предварительная подготовка файлов Статика, которая меняется редко: сборка сразу кладёт рядом .gz и .br Только файлы на диске; динамику не покрывает, архивы нужно пересобирать при каждом обновлении
Сжатие на периметре доставки Геораспределённая аудитория и большой объём статики Настройки зависят от площадки; часть ответов идёт мимо, если сжатие уже выполнено на источнике
Сжатие в приложении Ответы формируются на лету и не проходят через общий сервер Процессорное время тратится на каждый запрос, сложнее кэшировать и отлаживать

Порядок работ: от аудита отдачи до проверки в проде

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

  1. Аудит отдачи. Снимаем реальные размеры ответов по типам контента: разметка, стили, скрипты, шрифты, ответы API. Смотрим, что уже приходит сжатым от периметра. На выходе — список типов, где сжатие даёт выигрыш, и тех, где оно только тратит ресурс.

  2. Схема обработки запроса. Фиксируем, на каком узле применяется компрессия и что сжимает периметр. Двойное сжатие одного ответа — это нагрузка без выигрыша в размере.

  3. Настройка компрессии. Включаем gzip как базовое покрытие и Brotli для клиентов, которые его поддерживают: на текстовых типах он даёт меньший размер. Задаём уровень сжатия, минимальный размер ответа, список типов и исключения для уже сжатых форматов; сжатый и несжатый вариант должны корректно разделяться в кэше.

  4. Проверка перед выкаткой. Сравниваем размер и время отдачи до и после на стенде, отдельно на холодном и тёплом кэше, прогоняем ключевые страницы и ответы API.

  5. План отката. Конфигурация версионируется, изменения уезжают одной правкой, которую снимают без пересборки приложения. Заранее фиксируем метрики, по которым считаем выкатку неудачной.

  6. Выкатка и передача. Раскатываем сначала на часть трафика, следим за долей сжатых ответов и временем отдачи, затем включаем полностью. Передаём команде конфиги, схему и короткую инструкцию по проверке после релиза.

Конфигурации, схемы и регламенты на выходе

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

  • Готовые конфигурации сервера: уровни сжатия для статики и динамики, порог минимального размера ответа, работа с предсжатыми файлами — с пояснением, почему выбраны именно эти значения.
  • Схема обработки запроса: путь от клиента до отдачи через прокси, кэш и приложение, место сжатия в этой цепочке и точки, где ответ может пройти мимо него.
  • Политики исключений: перечень типов файлов, которые сжимать бессмысленно — изображения, видео, архивы, уже упакованные форматы.
  • Регламент изменений: как правки списков и уровней проходят проверку до выката, что фиксируется в истории и по какому условию откатывается.
  • Документация по отдаче: какие заголовки сервер обязан вернуть, как убедиться, что ответ пришёл сжатым, куда смотреть при жалобе на медленную загрузку.
  • Набор проверок и метрик: доля ответов со сжатием, объём передаваемых данных до и после, время отдачи и частота ошибок сжатия.
  • Инструкция по поддержке: где менять исключения и уровни, как добавить новый тип файлов и на что это повлияет.

Кейс: ускорили отдачу каталога без замены серверов

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

Замеры до внедрения

Средняя страница каталога весила около 1,2 МБ, из них на разметку, стили и скрипты приходилось больше 80%. Время до первого отображения на среднем канале — порядка 3,4 с, доля сжатых ответов — ноль. Отказы на мобильных были заметно выше, чем на десктопе: разница объяснялась пропускной способностью канала, а не качеством вёрстки.

Что изменили и что получилось

Включили gzip для текстовых типов и добавили brotli с предварительным сжатием статики на диске — файлы готовились один раз, а не на каждый запрос. Конфигурацию Nginx дополнили явным списком типов, отсечением уже сжатых форматов и кэшированием вариантов на прокси. Доля сжатых ответов выросла до 96%, вес страницы каталога упал до 210 КБ, время отклика сократилось до 1,1 с — на том же железе и без переписывания серверной логики.

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

Чем отличается подготовка заранее от обработки на лету?

Разница в том, где и когда тратится процессорное время. При подготовке заранее сжатие выполняется один раз — на этапе сборки или публикации контента, а результат лежит рядом с оригиналом отдельным файлом. Веб-сервер в этом случае лишь выбирает подходящий вариант по заголовку Accept-Encoding и отдаёт готовые байты, не нагружая процессор на каждый запрос.

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

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

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

Частые технические вопросы по настройке отдачи

Сомнения перед включением сжатия обычно одни и те же: как убедиться, что оно работает, не начнёт ли контент сжиматься дважды и что исключить из обработки. Короткие ответы на каждый — ниже.

Как проверить, что сжатие действительно включилось?

Запрос с заголовком Accept-Encoding и ответ с Content-Encoding: в теле приходит тот же контент, но с заметно меньшим Content-Length. Проще всего сравнить размер ответа с заголовком и без него, а по логам дополнительно посмотреть коэффициент сжатия — так видно, что правило сработало не только на разметке, но и на стилях, скриптах и шрифтах.

Откуда берётся двойное сжатие?

Если перед сервером стоит прокси или внешний кэш, который сжимает ответы сам, контент уходит закодированным дважды. Рабочий вариант — оставить один уровень: либо на краю, либо на самом сервере. Мы фиксируем это до работ, чтобы потом не искать причину выросшего объёма ответа у части пользователей.

Какие типы файлов исключают?

По умолчанию сжимается только разметка, остальное — стили, скрипты, json, svg, шрифты — перечисляют вручную. Бинарные форматы и предварительно сжатые копии отдают как есть: выигрыша в размере нет, а нагрузка на процессор растёт на каждом запросе.

Что с кэшированием и заголовками?

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

Совместимо ли это с прокси и балансировщиками?

Да. Единственное, о чём стоит договориться заранее, — на каком уровне включено сжатие: если соединение терминируется на балансировщике, логичнее делать это там. Обычно так и выясняется, почему у части аудитории ответы приходят без сжатия.

Обсудим задачу: с чего начинаем и что нужно от вас

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

Дальше нужны вводные данные — без них оценка работ превращается в догадки. Обычно просим:

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

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

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139