Эта статья пригодится всем, кто неравнодушен к скорости доставки своего веб-приложения пользователю и хочет выжать дополнительные миллисекунды и килобайты экономии.
Что такое brotli?
Это новый стандарт компрессии данных, разработанный Google. Хорошее описание и сравнение с другими алгоритмами есть у Clouflare.
В двух словах: это новый вид сжатия, который оптимизирован для веб-применений (HTML, CSS, JS и т.д.) за счет использования статического словаря и других оптимизаций. Он показывает сравнимую скорость при лучшем сжатии по сравнению с gzip и намного лучшее сжатие при максимальных настройках (и очень низкой скорости). Подробное исследования скорости и коэффициентов компрессии смотрите в указанной статье от Cloudflare.
Я приведу небольшую таблицу с реальными файлами (JS, CSS) живого веб-сайта. Перед сжатием все файлы были минифицированы. Сравнивать будем zopfli (i500) — совместимый с gzip компрессор и brotli с настройкой сжатия 11 (максимум).
Тип файлов и сжатие | Размер (байт) | Размер (в % от исходного) |
---|---|---|
CSS исходные файлы | 334 937 | 100% |
CSS zopfli | 60 771 | 18,1% |
CSS brotli | 56 168 | 16,7% |
JS исходные файлы | 477 393 | 100% |
JS zopfli | 149 905 | 31,4% |
JS brotli | 135 766 | 28,4% |
Из этой таблицы можно прикинуть экономии для варианта использования в static режиме (когда файлы сжаты заранее и отдаются Nginx как есть). Для компрессии динамического контента все немного сложнее — нужно сохранять баланс между степенью компрессии и временем сжатия.
Для себя я вывел следующее правило: за счет zopfli можно сэкономить примерно 10% по сравнению с gzip 9, а brotli даёт еще 10% экономии.
Поддержка браузерами
Достаточно хорошая, чтобы использовать уже сейчас. По данным caniuse.com это около 50% аудитории. На самом деле, думаю побольше, потому что brotli поддерживается в Chrome 51+, Firefox 47+ и мобильным Chrome. Важное дополнение: так как brotli несовместим с gzip, он поддерживается только для HTTPS-ресурсов. Это чтобы всякие тупые прокси не побили контент.
Посмотреть поддержку клиентом просто: он должен указать в заголовке запроса accept-encoding br, что и означает «brotli». Например, так:
accept-encoding: gzip, deflate, sdch, br
Включаем поддержку в Nginx
К сожалению, пока нет стандартного модуля для поддержки brotli в Nginx. Но нас этим не остановишь: есть сторонние модули от самого Google и от Cloudflare. Мы будем использовать вариант от Google, так как он нормально документирован и имеет все нужные возможности.
Здесь нужно определиться, как вы будете использовать brotli: только в статическом варианте (brotli_static) или в динамическом (сжатие на лету — brotli). Сборка модуля в режиме brotli_static проще, так как не требуется библиотека для сжатия brotli: libbrotli.
Используем готовый пакет из PPA
Мы будем использовать Ubuntu 16.04 в качестве сервера. Здесь нам на помощь приходит PPA: https://launchpad.net/~hda-me/+archive/ubuntu/nginx-stable. Из PPA мы получаем Nginx Stable ветки с множеством дополнительных модулей. Большинство из них динамические, то есть их можно подключать по желанию. Если вас устраивает этот вариант, можете ставить и переходить к конфигурации.
Собираем Nginx самостоятельно
В этом случае процесс аналогичен сборке Nginx с любыми другими модулями. Сначала качаем и распаковываем исходники Nginx (указана актуальная на момент публикации версия).
wget https://nginx.org/download/nginx-1.11.4.tar.gz
Получаем код модуля ngx_brotli:
git clone https://github.com/google/ngx_brotli.git
Если мы хотим использовать brotli в динамическом режиме, качаем libbrotli:
git clone https://github.com/bagder/libbrotli.git
И собираем (в папке libbrotli):
./autogen.sh
./configure
make
Или можем установить libbrotli из PPA, указанного ранее.
sudo add-apt-repository ppa:hda-me/nginx-stable
sudo apt-get update
sudo apt-get install libbrotli
Если нам нужен только brotli_static, перед сборкой Nginx говорим об этом:
export NGX_BROTLI_STATIC_MODULE_ONLY=1
Теперь идём в папку с исходниками Nginx и собираем его (c опцией --add-module=[путь до ngx_brotli]):
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-stream_geoip_module=dynamic --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed' --add-module=/home/db/ngx_brotli
make
Далее можно установить Nginx (make install) или собрать в deb-пакет:
sudo checkinstall --pkgname=nginx --pkgversion=1.11.4 --nodoc
Конфигурация Nginx
Итак, у нас наконец есть Nginx с поддержкой brotli. Для использования статических brotli-файлов (сжатых заранее), достаточно включить в конфиг nginx.conf (секция http) одну директиву:
brotli_static on;
Теперь nginx будет искать версию файла с суффиксом .br, если клиент заявляет о поддержке brotli. Если не найдёт, то будет работать модуль gzip_static (если включён).
Для активации динамического режима указываем следующие параметры:
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css text/xml application/x-javascript;
Здесь мы используем уровень сжатия 6, потому что он имеет хорошее соотношение качество/производительность. Уровень сжатия будет лучше, чем с gzip 9. Далее указаны MIME-типы контента для сжатия. Уточните конфигурацию ваших MIME-типов на сервере, чтобы сжатие применялось к нужным типам контента. Brotli имеет приоритет перед gzip, поэтому будет использоваться в случае поддержки (также для статического режима).
Проверить работу brotli просто: посмотрите на заголовки ответа, там должно быть:
content-encoding:br
На этом всё: успехов в оптимизации и используйте новые технологии!
P. S. Если вы используете Ubuntu 16.04, то установить утилиту для консольного сжатия brotli очень просто:
sudo apt-get install brotli
Автор: Nickmob