Налаштування стиснення 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
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1140