SDCH+Brotli, або як потиснути ваш HTML контент в 20 разів


Останнім часом з'явилося кілька альтернативних технологій стиснення текстових даних (на додаток до gzip), які не тільки працюють (=тиснуть) краще (судячи з офіційним порівнянь), але і доступні в браузерах (переважно, в Chrome-based, але це вже 40-60% аудиторії сайтів).

Нижче я розповім, навіщо може бути корисно дельта-стиснення даних (SDCH, SanDwiCH) і як його налаштувати на вашому сервері.

Zopfli, brotli, sdch
Невелика зведення, що за звірі такі zopfli, brotli і sdch. Zopfli — «поліпшена» версія zlib, яка створює повністю сумісні з алгоритмом LZ77 файли, але покращує стиснення на 3-8%. Тобто це «gzip на стероїдах». Плюсами є повна сумісність створюваних архівів з будь-якими розпаковщиками, які розуміє формат gzip, включаючи всі браузери і швидкість розпакування не відрізняється від розпакування звичайного архіву). Мінусом є великий час (приблизно в 50-100 разів більше) архівації даних. Це обмежує використання zopfli тільки для gzip_static рішень (коли дані попередньо стискуються, і віддаються вже в стислому вигляді клієнту, а не архівуються «на льоту»).

Brotli є маленькою революцією в стисненні текстових даних веб-сайтів. У самій специфікації закладений словник (2/3 розміру самої специфікації з найбільш вживаними фразами (включаючи теги HTML, CSS-інструкції і JavaScript-код). Цей словник є у всіх клієнтів, що підтримують цей формат стиснення, за рахунок чого істотно скорочується розмір переданих даних (zlib-архів містить весь словник, який вимагається для його розпакування, brotli-архів не містить всього словника). За рахунок усунення передачі словника досягається виграш в 15-20% щодо zopfli-архіву (або в 20-25%, якщо брати gzip-9). Мінусом є те, що brotli повинен підтримуватися браузерами (зараз Chrome, Android + Firefox). І швидкість стиснення даних теж досить низька.

Brotli може використовуватися як доповнення до gzip-стиснення статичних архівів для тих клієнтів, які його розуміють. Це дозволяє, в середньому, скоротити розмір переданих текстових даних ще на 10%. Тут докладне керівництво, як прикрутити brotli для nginx.

SDCH є додатковим підходом, таким поворотом на 90 градусів відносно основної парадигми, і реалізацією дельта-кодування даних. У чому суть: ми передаємо користувачеві (браузеру) певний набір вихідних даних (перший HTML-документ), а потім починаємо відправляти тільки зміни щодо цього документа (дельта-чанки). На практиці це призводить до скорочення переданих даних ще в 1,5-3 рази. І повністю сумісне з додатковим gzip-стиснення дельта-чанків.

Тепер по порядку.

Як працює SDCH
Перше, що я рекомендую зробити, — це переглянути презентацію LinkedIn про SDCH (її текстову розшифровку, загальне введення в SDCH, прикладне використання з «підводними каменями».

Вся суть комунікацій між браузером і сервером представлена в цій схемі:



5-крокове взаємодія реалізується так:

  1. Браузер запитує сторінку сайту, повідомляючи, що підтримуємо sdch-кодування (
    Accept-Encoding: sdch
    ).
  2. Сервер відповідає, що поточний контент сторінки ще не стиснутий (
    X-SDCH-Encode: 0
    ), але словник для стиснення можна завантажити за адресою (
    Get-Dictionary: ...
    )
  3. Браузер отримує сторінку сайту і словник для завантаження. Завантажує словник паралельно завантаженні контенту поточної сторінки.
  4. Браузер робить запит до наступної сторінки сайту, відправляючи хеш завантаженого словника (
    Avail-Dictionary
    ).
  5. Сервер відповідає sdch-кодованої сторінкою, яка може бути додатково gzip-стиснута (
    Content-Encoding: sdch, gzip
    = спочатку потрібно розпакувати за допомогою gzip, а потім розшифрувати з допомогою SDCH-словника).


Заводимо SDCH на сервері
Я припускаю, що читач в курсі, як збирати nginx (і не тільки) з вихідних кодів, як його настроювати (nginx.conf) і як тестувати запити/відповіді (в браузері або консолі). Далі буде більш-менш детальне керівництво, як запустити SDCH для свого сайту.

Нам буде потрібно:

  1. Пакет open-vcdiff (акуратно збираємо, включаючи репозиторії в third party), що реалізує саме кодування.
  2. Пакет femtozip для складання SDCH-словника.
  3. (Опціонально, якщо є cmake LVL80+) SInGe як альтернативна утиліта для складання і перезбирання словників.
  4. Nginx-модуль sdch_module
  5. (Опціонально, якщо хочемо zopfli-стиснення словника) Zopfli
  6. (Опціонально, якщо хочемо brotli-стиснення словника) Brotli + brotli_static


Збираємо і налаштовуємо
Збираємо open-vcdiff:

Збірка open-vcdiffgit clone --recursive github.com/google/open-vcdiff
cd open-vcdiff
cmake --build ./ && make install

Збираємо femtozip:

Збірка femtozipgit clone github.com/gtoubassi/femtozip
cd femtozip/cpp
./configure && make install

Завантажуємо модулі nginx з репозиторіїв і додаємо їх при складанні nginx в
configure
:

Конфігурація збірки nginx--add-module=/путь_до_исходных_кодов_модуля/ngx_brotli \
--add-module=/путь_до_исходных_кодов_модуля/sdch_module \


Створюємо словник
Правильний словник — єдиний аспект SDCH, потребує суттєвої уваги. При великому розмірі словника він буде сильно сповільнювати завантаження першої сторінки для користувача (оскільки завантажується браузером паралельно ключових ресурсів — CSS і JavaScript — відразу після отримання HTML-відповіді). При малому розмірі словника значного виграшу при використанні SDCH не буде.

Правильна стратегія у світлі всіх озвучених умов виглядає приблизно наступним чином:

  • Використовувати SDCH-словники тільки для динамічного HTML контенту. Для статичних файлів відмінно працює zopfli+brotli, вони завантажуються один раз (майже всі ресурсні файли потрапляють в браузер при завантаженні першої сторінки сайту), розмір SDCH-словника для статичних ресурсів може бути на порядок більше HTML.
  • Тримати SDCH-словник в межах від 0,5 до 3 розмірів середньої HTML-сторінки сайту.
  • Збирати SDCH-словник для сайту не частіше, ніж раз на тиждень.
Для складання словника нам будуть потрібні деякі (не дуже багато) характерні сторінки сайту. При простій наскрізний структурі дизайну можна просто взяти 3-5 актуальних сторінок і скопіювати їх в папку для складання словника.

Після цього запускаємо femtozip (або SInGe, якщо вдалося зібрати його):

fzip --dictonly --build --model website.dict --maxdict 36000 html_folder

Тут 36000 — магічне число, що обмежує розмір словника зверху (наші 0,5-3 розміру HTML-файлу),
website.dict
— результуючий файл словника,
html_folder
— папка, куди скопіювали HTML-сторінки.

Увага, магія! У вихідний файл
website.dict
— треба додати 3 рядка заголовків і переклад рядка після них (для передачі в браузер). Після цього використовувати цей словник як вхідний для vcdiff буде не можна, тому рекомендую мати два файл для тестування: сам словник (наприклад,
website.raw.dict
) і словник для браузера (наприклад,
website.dict
).

Заголовки для SDCH-словникаDomain: www.website.ru
Path: /
Format-version: 1.0


Отриманий файл словника можна додатково стиснути через brotli (зараз brotli підтримується у всіх браузерах, які підтримують sdch):

bro --quality 11 --input website.dict --output website.dict.br

Налаштовуємо nginx
Після складання nginx з модулем SDCH нам залишається тільки покласти всі файли словника в папку сайту, наприклад, в корінь і задати конфігурацію SDCH (мінімальний розмір 3 Кб — з наведених вище досліджень про ефективність SDCH для малих файлів):

Конфігурація nginxsdch on;
sdch_dict /full_path_to_sdch_dictionary/website.dict;
sdch_url /website.dict;
sdch_min_length 3096;
sdch_nodict_types text/plain application/xhtml+xml, text/richtext text/xsd text/xsl text/xml application/xml application/json image/x-icon application/rss+xml;
sdch_nodict_types text/css;
sdch_nodict_types application/msword application/vnd.ms-excel application/vnd.ms powerpoint, text/csv;
sdch_nodict_types text/javascript application/javascript application/x-javascript text/x-js text/ecmascript application/ecmascript text/vbscript text/fluffscript;
sdch_nodict_types image/vnd.microsoft.icon image/bmp image/x-ms-bmp;
sdch_nodict_types image/svg+xml application/x-font-ttf font/truetype application/x-font font/opentype font/otf font/ttf application/x-font-truetype application/x-font-opentype application/vnd.ms-fontobject application/font-woff application/font-woff2 application/pdf;
sdch_nodict_types application/vnd.groove-tool-template;
sdch_nodict_types image/gif image/png image/jpeg image/tiff;


Якщо при перезапуску nginx видається помилка «не можу завантажити SDCH-словник» — перевірте, чи правильно додали в словник 4 рядка заголовків. Вони обов'язково повинні бути присутніми.

Тестування і перевірка
Для тестування нам потрібно отримати SHA256-хеш словника (точніше, перші 8 символів), щоб відразу відправити на сервер — типу словник у нас вже є. Зробити це можна, наприклад, так (в папці з фінальним словником):

a=$(cat website.dict | sha256sum | awk '{print $1}' | xxd -len 6 -r -p | base64);echo ${a:0:8}

Далі запитуємо SDCH-кодований контент, використовуючи отриманий хеш.

curl -v "http://127.0.0.1" --insecure -o sdch.html --header "Host: website.ua" --header "Accept-Encoding: sdch" --header "Avail-Dictionary: HASH"

Отриманий файл —
sdch.html
— можна розкодувати через vcdiff (використовуючи вихідний словник, без заголовків):

cat sdch.html | vcdiff decode -dictionary website.raw.dict > result.html

Тепер порівнюємо
result.html
з початковою сторінкою і радіємо зменшення розміру.

При виникненні будь-яких проблем з раскодировкой даних потрібно перезібрати словник (використовуючи інший розмір, наприклад, або набір файлів).

Практичний вихлоп
Відносно стабільний результат роботи SDCH (+gzip) «на льоту» дав зменшення HTML-файлів в 1,5-2 рази (3 Кб проти 5,5-6 Кб gzip стиснутих). У деяких «екстремальних» умовах (при збільшенні SDCH-словника в brotli-стислому вигляді до 2 стислих HTML-сторінок) вдалося досягти виграшу в 3 рази (1,9 Кб проти 5,7 Кб) або у 10 разів відносно мінімізованого HTML-документа (19,6 Кб). З урахуванням істотного розміру ресурсних файлів (100+ Кб CSS / JavaScript «доважок» у вигляді 10 Кб SDCH-словника виглядає несуттєво, але «окупається» тільки через 3 перегляду сторінки (не включаючи саму першу запитану сторінку).

Також можливий і зворотний ефект від SDCH, коли при середній глибині перегляду в 3 сторінки користувач завантажить більше даних, ніж при звичайному стисненні:


Висновок
SDCH реально використовувати для сайту, щоб ще в рази скоротити обсяг переданих даних. Але при неправильному розмірі словника це буде анти-паттерном прискорення сайту.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.