Сжатие gzip nginx: где теряется скорость и трафик
Компрессия включена, директива в конфигурации Nginx стоит, перезапуск выполнен — а браузер по-прежнему получает тяжёлый ответ. Вес ответа страницы не меняется, медленная первая загрузка остаётся, и заметно это не в логах, а в метриках на стороне клиента. Типовая причина: сжатие gzip настроено, но срабатывает не для всех ответов — часть уходит мимо правила из внутреннего кеша, через прокси или как статика, для которой условие не совпало.
Второй класс проблем — охват. Список типов содержимого по умолчанию узкий: стили, скрипты, векторная графика, JSON в него не попадают. Одни ответы сжимаются на лету при каждом запросе, другие отдаются сжатыми повторно — и клиент распаковывает то, что выгоднее было получить как есть. Проверяется это только по заголовкам: смотрит ли сервер на поддерживаемые клиентом форматы и что реально лежит в теле ответа.
Третье — узкое место отдачи. Сжатие выполняется в момент прихода запроса, и ресурс тратится на каждое обращение вместо отдачи заранее подготовленного файла. На пиках это даёт очередь: время ответа растёт не из-за нагрузки на канал, а из-за одной и той же повторяющейся работы. Цена измерима — в разы больше байт на клиента, просевшая конверсия на медленной первой загрузке и трафик, который растёт вместе с аудиторией.
Ниже разбираем, как это закрывается: где именно теряется сжатие, какие правила это ловят и как отдавать подготовленные архивы вместо работы на каждый запрос.
Что даёт правильное сжатие: время отклика и объём
Объём передачи
Сжимаются текстовые ресурсы: разметка, стили, скрипты, ответы API в JSON. На типовом фронтенде это 60–80% веса страницы, и после настройки они уходят в 3–5 раз меньшим потоком. Картинки, видео и шрифты уже сжаты форматом — их из политики исключают, чтобы не тратить процессор впустую.
Время отклика
Меньше байт на провод — быстрее первый отрисованный экран, особенно на мобильных сетях и в дальних регионах. Brotli на статике отдаёт заметно меньший объём, чем gzip на том же уровне: разница в размере достигает 15–25% на стилях и скриптах. Для динамики включают сжатие на лету с умеренным уровнем — выигрыш по времени перевешивает стоимость.
Нагрузка на процессор
Сжатие стоит циклов, поэтому его разводят по типам контента и уровням. Статику готовят заранее и кешируют, динамику сжимают на низком уровне, мелкие ответы не трогают вовсе — на них заголовки весят больше тела. Так процессор занят только там, где это реально сокращает передачу.
Устойчивость под нагрузкой
Экономия канала — это запас на пиках. Когда трафик вырастает в разы, узкое место смещается с полосы на сами сервисы, и сайт держит наплыв без расширения канала. Отдача статики ускоряется ещё и за счёт кеша на границе сети: сжатый ответ отдаётся из него, не доходя до приложения.
Что проверяем после настройки
Замеряем долю сжатых ответов, фактический коэффициент по типам файлов и загрузку процессора в часы пик. Правки вносим по цифрам, а не «на глаз»: видно, какие форматы оставить в политике, а какие — исключить.
Где включать компрессию: варианты и ограничения
Точку включения выбирают по тому, кто владеет ответом и где уместно тратить процессор. Компрессия — звено цепочки доставки: приложение формирует тело, обратный прокси маршрутизирует запросы, веб-сервер отдаёт статику, периметр — кэш. Сжимать в двух местах подряд нельзя: повторная обработка уже сжатого тела ломает ответ, поэтому точка выбирается одна.
Критерии выбора: управление списком типов и минимальной длиной ответа, наличие Vary: Accept-Encoding для корректной работы кэшей, цена процессорного времени на запрос и возможность хранить готовые архивы.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Сжатие на веб-сервере | Смешанный трафик: статика и ответы приложения идут через один сервер, нужны гибкие правила по типам | Список типов и порог длины задаются вручную; ошибка в правилах даёт либо несжатый ответ, либо лишнюю нагрузку |
| Сжатие на обратном прокси | Несколько сервисов за одним входом, нужны единые правила и кэш сжатых ответов | Сжимает по заголовкам, содержимое не видит; при кэшировании варианты надо разделять по Accept-Encoding |
| Предварительная подготовка файлов | Статика, которая меняется редко: сборка сразу кладёт рядом .gz и .br |
Только файлы на диске; динамику не покрывает, архивы нужно пересобирать при каждом обновлении |
| Сжатие на периметре доставки | Геораспределённая аудитория и большой объём статики | Настройки зависят от площадки; часть ответов идёт мимо, если сжатие уже выполнено на источнике |
| Сжатие в приложении | Ответы формируются на лету и не проходят через общий сервер | Процессорное время тратится на каждый запрос, сложнее кэшировать и отлаживать |
Порядок работ: от аудита отдачи до проверки в проде
Сжатие — это не одна директива в конфиге, а цепочка решений: что жать, на каком узле ставить компрессию и как не сломать уже сжатые форматы вроде изображений и видео. Ниже — порядок, по которому мы ведём внедрение: эффект предсказуем, а откат занимает минуты.
-
Аудит отдачи. Снимаем реальные размеры ответов по типам контента: разметка, стили, скрипты, шрифты, ответы API. Смотрим, что уже приходит сжатым от периметра. На выходе — список типов, где сжатие даёт выигрыш, и тех, где оно только тратит ресурс.
-
Схема обработки запроса. Фиксируем, на каком узле применяется компрессия и что сжимает периметр. Двойное сжатие одного ответа — это нагрузка без выигрыша в размере.
-
Настройка компрессии. Включаем gzip как базовое покрытие и Brotli для клиентов, которые его поддерживают: на текстовых типах он даёт меньший размер. Задаём уровень сжатия, минимальный размер ответа, список типов и исключения для уже сжатых форматов; сжатый и несжатый вариант должны корректно разделяться в кэше.
-
Проверка перед выкаткой. Сравниваем размер и время отдачи до и после на стенде, отдельно на холодном и тёплом кэше, прогоняем ключевые страницы и ответы API.
-
План отката. Конфигурация версионируется, изменения уезжают одной правкой, которую снимают без пересборки приложения. Заранее фиксируем метрики, по которым считаем выкатку неудачной.
-
Выкатка и передача. Раскатываем сначала на часть трафика, следим за долей сжатых ответов и временем отдачи, затем включаем полностью. Передаём команде конфиги, схему и короткую инструкцию по проверке после релиза.
Конфигурации, схемы и регламенты на выходе
Мы передаём не только работающий сервер, но и набор артефактов, по которым сжатие дальше ведётся своими силами. Каждый документ привязан к конкретному месту в конфигурации, поэтому логику правил не приходится восстанавливать по истории правок.
- Готовые конфигурации сервера: уровни сжатия для статики и динамики, порог минимального размера ответа, работа с предсжатыми файлами — с пояснением, почему выбраны именно эти значения.
- Схема обработки запроса: путь от клиента до отдачи через прокси, кэш и приложение, место сжатия в этой цепочке и точки, где ответ может пройти мимо него.
- Политики исключений: перечень типов файлов, которые сжимать бессмысленно — изображения, видео, архивы, уже упакованные форматы.
- Регламент изменений: как правки списков и уровней проходят проверку до выката, что фиксируется в истории и по какому условию откатывается.
- Документация по отдаче: какие заголовки сервер обязан вернуть, как убедиться, что ответ пришёл сжатым, куда смотреть при жалобе на медленную загрузку.
- Набор проверок и метрик: доля ответов со сжатием, объём передаваемых данных до и после, время отдачи и частота ошибок сжатия.
- Инструкция по поддержке: где менять исключения и уровни, как добавить новый тип файлов и на что это повлияет.
Кейс: ускорили отдачу каталога без замены серверов
Каталог крупного поставщика: десятки тысяч карточек, тяжёлые шаблоны, много текста и разметки в каждом ответе. Замеры показали, что узкое место не в сервере и не в базе — процессор и диск были загружены наполовину, а страница тормозила именно на передаче. Ни один текстовый ответ не уходил сжатым: настройку отключили ещё при первичной установке и с тех пор к ней не возвращались.
Замеры до внедрения
Средняя страница каталога весила около 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, стили, шрифты, статика;
- схему кэширования: промежуточный прокси, сеть доставки контента, версионирование файлов;
- запас по процессору на узлах, которые сжимают трафик, и профиль пиковой нагрузки;
- окружения и порядок выпуска: как изменение доезжает до продакшена и есть ли тестовый контур;
- требования к откату и окна, когда конфигурацию можно переключать без риска;
- метрики, по которым вы судите о результате: время ответа, объём трафика, нагрузка на процессор, доля попаданий в кэш.
На выходе вы получаете план работ: что включаем, в каком порядке, чем проверяем эффект и как откатываем за один шаг. Опишите задачу — вернёмся с оценкой и планом, а после согласования назначим старт проекта.







