Zstd, Brotli и Gzip: что выбрать для сжатия API
Сравнение Zstd, Brotli и Gzip для сжатия ответов API: скорость, степень сжатия, задержка, поддержка клиентами и практические рекомендации внедрения.

Зачем вообще сжимать ответы API
Сжатие ответов API — это простой способ уменьшить объём данных, которые сервер отправляет клиенту. Для пользователя это часто означает более быстрые ответы и меньший расход трафика, а для бизнеса — экономию на передаче данных (egress) и более предсказуемую нагрузку на сеть.
Что в API обычно сжимают
Чаще всего сжимают текстовые форматы, которые хорошо «складываются» за счёт повторяющихся полей и структур:
- JSON (самый частый кандидат): ключи, одинаковые названия полей и типовые значения дают заметный выигрыш.
- XML: как правило, сжимается ещё лучше из‑за большого количества тегов.
- Текст: CSV, лог‑фрагменты, HTML (реже в API), GraphQL‑ответы.
А вот уже сжатые или плохо сжимаемые данные (JPEG/PNG, MP4, PDF, protobuf в некоторых схемах) обычно дают меньший эффект — иногда их вообще выгоднее не трогать.
Что вы выигрываете
-
Меньше трафика: особенно заметно на крупных JSON‑ответах и при высокой частоте запросов.
-
Меньше время передачи: чем меньше байтов надо «протолкнуть» по сети, тем ниже время загрузки, особенно на мобильных сетях и при высокой RTT.
-
Меньше стоимость egress: актуально для облаков и публичных API, где оплата часто зависит от объёма исходящего трафика.
Что вы теряете
Сжатие не бесплатное:
- CPU на сервере (сжать) и на клиенте (распаковать).
- Дополнительная задержка на стороне сервера, если выбран высокий уровень сжатия или ответы маленькие (на них оверхед может «съесть» пользу).
- Сложности совместимости: нужно учитывать, что поддерживает клиент (заголовок
Accept-Encoding), и иметь корректный фолбэк.
Почему выбор алгоритма зависит от сценария
Один и тот же алгоритм может быть идеальным в одном случае и спорным в другом.
- Для мобильных клиентов важны экономия трафика и стабильность на плохих сетях.
- Для внутренних микросервисов часто важнее минимальная задержка и CPU, потому что сеть быстрая, а запросов много.
- Для публичного API приходится балансировать всё сразу: совместимость, стоимость трафика и нагрузку на инфраструктуру.
Базовые принципы: что влияет на скорость и размер
Сжатие ответа — это обмен «время CPU на сервере/клиенте» на «меньше байт по сети». Итоговую скорость определяет не только то, насколько хорошо алгоритм уменьшает размер, но и сколько времени уходит на (де)сжатие, плюс сетевые накладные расходы.
Идея словарей и энтропийного кодирования (очень коротко)
Большинство современных алгоритмов (и Gzip, и Brotli, и Zstd) опираются на два базовых шага:
-
Поиск повторов: алгоритм замечает, что куски данных повторяются (например, ключи JSON, одинаковые строки, повторяющиеся структуры) и заменяет повтор на короткую ссылку назад — условно «это уже было вот там».
-
Энтропийное кодирование: когда данные стали «более предсказуемыми» (много коротких ссылок, частые символы), их упаковывают так, чтобы частое занимало меньше бит, а редкое — больше.
Отдельная тема — словари: это заранее известный набор типичных фрагментов (например, характерные поля вашего JSON). Словарь помогает сжимать даже там, где внутри одного ответа повторов мало.
Что означает «уровень сжатия» и почему он влияет на CPU
«Уровень» почти всегда означает степень усердия: насколько глубоко алгоритм ищет повторы и насколько тщательно подбирает представление.
- Выше уровень → обычно меньше размер, но медленнее сжатие (больше CPU, больше задержка на сервере).
- Ниже уровень → быстрее, но экономия трафика скромнее.
Важно: скорость распаковки часто растёт не так сильно, как скорость упаковки. Поэтому для API типичный подход — сжимать умеренно, чтобы не ухудшать p95/p99 latency.
Текст против бинарных форматов
Текст (JSON, HTML, CSS) обычно хорошо сжимается: много повторяющихся ключей, пробелов, похожих фрагментов. Бинарные форматы (Protobuf, MessagePack) уже плотнее и содержат меньше очевидных повторов, поэтому выигрыш от сжатия может быть меньше.
При этом «уже бинарное» не значит «не сжимается»: если ответы большие и однотипные, сжатие всё равно может дать эффект.
Почему маленькие ответы могут не выигрывать
У сжатия есть фиксированные накладные расходы: заголовки, служебные данные, время на запуск компрессора. Если ответ условно 200–500 байт, то:
- экономия в байтах может быть минимальной или даже отрицательной;
- а задержка на CPU и дополнительные действия в стеке HTTP становятся заметнее.
Поэтому на практике часто вводят порог размера: сжимать только ответы больше N байт и только те Content-Type, где это действительно даёт смысл (например, JSON).
Brotli: особенности и где он обычно лучший
Brotli (br) — алгоритм сжатия, который чаще всего выигрывает на текстовых ответах: HTML, CSS, JS, JSON. Его любят за то, что при той же логике доставки он часто даёт меньший размер, чем gzip, а значит уменьшает трафик и ускоряет загрузку на медленных каналах. Для API это особенно заметно на «болтливых» JSON‑ответах с повторяющимися ключами.
Поддержка в браузерах и HTTP‑клиентах
С точки зрения совместимости Brotli сегодня — почти стандарт для веба:
- Браузеры: современные версии Chrome/Chromium, Firefox, Safari и Edge поддерживают
brи отправляют его вAccept-Encoding. - Типичные HTTP‑клиенты: многие библиотеки умеют Brotli, но «из коробки» ситуация менее ровная, чем у gzip. Например, в сервер‑сервер взаимодействиях или в старых мобильных SDK иногда встречается поддержка только gzip.
Практическое правило: для публичных веб‑клиентов Brotli можно смело включать, но для широкого спектра интеграций оставляйте фолбэк на gzip через стандартную HTTP‑схему Accept-Encoding.
Где Brotli используется чаще всего
Brotli чаще выбирают там, где много текстового контента и важен размер:
- Фронтенд‑ответы: статика и SSR/HTML‑страницы.
- CDN и edge‑кэширование: многие CDN умеют отдавать Brotli на лету или хранить отдельные варианты по
Accept-Encoding. - Публичные API для браузерных приложений: JSON, GraphQL‑ответы, иногда даже XML.
Для внутренних микросервисов Brotli используют реже: там важнее суммарная CPU‑стоимость и предсказуемая задержка, а не минимальный размер любой ценой.
Сильные стороны: хороший размер на тексте
Главный плюс Brotli — эффективное сжатие текстовых форматов. На JSON это обычно выражается в меньшем размере, чем у gzip при сопоставимых настройках. Особенно хорошо работает на:
- больших ответах (десятки/сотни KB и больше);
- данных с повторяемой структурой (типичные объекты/списки);
- контенте, который легко кэшируется (потому что компрессия выполняется реже).
Если у вас API «упирается» в пропускную способность или стоимость трафика, Brotli часто даёт ощутимый эффект.
Слабые стороны: скорость сжатия на высоких уровнях и CPU
Компромисс Brotli — цена сжатия. На высоких уровнях он может:
- заметно нагружать CPU на сервере;
- увеличивать latency из‑за времени на компрессию, особенно на динамических ответах без кэша;
- требовать более аккуратной настройки порогов (например, не сжимать слишком маленькие ответы).
Поэтому типичная практика: держать Brotli включённым для текстового контента, но выбирать умеренные уровни сжатия и опираться на кэширование (на CDN или на уровне приложения), чтобы не пересчитывать компрессию на каждый запрос.
Gzip: совместимость и типичные компромиссы
Gzip — самый «понятный» и распространённый вариант компрессии для HTTP‑ответов. Во многих командах он остаётся выбором «по умолчанию» просто потому, что почти гарантированно будет поддержан клиентом и не принесёт сюрпризов в продакшене.
Почему Gzip до сих пор выбирают по умолчанию
Исторически gzip поддерживается практически везде: браузеры, мобильные SDK, HTTP‑клиенты, CDN и старые корпоративные прокси. Если у вас публичный API и вы не контролируете клиентов, gzip часто становится самым безопасным базовым уровнем: клиент прислал Accept-Encoding: gzip — вы отдали сжатый ответ; не прислал — отдали обычный.
Совместимость: клиенты, прокси, балансировщики
Главное преимущество gzip — предсказуемая совместимость по всей цепочке доставки. Даже если между сервером и потребителем стоят балансировщики, API‑шлюзы или промежуточные кэши, gzip обычно корректно проходит через них без дополнительных настроек. Это снижает риск редких багов вида «у части пользователей ответы внезапно перестали распаковываться».
На практике gzip удобно использовать как гарантированный «фолбэк» для случаев, когда более современные алгоритмы недоступны или отключены на стороне клиента.
Сильные стороны: простота и предсказуемость
Gzip легко включить в популярных веб‑серверах и прокси, легко мониторить и объяснять. Он даёт стабильный выигрыш на типичных текстовых payload’ах (JSON, HTML, CSS) и хорошо подходит для сценариев, где важнее минимизировать операционные риски, чем выжать максимум экономии трафика.
Слабые стороны: чаще хуже по размеру
Компромисс — эффективность сжатия. На JSON и других текстовых ответах gzip нередко уступает Brotli и Zstd по итоговому размеру, а значит может проигрывать по задержке на медленных сетях или при дорогом трафике.
Поэтому gzip — отличный «универсальный минимум»: включить легко, работает почти везде, но если цель — максимальная экономия трафика и лучшая скорость загрузки у клиентов, обычно есть смысл рассматривать более современные варианты (с сохранением gzip как запасного пути).
Zstd: быстрый компромисс для API
Zstandard (Zstd) часто выбирают для API, когда важны и скорость, и экономия трафика. Его сильная сторона — очень быстрая распаковка при хорошем коэффициенте сжатия, из‑за чего задержка на клиенте обычно получается небольшой даже на слабых устройствах.
Что обычно ценят в Zstd
Для API Zstd интересен тем, что «дешевле» по CPU на распаковке, чем многие альтернативы, и при этом нередко сжимает заметно лучше, чем классический Gzip на сопоставимых настройках. Это помогает снизить время передачи (особенно на медленных сетях) без резкого роста нагрузки на клиентов.
Отдельный плюс — предсказуемость: на типичных API‑ответах (JSON, иногда protobuf‑байты, логи, большие списки) Zstd даёт стабильный баланс и редко оказывается «плохим выбором», если инфраструктура его поддерживает.
Где он особенно полезен
Микросервисы. Во внутренних вызовах много однотипных JSON‑ответов, и выигрыш часто выражается в меньшей сетевой нагрузке и меньшем общем времени ответа. Если сервисы общаются через прокси/mesh, имеет смысл проверить, пропускает ли он Content-Encoding: zstd и не ломает ли кеширование.
Мобильные клиенты. Экономия трафика и более быстрая распаковка на устройстве дают приятный эффект для UX. Здесь важно убедиться, что SDK/HTTP‑клиент умеет Zstd, иначе понадобится аккуратный фолбэк.
Большие JSON‑ответы. На длинных списках, каталогах, аналитике и «тяжёлых» payload’ах Zstd часто заметно сокращает размер, а распаковка остаётся быстрой.
Уровни компрессии: «быстро» vs «сильно»
На практике для API чаще всего выбирают низкие или средние уровни: они дают хороший прирост к размеру по сравнению с отсутствием сжатия, но не увеличивают время кодирования настолько, чтобы ухудшить latency.
Простое правило: если у вас много коротких ответов и критична задержка — берите более быстрый уровень. Если ответы крупные и повторяющиеся, и серверный CPU не узкое место — можно поднять уровень и посмотреть, окупается ли дополнительное сжатие по метрикам.
Ограничения: поддержка клиентами и инфраструктурой
Главный стоп‑фактор Zstd — совместимость. Не все браузеры, CDN, прокси и корпоративные шлюзы одинаково хорошо принимают zstd в Accept-Encoding. Поэтому обычно делают так: сервер выбирает Zstd только если клиент явно его запросил, иначе отдаёт Gzip (или без сжатия), и обязательно тестируют цепочку целиком — от клиента до балансировщика и кеша.
Если вы не контролируете клиентов (публичный API), Zstd стоит включать как опцию с безопасным фолбэком, а не как единственный формат.
Как корректно сравнивать: метрики и методика тестирования
Сравнение Brotli, Gzip и Zstd «в вакууме» почти всегда приводит к неправильным выводам. Для API важно не только то, насколько уменьшается тело ответа, но и то, как это отражается на задержках и нагрузке на CPU при реальном профиле трафика.
Какие метрики сравнивать
Минимальный набор метрик, который имеет смысл собирать для API:
- Размер ответа после сжатия (bytes). Именно он влияет на время передачи по сети и на счета за трафик.
- Время сжатия на сервере (CPU time). Критично для high‑load и для «тяжёлых» уровней Brotli.
- Время распаковки на клиенте (CPU time). Важно для мобильных устройств и слабых клиентских CPU.
- End‑to‑end latency: среднее и обязательно p95/p99. Часто компрессия улучшает среднее, но может ухудшить хвосты из‑за CPU‑пиков.
- Throughput (req/s) при фиксированном бюджете CPU — полезно как интегральный показатель.
Отдельно фиксируйте, где именно меряете: «чистое» время кодека или полную серверную обработку (с сериализацией JSON, сетевым стеком и т. п.).
Почему нужно мерить на ваших данных
Кодеки по‑разному реагируют на структуру полезной нагрузки:
- Тип JSON: плоский, вложенный, с массивами объектов — меняет распределение повторов.
- Повторяемость полей и значений: одинаковые ключи, перечисления, повторяющиеся строки сжимаются лучше.
- Стабильность схемы: если поля часто меняются, выигрыши могут быть ниже.
Поэтому сравнивайте не «JSON вообще», а ваши типовые ответы: например, /users, /search, /feed, /metrics.
Рекомендованный набор тестов по размерам
Сделайте минимум три набора, чтобы не экстраполировать результаты:
- Маленькие (1–5 KB): короткие справочники, статусы, feature‑flags. Здесь важны накладные расходы и пороги включения компрессии.
- Средние (20–100 KB): типичный «рабочий» API‑ответ с объектами и списками.
- Большие (300 KB–2 MB): ленты, батчи, отчёты. Здесь обычно лучше видно различие по степени сжатия.
Для каждого набора прогоняйте несколько уровней качества (например, по 2–3 уровня на кодек), иначе сравнение будет нечестным: «максимальный Brotli» против «дефолтного gzip» редко отражает реальную эксплуатацию.
Как учитывать TLS, сеть и кеширование
Чтобы результаты были применимы:
- Отделяйте CPU от сети: сначала замерьте локально (loopback) «кодек + сериализация», затем повторите в условиях, близких к боевым (с реальной RTT/пропускной способностью).
- Учитывайте TLS: на коротких ответах задержка может быть доминирующей из‑за handshake/шифрования, и выгода от сжатия будет менее заметна.
- Кеширование: если ответы часто уходят из CDN/edge или из серверного кеша, то цена сжатия на origin меняется. В тестах явно фиксируйте сценарий: «сжатие на лету» vs «предсжатые ответы/кеш».
- Стабилизируйте окружение: одинаковое число воркеров, прогрев, отключённый autoscaling на время теста, повторяемые прогоны.
Итог: хорошая методика сравнения — это не один бенчмарк, а набор измерений, где вы видите компромисс «байты ↔ CPU ↔ хвостовые задержки» именно на ваших API‑ответах.
HTTP-нюансы: заголовки, фолбэки и совместимость
Сжатие в HTTP — это не только выбор алгоритма, но и корректная «договорённость» между клиентом и сервером. Ошибки в заголовках часто приводят к странным багам: сломанному кешу, двойному сжатию или непредсказуемому поведению через прокси.
Как работает согласование: Accept-Encoding и Content-Encoding
Клиент сообщает, какие кодеки он понимает, через Accept-Encoding. Сервер выбирает один вариант и отвечает с Content-Encoding.
Пример типичного запроса:
Accept-Encoding: br, gzip, zstd
Ответ сервера:
Content-Encoding: br
Если клиент указывает «веса» (q-values), сервер должен учитывать приоритеты:
Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1
Важно: если сервер сжимает ответ, меняется представление ресурса. Поэтому почти всегда нужно добавлять:
Vary: Accept-Encoding
Иначе общий кеш (CDN, прокси, корпоративный кеш) может сохранить сжатую версию и отдать её клиенту, который сжатие не поддерживает.
Фолбэк-стратегия: что отдавать, если алгоритм не поддержан
Правило простое: сервер выбирает лучший из поддерживаемых клиентом вариантов, иначе отдаёт «как есть» (без Content-Encoding). На практике для публичных HTTP API чаще всего безопасный порядок такой:
brдля браузерных клиентов (широкая поддержка)gzipкак универсальный запасной вариантzstd— отлично подходит для контролируемых клиентов (мобильные приложения, SDK, сервис‑к‑сервису), но поддержка на «краю» (браузеры, некоторые прокси) может быть ограничена
Если вы решаете включать zstd, убедитесь, что клиенты реально отправляют Accept-Encoding: zstd, и что промежуточные устройства не вычищают этот токен.
Особенности при прокси/шлюзах: не ломать заголовки и кеш
Прокси, API‑шлюзы и CDN часто делают две вещи: модифицируют заголовки и кешируют ответы. Отсюда ключевые проверки:
-
Не допускайте двойного сжатия. Если апстрим уже отдал
Content-Encoding: gzip, даунстрим не должен «сжать ещё раз». Обычно это решается настройкой, что сжатие выполняется в одном месте (например, на edge) и отключается на остальных слоях. -
Кеш должен различать варианты.
Vary: Accept-Encodingобязателен, иначе возможна выдача «не того» байтового представления. -
ETag/Content-Length. При сжатии меняются и длина, и хеш. Если вы генерируете
ETagна базе тела, он должен соответствовать конкретной кодировке. СContent-Lengthпроще: при потоковой отдаче сервер может перейти на chunked и не считать длину заранее.
Когда стоит отключать сжатие
Сжатие не всегда полезно. Его обычно отключают для:
- уже сжатых форматов:
image/png,image/jpeg,image/webp,video/*,audio/* - архивов и бандлов:
application/zip,application/gzip,application/x-7z-compressed,application/pdf - слишком маленьких ответов (порог по размеру), где выигрыш в трафике меньше, чем затраты CPU и задержка на компрессию
Для JSON/текста сжатие почти всегда окупается, но только если заголовки и кеширование настроены аккуратно — тогда вы получаете экономию трафика без сюрпризов в совместимости.
Практические настройки: уровни, пороги и типы контента
Настройки сжатия для API лучше начинать с простых правил, которые дают заметный выигрыш без лишней нагрузки на CPU. Здесь нет «идеального уровня»: выбор — это баланс между экономией трафика и добавленной задержкой на сжатие.
Рекомендуемые уровни по умолчанию (логика выбора)
- Gzip: уровень 5–6. Ниже (1–3) часто сжимает заметно хуже, а выше (7–9) обычно даёт небольшой прирост размера ценой ощутимых CPU‑затрат.
- Brotli: уровень 4–6 для динамических API‑ответов. Высокие уровни (9–11) хороши для статических файлов, которые можно сжать заранее, но для «на лету» могут добавить лишнюю задержку.
- Zstd: уровень 3–5. Он обычно даёт хорошее соотношение «скорость/размер» и часто выигрывает у gzip по времени при сопоставимой компрессии.
Практическое правило: если ваши p95/p99 задержки чувствительны, начинайте с умеренных уровней (gzip 5, brotli 4–5, zstd 3) и повышайте только после измерений.
Порог включения: не сжимайте мелочь
Сжатие имеет фиксированные накладные расходы (заголовки, работа CPU). Поэтому включайте его только для ответов больше N байт. Типичные стартовые значения:
- N = 1024 байта для JSON и текста: ниже экономия часто невелика.
- Если API отдаёт очень много маленьких ответов, можно поднять порог до 2–4 КБ, чтобы не раздувать CPU‑нагрузку.
Типы контента: что сжимать, а что нет
Сжимайте в первую очередь:
application/json,application/problem+jsontext/*(например,text/plain,text/csv)
Не сжимайте (обычно бесполезно или рискованно):
- уже сжатое:
image/*,video/*,application/zip,application/pdf - бинарные форматы, где выигрыш непредсказуем
Безопасность и риски
Главное правило: не сжимайте ответы, где в одном теле смешиваются секреты и отражённые данные пользователя (класс атак типа BREACH/CRIME). Для API это часто означает осторожность с:
- страницами/ответами, где возвращается токен, e‑mail, персональные данные и одновременно есть отражение параметров запроса
- подробными текстами ошибок, которые «эхом» включают пользовательский ввод
Для ошибок (4xx/5xx) полезно быть аккуратнее: либо включать сжатие только после порога размера, либо держать сообщения лаконичными — так вы снизите и риски, и шум в логах.
Кеш и CDN: Vary и ключ кеша
Если вы отдаёте сжатие, обязательно добавляйте Vary: Accept-Encoding. Иначе CDN/прокси может закешировать gzip‑версию и отдать её клиенту, который её не поддерживает.
Учтите, что Vary увеличивает количество вариантов объекта в кеше (по сути, разные ключи для gzip/br/zstd/identity), поэтому:
- фиксируйте понятные правила фолбэка (если нет поддержки — отдавайте несжатое)
- следите за hit rate на CDN и при необходимости ограничивайте набор кодеков для публичных эндпоинтов
Сценарии: публичный API, мобильные клиенты и микросервисы
Выбор алгоритма сжатия для API почти всегда зависит не от «кто лучше в вакууме», а от сценария: какая сеть, сколько запросов в секунду, насколько дорог CPU и как ведут себя клиенты.
Мобайл и нестабильная сеть: что важнее — CPU или трафик
Для мобильных клиентов обычно критичны два параметра: объём передаваемых данных и «время до первого полезного байта». При плохой сети даже несколько лишних килобайт на каждом ответе превращаются в ощутимую задержку, поэтому более сильное сжатие часто выигрывает.
Практика такая: если у вас много JSON (профили, ленты, каталоги), то Brotli нередко даёт лучший размер, но может потребовать больше CPU на сервере и иногда на клиенте. Zstd часто оказывается удачным компромиссом: размер чуть хуже, зато компрессия/декомпрессия быстрее — это важно, когда приложение делает много запросов подряд.
Ещё один нюанс: батарея и нагрев. Если клиент — слабое устройство, слишком «тяжёлая» декомпрессия может нивелировать выигрыш от меньшего трафика. Поэтому стоит протестировать на реальных устройствах (не только в эмуляторе) и не ставить максимальные уровни «на всякий случай».
Высоконагруженный публичный API: где упираемся в CPU и как выбрать уровень
При большом RPS компрессия начинает конкурировать за CPU с бизнес‑логикой. Тут победит не тот алгоритм, который сжимает сильнее, а тот, который даёт минимальную суммарную задержку и не «съедает» ядра.
Типичный подход:
- включить сжатие только для реально больших ответов (например, начиная с нескольких килобайт),
- выбрать умеренный уровень (часто «середина шкалы» даёт 80% выигрыша по размеру за малую долю CPU),
- кэшировать уже сжатые представления для популярных эндпоинтов, если есть CDN/edge или серверный кеш.
В таких условиях Zstd часто удобен как «быстро и достаточно эффективно». Gzip — безопасный вариант по совместимости, но при тех же бюджетах CPU иногда проигрывает по времени.
Внутренние сервисы в одном датацентре: когда сжатие может быть лишним
Если микросервисы общаются в одном датацентре, сеть обычно быстрая и дешёвая, а задержки чаще завязаны на очереди, базы и сериализацию. Сжатие может:
- добавить лишнюю нагрузку на CPU,
- ухудшить хвостовые задержки (p95/p99),
- усложнить отладку, если включено везде без разбора.
Здесь разумно включать компрессию точечно: для «толстых» ответов, межрегионального трафика или когда сервисы ходят через более дорогие каналы.
Стриминг/гранулярные ответы: влияние размера чанков и частоты запросов
При частых коротких ответах (много мелких запросов) сжатие может почти не помочь: заголовки и накладные расходы компрессора становятся сравнимы с полезной нагрузкой. Лучше увеличить гранулярность (пакетировать данные), либо поднять порог, при котором включается сжатие.
Для стриминга важны размеры чанков: слишком маленькие чанки хуже «сжимаются» и увеличивают расходы на обработку. Если вы отдаёте данные порциями, тестируйте разные размеры порций и смотрите не только на итоговый размер, но и на задержку между порциями.
Итоги и чеклист внедрения
Быстрые рекомендации выбора
Если нужен «без сюрпризов» вариант для большинства клиентов и прокси, Gzip остаётся самым безопасным базовым выбором: его поддерживают почти везде, а поведение хорошо предсказуемо.
Если основная аудитория — браузеры и вы отдаёте много текстового контента (JSON, HTML, CSS, JS), часто выигрывает Brotli: он обычно даёт меньший размер на проводе при приемлемой цене по CPU.
Если вы контролируете клиентов (мобильное приложение, SDK, внутренние сервисы) и хотите баланс «скорость сжатия/размер/latency», рассмотрите Zstd — но только при уверенной поддержке на стороне клиентов и вашей инфраструктуры.
Где это удобно применять на практике (пример)
Если вы быстро собираете и развиваете API (например, админки, каталоги, личные кабинеты) и при этом хотите держать под контролем latency и стоимость трафика, компрессию проще закладывать как стандартную часть пайплайна.
В TakProsto.AI — вайб‑кодинг платформе для российского рынка, которая генерирует веб (React), бэкенд (Go + PostgreSQL) и мобильные приложения (Flutter) из чата — такие «инфраструктурные» вещи удобно фиксировать на уровне шаблонов/проектных настроек: пороги сжатия, список Content-Type, фолбэки по Accept-Encoding, а затем проверять эффект в метриках и откатываться через снапшоты/rollback, если хвосты p95/p99 ухудшились.
План внедрения: от теста к продакшену
-
Измерить текущее состояние. Соберите базовую линию по размеру ответов, CPU на сервисе и p95/p99 latency.
-
Включить сжатие для части трафика. Начните с малого: отдельный маршрут, отдельный пул, канареечный релиз или 5–10% запросов.
-
Сравнить по p95, а не только по «среднему». Часто сжатие улучшает среднюю задержку, но может ухудшить хвосты из‑за CPU и конкуренции за ресурсы.
-
Расширить охват. Если хвосты не просели и выигрыш по трафику заметен, увеличивайте долю и добавляйте типы ответов.
Набор наблюдаемости (что мониторить)
- Размер: bytes_in/bytes_out, средний и p95 размер тела ответа, доля ответов без сжатия.
- Производительность: CPU (user/system), нагрузка на воркеры, время сериализации JSON отдельно от времени компрессии.
- Latency: p50/p95/p99 на уровне API и на уровне upstream (если есть прокси).
- Надёжность: доля 5xx, timeouts, разрывы соединений, рост ретраев у клиентов.
- Принятие клиентами: доля запросов с
Accept-Encoding, распределение по алгоритмам.
Чеклист перед релизом
- Заголовки: корректные
Content-EncodingиVary: Accept-Encoding. - Фолбэк: если клиент не прислал нужное значение в
Accept-Encoding, отдавайте несжатый ответ или более совместимый алгоритм. - Кеши и CDN: проверьте, что разные варианты кодирования не «склеиваются» в одном кеше.
- Ограничения по типам данных: сжимайте в первую очередь текст (JSON, text/*); не тратьте CPU на уже сжатые форматы (jpeg/png/mp4/zip).
- Пороги: задайте минимальный размер тела, ниже которого сжатие не включается.
- Безопасность: избегайте сжатия для секретных данных в контекстах, где возможны атаки на компрессию (особенно при отражении пользовательского ввода).
Итог простой: начните с совместимого варианта, измеряйте хвосты задержек, и включайте более «сильные» алгоритмы только там, где они реально дают выигрыш на ваших данных и клиентах.
FAQ
Зачем вообще включать сжатие ответов API?
Сжатие уменьшает объём данных в ответе, что обычно даёт:
- меньше трафика (и затрат на egress);
- быстрее передачу по медленным сетям и при высокой RTT;
- более предсказуемую нагрузку на сеть.
Но сжатие добавляет CPU и может ухудшить хвостовые задержки, если настроено агрессивно.
Какие типы данных в API имеет смысл сжимать, а какие нет?
В первую очередь — текстовые форматы, которые хорошо «складываются» за счёт повторов:
application/jsonи родственные (application/problem+json);text/*(например,text/plain,text/csv);- XML, GraphQL-ответы.
Обычно не стоит сжимать уже сжатые данные (image/*, video/*, application/zip, application/pdf) — выигрыш маленький, а CPU тратится.
Почему маленькие ответы часто лучше не сжимать?
Потому что у сжатия есть фиксированный оверхед: служебные байты кодека и время на запуск/работу компрессора. На ответах порядка сотен байт экономия может быть близка к нулю (или даже «в минус»), а задержка и CPU — реальными.
Практика: введите порог, например от 1 КБ для JSON/текста (и поднимайте до 2–4 КБ, если у вас много мелких ответов и критичен CPU).
Как правильно работают Accept-Encoding, Content-Encoding и Vary при сжатии?
Accept-Encoding — что умеет клиент (например: br, gzip, zstd).
Content-Encoding — чем сервер реально закодировал ответ.
Если вы отдаёте сжатые варианты, почти всегда добавляйте:
Vary: Accept-Encoding
Иначе кеш (CDN/прокси) может сохранить, например, gzip-версию и отдать её клиенту, который gzip не поддерживает.
Какую фолбэк-стратегию выбрать между br/gzip/zstd?
Типичная безопасная схема для публичного API:
- выбрать лучший алгоритм из тех, что явно перечислены в
Accept-Encoding; - если ничего не подходит — отдать без
Content-Encoding(identity).
На практике часто держат:
brдля браузерных клиентов;gzipкак самый совместимый фолбэк;zstdкак опцию для контролируемых клиентов (SDK/мобайл/сервис‑к‑сервису), если инфраструктура пропускает.
Когда Brotli — лучший выбор для API?
Обычно Brotli выигрывает на текстовых ответах (HTML/CSS/JS/JSON) по итоговому размеру. Это полезно, когда важны байты на проводе: мобильные сети, дорогой трафик, большие JSON.
Но на высоких уровнях Brotli может заметно грузить CPU при сжатии «на лету», поэтому для динамического API чаще выбирают умеренные уровни и полагаются на кеширование.
Почему gzip до сих пор остаётся “по умолчанию”?
Gzip выбирают из-за предсказуемой совместимости: его понимают почти все клиенты, прокси, балансировщики и корпоративные шлюзы.
Если у вас публичный API с неизвестными интеграциями, gzip часто становится базовым «без сюрпризов» вариантом. Минус — на текстовых данных он нередко проигрывает Brotli/Zstd по размеру.
В каких сценариях Zstd особенно полезен?
Zstd часто даёт хороший баланс: прилично сжимает и обычно быстро распаковывается, что помогает удерживать latency.
Подходит для:
- внутренних микросервисов (много однотипных ответов);
- мобильных клиентов (экономия трафика при быстрой распаковке);
- больших JSON/батчей.
Главный стоп‑фактор — совместимость: включайте Zstd только для клиентов, которые явно его запросили (Accept-Encoding: zstd) и после проверки всей цепочки (прокси/CDN/mesh).
Какие уровни сжатия разумно ставить по умолчанию?
Стартовые «умеренные» настройки, которые часто дают хороший баланс:
- gzip: уровень 5–6;
- brotli: уровень 4–6 для динамики (9–11 — скорее для предсжатой статики);
- zstd: уровень 3–5.
Дальше корректируйте по метрикам (особенно p95/p99): иногда +1 уровень почти не уменьшает размер, но заметно увеличивает CPU.
Как корректно сравнить Brotli, gzip и Zstd на своём API?
Сравнивайте не «в вакууме», а на ваших типовых ответах и под ваш профиль нагрузки. Минимальный набор метрик:
- размер после сжатия (bytes);
- время сжатия на сервере (CPU time);
- время распаковки на клиенте (CPU time);
- end-to-end latency (p50 и обязательно p95/p99);
- throughput (req/s) при фиксированном бюджете CPU.
Прогоняйте тесты на разных размерах (малые/средние/большие ответы) и фиксируйте сценарий (сжатие на лету vs из кеша).