gzip
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 для соседнего проекта.
Ключевые вехи:
- 1993 — gzip 1.0. Внутри — DEFLATE, который Фил Кац (Phil Katz) придумал
для PKZIP в конце 1980-х. Кац алгоритм не патентовал, и это оказалось
решающим: DEFLATE сочетал LZ77 (1977 год, Лемпел и Зив) и коды Хаффмана
(1952 год, Дэвид Хаффман), и оба были свободны. - 1995 — библиотека zlib тех же авторов. Она вынесла DEFLATE в отдельный
код, который можно встроить в любую программу. Сегодня zlib есть в
практически каждой операционной системе, браузере, в Python, Java, Go,
PostgreSQL и тысячах других мест. - Май 1996 — RFC 1950 (zlib), RFC 1951 (DEFLATE) и RFC 1952 (формат gzip).
Три коротких документа зафиксировали формат навсегда: файл, сжатый в 1996
году, распакуется любым современным gzip. - 1997 — HTTP/1.1 (RFC 2068, затем RFC 2616) официально описал
Content-Encoding: gzip. С этого момента веб начал жить в сжатом виде. - 2003 — истёк патент Unisys на LZW в США.
compressэто уже не спасло:
gzip победил окончательно. - 2010-е — появление конкурентов: Brotli от Google (2013–2015) и Zstandard
от Facebook (2016). Они лучше по цифрам, но gzip остаётся тем форматом,
который поддерживается буквально везде.
Сегодня утилита 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. Последовательность из четырёх шагов:
- Браузер шлёт запрос с заголовком
Accept-Encoding: gzip, deflate, br, zstd— «вот что я умею распаковывать». - Сервер смотрит на тип ответа. Если это текст (HTML, CSS, JS, JSON, SVG)
и клиент умеет gzip — сжимает на лету. - Ответ уходит с заголовками
Content-Encoding: gzipиVary: Accept-Encoding. Второй заголовок говорит кешам: «у этого URL есть
разные версии для разных клиентов, не отдавай сжатую тому, кто её не
просил». - Браузер распаковывает и отдаёт 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.
Где встречается в обычной жизни
- Открываешь любой сайт. По разным оценкам, больше 80 % страниц в
интернете едут в браузер сжатыми — gzip или Brotli. Вкладка «Network»
в инструментах разработчика показывает две цифры размера: «transferred»
(сколько проехало по сети) и «size» (сколько получилось после
распаковки). Разница — это и есть gzip. - Скачиваешь программу для Linux или macOS через терминал. Файлы
something-1.2.3.tar.gz— этоtar(склейка папки в один файл) плюс gzip.
Командаtar xzfв одну строку распаковывает и то и другое. - Обновление прошивки роутера, телевизора, умной колонки. Образы
прошивок почти всегда сжаты, и очень часто именно gzip — потому что
распаковщик zlib помещается в несколько килобайт и есть на любом чипе. - Логи на сервере. Утилита
logrotateкаждую ночь переименовывает
вчерашний лог и сжимает его:access.log.1.gz,access.log.2.gz.
Текстовые логи сжимаются в 10–20 раз, поэтому год логов помещается туда,
куда без сжатия влез бы месяц. - Файлы PDF и документы Office. Внутри PDF потоки текста и векторной
графики сжаты DEFLATE-ом (там он называетсяFlateDecode). Файлы
.docxи.xlsx— это zip-архивы с XML внутри, и тот же DEFLATE.
Именно поэтому «документ» в 30 страниц весит 40 КБ.
Где встречается в IT и бизнесе
- Сжатие ответов API и статики. Нужно, когда отдаёшь JSON, HTML, CSS,
JS. Экономия трафика 70–90 %, ускорение загрузки — особенно на
мобильных сетях. Включается на веб-сервере (nginx, Apache, Caddy) или
на CDN (Cloudflare сжимает сам). - Хранение логов и бэкапов. Нужно, когда данных много и читают их
редко. Дамп PostgreSQL черезpg_dump | gzipуменьшается в 5–10 раз.
Стоимость дискового места в облаке падает пропорционально. - Архивы данных для аналитики. Форматы CSV и JSON-строк принято
хранить как.csv.gzи.jsonl.gz; pandas, ClickHouse, BigQuery,
Spark читают их напрямую без ручной распаковки. - Транспорт между сервисами. gRPC и большинство HTTP-клиентов умеют
сжимать тела запросов. Нужно, когда сервисы в разных дата-центрах и
платишь за трафик между ними. - Дистрибуция софта. Пакеты Debian (
.deb), исходники ядра Linux,
Docker-слои (tar.gzв реестре образов) — всё поверх gzip или его
наследников.
Для бизнеса это переводится так: сжатие текстовых ответов — самая дешёвая
оптимизация скорости сайта из существующих. Одна строчка в конфиге даёт
больше, чем неделя оптимизации кода. И наоборот: если сжатие сломано или
не включено для нужного типа, дашборд, который «должен грузиться за
секунду», грузится десять.
Кто пользуется
- Каждый браузер (Chrome, Safari, Firefox, Edge) поддерживает gzip с
конца 1990-х. Brotli — с 2016–2017 годов, Zstandard — Chrome с версии
123 (2024 год), Firefox с 126. - nginx — самый распространённый веб-сервер мира (по данным W3Techs,
около трети всех сайтов); модульngx_http_gzip_moduleвстроен
по умолчанию. Apache — модульmod_deflate. - Cloudflare — по их собственным данным, обслуживает примерно 20 %
веб-трафика; сжимает ответы Brotli, gzip или Zstandard в зависимости от
клиента. - Google — ещё в 2009 году в блоге про скорость веба заявляли, что
сжатие экономит им десятки процентов трафика; тогда же начали проект
Zopfli (2013) — генератор DEFLATE-потоков, совместимых с gzip, но на
3–8 % плотнее ценой в сотни раз более медленного сжатия. - Linux и все Unix-подобные системы — ядро Linux само распаковывает
gzip при загрузке (образ ядраvmlinuzтрадиционно сжат gzip,
сейчас чаще zstd или xz). - Git — каждый объект в репозитории хранится сжатым zlib. Когда ты
делаешьgit push, по сети едут сжатые pack-файлы. - PNG — весь формат изображения построен на zlib поверх фильтров
предсказания. Каждая иконка на каждом сайте — это DEFLATE.
Масштаб можно оценить так: 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 раз без каких-либо преимуществ.
Когда НЕ стоит использовать
- Для уже сжатых данных. JPEG, PNG, WebP, MP4, MP3, PDF,
.zip,
.gz— сжимать бесполезно: выигрыш 0–2 %, а процессор тратится на
каждый запрос. Именно поэтому вgzip_typesперечисляют только
текстовые типы, а не ставят*. Потому что повторов там уже нет. - Для очень маленьких ответов. Ответ в 100 байт после gzip станет
120 байт: заголовок и таблица Хаффмана весят больше экономии. Порог
gzip_min_lengthв nginx стоит 20 байт по умолчанию, разумно поднять
до 1000. Потому что математика сжатия работает на повторах, а в
100 байтах их нет. - Когда сжимаешь секреты вместе с данными, которые контролирует
злоумышленник. Атаки CRIME (2012) и BREACH (2013) показали: если в
одном сжатом HTTPS-ответе лежат и секретный токен, и текст, который
атакующий может подставлять, то по размеру ответа можно посимвольно
угадать токен. Потому что gzip сожмёт совпавший кусок сильнее, и это
видно в длине. Практическое правило: CSRF-токены и сессионные секреты
не должны оказываться в сжимаемом теле вместе с отражённым
пользовательским вводом. - Когда нужен произвольный доступ внутрь файла. Достать одну запись
из середины 10-гигабайтного.jsonl.gzнельзя без чтения всего, что
до неё. Потому что каждая ссылка LZ77 указывает назад, и без
предыдущих 32 КБ ничего не распакуешь. Для таких задач — Parquet,
bgzip (блочный gzip из биоинформатики) или zstd с точками
синхронизации.
Сжатие — это не про размер, а про повторы
Gzip не «уменьшает файл», он «убирает повторы и уплотняет частое». Из этого следуют все правила: текст сжимается, картинки нет; длинный JSON сжимается лучше короткого; одинаковая структура записей — лучший друг сжатия; шифрование до сжатия убивает эффект (шифротекст выглядит как шум), поэтому всегда сначала сжимай, потом шифруй — именно так и делает TLS.
Связанные понятия
- DEFLATE — сам алгоритм внутри gzip, zlib, zip и PNG: LZ77 плюс
Хаффман, описан в RFC 1951. - LZ77 — метод замены повтора ссылкой «назад на N байт, длина M»;
основа почти всех современных компрессоров без потерь. - Коды Хаффмана — способ построить оптимальные префиксные коды
переменной длины по частотам символов. - Content-Encoding / Accept-Encoding — заголовки HTTP, через которые
клиент и сервер договариваются о сжатии тела ответа. - Vary — заголовок, который сообщает кешам, что ответ различается по
какому-то заголовку запроса; безVary: Accept-Encodingкеш может
отдать сжатое тому, кто сжатие не понимает. - CRC-32 — контрольная сумма для проверки целостности; gzip хранит её
в хвосте файла. - tar — склейка папки в один файл без сжатия; в паре с gzip даёт
.tar.gz. - Энтропия Шеннона — теоретический предел: ниже него сжать без потерь
нельзя, и чем ближе данные к случайному шуму, тем ближе они к пределу.
Литература и источники
- RFC 1951 «DEFLATE Compressed Data Format Specification» (1996, en) —
https://www.rfc-editor.org/rfc/rfc1951. Всего 17 страниц, читается за
вечер. - RFC 1952 «GZIP file format specification» (1996, en) —
https://www.rfc-editor.org/rfc/rfc1952. Формат заголовка и хвоста. - Wikipedia: «gzip» (en) — https://en.wikipedia.org/wiki/Gzip и «Deflate»
(en) — https://en.wikipedia.org/wiki/Deflate. Русские версии есть, но
английские полнее. - Документация nginx, модуль ngx_http_gzip_module —
https://nginx.org/ru/docs/http/ngx_http_gzip_module.html. Все директивы
с умолчаниями, на русском. - Julia Evans, серия иллюстрированных заметок о том, как работает gzip
(en) — искать по запросу «Julia Evans gzip explained». Самое понятное
объяснение LZ77 и Хаффмана на картинках. - Дэвид Саломон, «Сжатие данных, изображений и звука» (ru, 2004; оригинал
«Data Compression: The Complete Reference», 5-е изд., 2010, en) —
энциклопедия по всем алгоритмам, если захочется глубже. - Статья Хаффмана 1952 года «A Method for the Construction of
Minimum-Redundancy Codes» (en) — 4 страницы, искать по названию;
исторический документ, который до сих пор актуален.
Где встретилось у меня
Вчера в проекте дашборда по переводам из CRM для агентства ты переводил
отчёт на «догрузку по месяцам»: горячее окно в index.html, архив по
месяцам в отдельных JSON-файлах по 1–1,7 МБ. Выяснилось, что в nginx
gzip on стоит, а gzip_types закомментирован, и JSON летел несжатым.
После добавления application/json в gzip_types месячный файл поехал
в 167 КБ вместо 1,2 МБ — в семь раз меньше. Установщик прогнал
оркестратор, а факт зафиксирован в правилах и README проекта.
Краткое резюме
- gzip — это утилита, формат и обёртка над алгоритмом DEFLATE (LZ77 +
Хаффман); придуман в 1992 году Гайи и Адлером как свободная замена
патентованномуcompress. - Сжимает, убирая повторы в окне 32 КБ и кодируя частое короче; поэтому
текст, JSON и логи ужимаются в 5–10 раз, а картинки и видео — никак. - В вебе включается заголовками
Accept-Encoding/Content-Encoding;
в nginxgzip onбезgzip_typesсжимает только HTML — это главные
грабли. - Проверяй не конфиг, а факт:
curl -I -H 'Accept-Encoding: gzip'и
смотриContent-Encodingв ответе. - Brotli и Zstandard плотнее и быстрее, но gzip остаётся универсальным
минимумом, который понимает любой клиент с 1997 года.