Алгоритм Brotli и статическое сжатие

На текущий момент алгоритм Brotli поддерживается значительной долей браузеров. Brotli сжимает лучше, чем gzip. Но скорость при максимальной компрессии настолько низкая, что выигрыш от сжатия контента полностью теряется.

Различия между динамическим и статическим сжатием контента:

  • Динамическое сжатие выполняется на лету. Пользователь делает запрос, контент сжимается, и сжатый контент передаётся пользователю.
  • Статическое сжатие осуществляется на диске еще до запроса данных. Когда пользователь их запрашивает, предварительно сжатые данные просто читаются с диска.

Проблема динамической компрессии заключается в том, что сервер не может ответить на поступивший запрос, пока выполняется сжатие. Если использовать максимальный уровень сжатия, это может задержать выдачу ответа и сказаться на производительности сайта.

Решением этой проблемы является статическая компрессия данных. Изучив это руководство, вы научитесь осуществлять статическое сжатие файлов для обеспечения оптимальной производительности.

Содержание

Как сжимать статический контент?

Если вы используете фреймворк Express, то потребуется модуль shrink-ray, который реализует статическое сжатие через встроенный механизм кеширования.

Но на серверах Apache это может быть не так просто. Неофициальный модуль Apache mod_brotli (и даже официальный модуль mod_deflate для gzip) не предоставляют функциональность для статического сжатия.

Но вы можете предварительно сжать статический контент на диске, а затем настроить сервер так, чтобы он предоставлял предварительно сжатые данные с диска, используя mod_rewrite.

Чтобы предварительно сжать данные вручную, используя бинарное сжатие в bash. Но автоматизация этого процесса с помощью gulp гораздо более удобна.

Допустим, вы хотите предварительно сжать все файлы HTML, CSS, JavaScript , изображения SVG, используемые в проекте и загружать их из отдельной папки:

const brotliCompress = () => {
    let src  = "src/**/*.{html,js,css,svg}",
        dest = "dist";

    return gulp.src(src)
        .pipe(brotli.compress({
            extension: "br",
            quality: 11
        }))
        .pipe(gulp.dest(dest));
};

exports.brotliCompress = brotliCompress;

Затем выполняется задача brotliCompress:

 

gulp brotliCompress

Она сжимает файлы, подходящие по формату (указанному в переменной src), и сохраняет их папке (указанной в переменной dest). Файл styles.css будет переименован в styles.css.br, файл scripts.js станет scripts.js.br и так далее.

Уровень компрессии задается в переменной quality. Ее максимальное значение – 11. Также возможно создание сжатых файлов в формате gzip для браузеров, которые не поддерживают алгоритм Brotli, с помощью команды gulp-gzip. Ее синтаксис похож на gulp-brotli. Максимальный уровень сжатия – 9.

Теперь нужно правильно настроить конфигурацию Apache:

# Файлы, сжатые по Brotli
<Files *.js.br>
    AddType "text/javascript" .br
    AddEncoding br .br
</Files>
<Files *.css.br>
    AddType "text/css" .br
    AddEncoding br .br
</Files>
<Files *.svg.br>
    AddType "image/svg+xml" .br
    AddEncoding br .br
</Files>
<Files *.html.br>
    AddType "text/html" .br
    AddEncoding br .br
</Files>

Вы также можете указать gzip-версии файлов для тех браузеров, которые не поддерживают алгоритм Brotli:

# Файлы, сжатые по gzip
<Files *.js.gz>
    AddType "text/javascript" .gz
    AddEncoding gz .gz
</Files>
<Files *.css.gz>
    AddType "text/css" .gz
    AddEncoding gz .gz
</Files>
<Files *.svg.gz>
    AddType "image/svg+xml" .gz
    AddEncoding gz .gz
</Files>
<Files *.html.gz>
    AddType "text/html" .gz
    AddEncoding gz .gz
</Files>

Теперь используем модуль mod_rewrite, чтобы установить кодировки заголовков запроса Accept-Encoding и загружать пользователю поддерживаемую версию сжатых данных:

# Включаем mod_rewrite
RewriteEngine On

# Предоставляем предварительно сжатые данные Brotli
RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{REQUEST_FILENAME}.br -f
RewriteRule ^(.*)$ $1.br [L]

# Предоставляем предварительно сжатые данные gzip
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.*)$ $1.gz [L]

Теперь предварительно сжатый по алгоритму Brotli контент будет предоставлен браузерам, которые его поддерживают. Это указано в их заголовках запроса Accept-Encoding. Другим браузерам будет предоставлены gzip-версии.

Как это сказывается на производительности?

Использование статического сжатия повышает быстродействие сайта. Чтобы это доказать, я провел эксперимент. Первоначально тестовый сайт «весил» примерно 900 Кб вместе с несколькими файлами стилей и скриптов, SVG- изображениями. Используя sitespeed.io, я провел 50 измерений для каждого из четырех вариантов сжатия контента:

  1. Динамическое сжатие Brotli на уровне 11.
  2. Статическое сжатие Brotli (на том же уровне).
  3. Динамическое сжатие gzip на уровне 9.
  4. Статическое сжатие gzip (на том же уровне).

Разброс в результатах оказался значительным:

 

Сравнение времени ответа при различных методах сжатия

Динамическое сжатие Brotli на наивысшем уровне компрессии очень медленное. Но при предварительном сжатии данных с помощью Brotli мы получаем всю выгоду от небольшого размера файлов.

Различия между динамическим и статическим сжатием с помощью gzip менее заметные. В среднем статическое сжатие способствует сокращению времени ответа.

Замечания и заключение

Статическое сжатие идеально, но не всегда. Например, динамически генерируемый контент не подходит для статического сжатия.

Что насчёт атак BREACH? Сжатый контент подвержен им при передаче через HTTPS. Но это является проблемой только для персональной информации. В этом случае можно оставить HTML-контент не сжатым.

Существует мало причин не применять статическое сжатие. Даже если ваш сервер не поддерживает его, то сжатие очень легко реализовать. Улучшите производительность вашего сайта уже сегодня!

Данная публикация представляет собой перевод статьи «Brotli and Static Compression» , подготовленной дружной командой проекта Интернет-технологии.ру