gzip

22 сентября 2026 · ~17 мин чтения

сжатие формат-данных веб nginx http история

gzip

gzip — это одновременно утилита, формат файла и алгоритм сжатия без потерь.
Внутри — алгоритм DEFLATE (сочетание LZ77 и кодов Хаффмана), снаружи —
маленький заголовок и контрольная сумма. Один и тот же gzip лежит в файлах
.tar.gz на сервере и в заголовке Content-Encoding: gzip, которым браузер
и веб-сервер договариваются передавать страницу в сжатом виде.

История

История gzip — это история про патенты. В конце 1980-х стандартом сжатия в
Unix-мире была утилита compress, основанная на алгоритме LZW (Лемпел — Зив —
Велч, 1984). В 1983 году компания Sperry (позже Unisys) получила патент на LZW,
а к началу 1990-х начала требовать лицензионные отчисления с тех, кто его
использовал. Тот же LZW сидел внутри формата GIF, что позже привело к
знаменитому скандалу «GIF tax» в 1994–1995 годах.

Проект GNU не мог позволить себе патентованный алгоритм в свободном
софте. Жан-Лу Гайи (Jean-loup Gailly) и Марк Адлер (Mark Adler) написали
замену. Первая публичная версия gzip 0.1 вышла 31 октября 1992 года, версия
1.0 — в феврале 1993 года. Гайи написал алгоритм сжатия, Адлер —
распаковку и, чуть позже, контрольную сумму Adler-32 для соседнего проекта.

Ключевые вехи:

Сегодня утилита gzip — часть проекта GNU, сопровождает её Джим Мейеринг
(Jim Meyering) и другие. Библиотеку zlib по-прежнему сопровождает Марк
Адлер — больше 30 лет. Текущая версия утилиты — 1.13 или новее (2023 год),
точную версию у себя смотри gzip --version.

Что это такое

Слово «gzip» означает три разные вещи, и путаница между ними — главный
источник непонимания.

Утилита. Программа gzip в командной строке: берёт файл report.json,
пишет report.json.gz и удаляет оригинал. Обратно — gunzip или
gzip -d. Сжимает один файл, не умеет архивировать папки. Именно поэтому
в Unix-мире папки сначала склеивают в один файл утилитой tar (tape
archive, архив для ленты), а потом сжимают — отсюда .tar.gz.

Формат. Файл .gz — это 10 байт заголовка (магические байты 1f 8b,
метод сжатия, флаги, время, имя ОС), опционально имя исходного файла, потом
поток DEFLATE, потом 8 байт хвоста: контрольная сумма CRC-32 и размер
исходных данных. Формат описан в RFC 1952 и не менялся с 1996 года.

Алгоритм. Строго говоря, у gzip нет собственного алгоритма — внутри
всегда DEFLATE. Но в разговоре «сжать gzip-ом» означает «сжать DEFLATE-ом
и завернуть в gzip-контейнер».

Теперь про соседей, с которыми gzip путают чаще всего.

gzip vs zip. Zip — архив: много файлов, каталог в конце, у каждого
файла свой метод сжатия (обычно тот же DEFLATE). Gzip — один поток, один
файл, никакого каталога. Zip можно распаковать частично (вытащить один файл
из тысячи), gzip — только целиком с начала. Зато gzip можно писать и читать
потоком, не зная заранее размер, а это ровно то, что нужно веб-серверу.

gzip vs zlib vs DEFLATE. Один и тот же сжатый поток можно завернуть в
три обёртки: голый DEFLATE (RFC 1951, без заголовка вообще), zlib
(RFC 1950, 2 байта заголовка и Adler-32 в хвосте), gzip (RFC 1952,
10 байт заголовка и CRC-32). В HTTP есть Content-Encoding: deflate
и он, по иронии, на практике означает zlib-обёртку, а некоторые старые
серверы слали голый DEFLATE. Из-за этой путаницы все давно используют
только gzip.

gzip vs Brotli vs Zstandard. Это три разных алгоритма для одной задачи.
Brotli использует встроенный словарь из 120 килобайт типичных фрагментов
веб-текста, поэтому HTML/CSS/JS сжимает на 15–25 % плотнее. Zstandard
быстрее всех при сравнимой плотности и умеет обучаемые словари. Gzip
проигрывает обоим по цифрам, но выигрывает тем, что его понимает каждый
клиент, написанный после 1997 года.

Сжатие без потерь vs с потерями. Gzip — без потерь: распакованное
байт в байт равно исходному. JPEG, MP3, WebP — с потерями: они выбрасывают
то, что человек не заметит. Gzip поверх JPEG почти ничего не даёт, потому
что «лишнее» оттуда уже выброшено, а оставшееся выглядит как шум.

Аналогии из жизни

Конспект лекции с сокращениями. Ты пишешь конспект и на первой
странице вводишь «ДР = директор по развитию», дальше пишешь только «ДР».
Это LZ77: вместо повторного текста — ссылка на то место, где он уже
встречался. Вторая часть — коды Хаффмана: часто встречающимся словам
даёшь короткие сокращения, редким — длинные.
Где ломается: конспект читает человек, который держит в голове все
сокращения. DEFLATE «помнит» только последние 32 килобайта. Если повтор
случился дальше, чем 32 КБ назад, ссылка на него невозможна — придётся
писать заново. Именно поэтому Brotli с его большим окном и словарём
сжимает плотнее.

Вакуумный пакет для одежды. Пуховик занимает полшкафа; выкачиваешь
воздух — он становится плоским; открываешь — снова пуховик, ничего не
потерялось. Так gzip работает с текстом: в тексте много «воздуха»
(повторов), после сжатия он занимает в 5–10 раз меньше.
Где ломается: из кирпича воздух не выкачаешь. Уже сжатые данные
(JPEG, MP4, другой .gz) не содержат повторов, и gzip их не уменьшит,
а иногда даже чуть увеличит за счёт своего заголовка. Вторая трещина:
вакуумный пакет открывается за секунду, а распаковка gzip хоть и быстрая
(сотни мегабайт в секунду), но не бесплатная — на слабом телефоне
это заметно.

Морзянка. Сэмюэл Морзе в 1830-х дал самой частой букве английского
языка E самый короткий код (одна точка), а редкой Q — длинный (тире-тире-
точка-тире). Это ровно идея Хаффмана, только Хаффман в 1952 году доказал,
как строить такие коды оптимально для любого распределения.
Где ломается: у Морзе таблица одна на все времена, а Хаффман в DEFLATE
строит новую таблицу для каждого блока данных и передаёт её вместе с
данными. Для очень маленьких файлов (до сотни байт) сама таблица может
весить больше, чем экономия. Поэтому nginx по умолчанию не сжимает ответы
короче 20 байт, а разумный порог — около 1 килобайта.

Как это работает

Разберём DEFLATE пошагово — без формул, но честно.

Шаг 1. LZ77: найти повторы. Алгоритм идёт по данным слева направо и
держит «скользящее окно» из последних 32 КБ уже пройденного текста. Для
каждой позиции он ищет: не встречалась ли такая же последовательность байт
раньше, в пределах окна? Если нашёл повтор длиной от 3 до 258 байт,
вместо самих байт записывает пару (расстояние назад, длина). Если не
нашёл — записывает байт как есть («литерал»).

Пример. Строка из JSON-файла:

{"campaign":"Kazan","region":"Kazan","status":"ok"}

Второе Kazan LZ77 запишет как «вернись на 21 байт назад, скопируй 5».
Пара вместо пяти байт. В настоящем JSON с тысячами строк одинаковой
структуры такие ссылки — почти весь файл: ключи "campaign",
"region", "status" повторяются в каждой записи. Вот почему JSON
и логи сжимаются в 7–10 раз, а месячный файл из 1,2 МБ превращается в
167 КБ.

Шаг 2. Хаффман: короче кодировать частое. После первого шага у нас
поток из литералов, длин и расстояний. Второй шаг строит для них дерево
кодов: чем чаще символ, тем короче битовая последовательность. Пробел и
буква «е» в русском тексте получат 3–4 бита вместо 8, а редкая «ъ» —
11–12 бит. Итог всё равно короче, потому что редкое встречается редко.

DEFLATE использует два дерева: одно для литералов и длин (вместе, чтобы
декодер по первому же коду понимал, что дальше), другое для расстояний.
Деревья либо стандартные (заранее известные, для маленьких блоков), либо
«динамические» — строятся под конкретный блок и записываются в его начало.

Шаг 3. Уровни сжатия. Ключ -1-9 (по умолчанию -6) управляет
только первым шагом: насколько усердно искать самое длинное совпадение.
-1 берёт первое попавшееся, -9 перебирает цепочки до 4096 кандидатов.
Разница по размеру между -6 и -9 обычно 1–3 %, по времени — в 2–5 раз.
Поэтому -6 и стал умолчанием, а nginx по умолчанию ставит вообще 1.

Шаг 4. Обёртка. Готовый поток DEFLATE оборачивают в gzip-контейнер:

1f 8b            магические байты (так файл опознают по содержимому)
08               метод: DEFLATE (единственный, что существует)
flags, mtime, xfl, OS   ещё 7 байт
[имя файла]      если есть
...DEFLATE...    сжатые данные
CRC-32           4 байта, контроль целостности
ISIZE            4 байта, размер оригинала по модулю 2^32

CRC-32 в хвосте — это защита: если файл повредился при передаче,
распаковщик скажет «crc error» вместо того, чтобы молча отдать мусор.

Как это выглядит в HTTP. Последовательность из четырёх шагов:

  1. Браузер шлёт запрос с заголовком Accept-Encoding: gzip, deflate, br, zstd — «вот что я умею распаковывать».
  2. Сервер смотрит на тип ответа. Если это текст (HTML, CSS, JS, JSON, SVG)
    и клиент умеет gzip — сжимает на лету.
  3. Ответ уходит с заголовками Content-Encoding: gzip и Vary: Accept-Encoding. Второй заголовок говорит кешам: «у этого URL есть
    разные версии для разных клиентов, не отдавай сжатую тому, кто её не
    просил».
  4. Браузер распаковывает и отдаёт JavaScript-коду уже обычный текст. Код
    на странице, fetch(), сам JSON — ничего не подозревают, что по сети
    ехало сжатое.

Важная деталь для nginx: директива gzip on включает механизм, но
какие типы сжимать решает gzip_types. По умолчанию там только
text/html. Без явной строки gzip_types application/json text/css application/javascript ... JSON и скрипты поедут в несжатом виде — при
включённом gzip. Это классические грабли: «сжатие включено, а файлы не
сжимаются».

Проверяй результат, а не конфиг

«gzip on» в конфиге не значит, что конкретный файл сжимается. Единственная честная проверка — запросить файл как браузер и посмотреть заголовки: curl -sI -H 'Accept-Encoding: gzip' https://host/data/2026-03.json | grep -i content-encoding. Если строки Content-Encoding: gzip нет — сжатие для этого типа не работает, что бы ни было написано в nginx.conf.

Есть ещё gzip_static: nginx может не сжимать на лету, а отдавать заранее
подготовленный file.json.gz, если он лежит рядом. Это снимает нагрузку с
процессора и позволяет сжать один раз на -9, а не каждый запрос на 1.

Где встречается в обычной жизни

Где встречается в IT и бизнесе

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

Кто пользуется

Масштаб можно оценить так: zlib — одна из самых массово установленных
библиотек в истории. Она есть на каждом смартфоне, каждом сервере, каждом
роутере. Марк Адлер однажды заметил, что zlib стоит и на марсоходе
(в софте наземной обработки снимков) — точную цитату найди по запросу
«Mark Adler zlib Mars».

Альтернативы и конкуренты

Brotli (Google, 2015, RFC 7932).
Плюсы: на 15–25 % плотнее gzip для веб-текста благодаря встроенному
словарю; поддерживается всеми современными браузерами; уровни 4–5
сжимают на лету не медленнее gzip -6.
Минусы: только через HTTPS (браузеры не шлют br по HTTP); высокие уровни
(9–11) очень медленные, годятся только для предварительного сжатия; в
nginx нужен отдельный модуль; старые клиенты и корпоративные прокси могут
его не понимать.

Zstandard / zstd (Facebook, 2016, RFC 8878).
Плюсы: самый быстрый из современных при сравнимой с gzip плотности;
масштабируется от «быстрее gzip -1» до «плотнее gzip -9»; обучаемые
словари для маленьких однотипных сообщений; стандарт де-факто для
бэкапов, логов и внутреннего транспорта.
Минусы: в браузерах появился только в 2024 году; поддержка в CDN и
веб-серверах ещё неровная; для веб-статики Brotli всё равно плотнее.

xz / LZMA (2009, Лассе Коллин).
Плюсы: сжимает плотнее всех перечисленных — на 30 % лучше gzip на
исходниках; стандарт для дистрибутивов Linux и архивов исходников.
Минусы: медленное сжатие и заметно медленная распаковка; в вебе не
используется; после инцидента с бэкдором в xz-utils в марте 2024 года
(CVE-2024-3094) доверие к проекту пришлось восстанавливать.

bzip2 (1996, Джулиан Сьюард).
Плюсы: плотнее gzip на 10–15 % для текста; проверенный временем.
Минусы: медленнее gzip и по сжатию, и по распаковке; вытеснен xz и zstd;
сейчас скорее историческое наследие.

Не сжимать вообще.
Плюсы: ноль процессорного времени, ноль сложности, ноль ошибок
конфигурации.
Минусы: платишь трафиком и временем ответа; для текстовых данных это
проигрыш в 5–10 раз без каких-либо преимуществ.

Когда НЕ стоит использовать

Сжатие — это не про размер, а про повторы

Gzip не «уменьшает файл», он «убирает повторы и уплотняет частое». Из этого следуют все правила: текст сжимается, картинки нет; длинный JSON сжимается лучше короткого; одинаковая структура записей — лучший друг сжатия; шифрование до сжатия убивает эффект (шифротекст выглядит как шум), поэтому всегда сначала сжимай, потом шифруй — именно так и делает TLS.

Связанные понятия

Литература и источники

Где встретилось у меня

Вчера в проекте дашборда по переводам из CRM для агентства ты переводил
отчёт на «догрузку по месяцам»: горячее окно в index.html, архив по
месяцам в отдельных JSON-файлах по 1–1,7 МБ. Выяснилось, что в nginx
gzip on стоит, а gzip_types закомментирован, и JSON летел несжатым.
После добавления application/json в gzip_types месячный файл поехал
в 167 КБ вместо 1,2 МБ — в семь раз меньше. Установщик прогнал
оркестратор, а факт зафиксирован в правилах и README проекта.

Краткое резюме