Brotli を用いた静的コンテンツ配信最適化と Accept-Encoding: br について
Intro
High Sierra に乗る Safari 11 で Brotli 対応がされるということで、メジャーブラウザの Brotli 対応が概ね揃うことになる。
そこで、本サイトも Brotli による静的コンテンツ配信に対応した。
brotli
brotli は Google が開発した新しい圧縮形式である。
LZ77 とハフマン符号化を合わせたものであり、元々は WOFF2 の仕様の一部として作られたものが、汎用化されたものである。
過去に公開されている zopfli と比べても、さらに圧縮率が 20-26% 向上しており、解答速度は zlib 相当とされている。
この効果に寄与する特徴的な要因として、仕様に含まれる辞書が挙げられる。
Static Dictionary
圧縮アルゴリズムは、簡単に言えば頻出する一致部分を短い情報で置き換える方式が中心となる。
ここで、頻出する一致部分を、対象とするコンテンツの中から探す場合は、探索する長さや範囲の広さなどによって結果が変わる。
もちろん、広い範囲を丁寧に探索すれば、効率よく圧縮が可能だとしても、それでは時間がかかってしまう。
そこで、コンテンツの種類に応じて、あらかじめ頻出する単語パターンを辞書として用意する方式が使用される場合がある。
Brotli は、以下の要領で構築した 122MB にもなる辞書を仕様に含み、これによって特に Web コンテンツにおいて高い圧縮率を実現している。
Unlike other algorithms compared here, brotli includes a static dictionary. It contains 13'504 words or syllables of English, Spanish, Chinese, Hindi, Russian and Arabic, as well as common phrases used in machine readable languages, particularly HTML and JavaScript. The total size of the static dictionary is 122'784 bytes. The static dictionary is extended by a mechanism of transforms that slightly change the words in the dictionary. A total of 1'633'984 sequences, although not all of them unique, can be constructed by using the 121 transforms. To reduce the amount of bias the static dictionary gives to the results, we used a multilingual web corpus of 93 different languages where only 122 of the 1285 documents (9.5 %) are in languages supported by our static dictionary.
— Comparison of Brotli, Deflate, Zopfli, LZMA, LZHAM and Bzip2 Compression Algorithms
なお、仕様には HexString で辞書の全体が記載されているが、これを Ascii に変換したものを以下に置いた。
これを見ると、引用したように HTML や JS などのコンテンツが強く圧縮されるだろうことが、想像できる。
Accept-Encoding: br
Google が提案した圧縮形式としては、本サイトも既に対応している Zopfli もある。
zopfli で静的コンテンツの gzip 配信と Content/Transfer-Encoding について
Zopfli が gzip 互換であり既存のブラウザでもそのまま利用できたのに対し、Brotli は全く新しいフォーマットとなっている。
つまりブラウザが Brotli に対応していない限り、Brotli 形式のファイルを配信することができない。
ブラウザが対応している形式については、ブラウザが Accept-Encoding ヘッダにそれを記載し、サーバとネゴシエーションする方法が取られる。
これまで、多くのブラウザは以下のような値を返していた。
Accept-Encoding: gzip, deflate
ここに、br
があれば Brotli に対応しているため、Brotli で圧縮したファイルをレスポンスできる。
Accept-Encoding: gzip, deflate, br
現状、Chrome などは HTTPS でしか Brotli を許可せず、またコンテンツによっては Brotli を許可しないフォーマットなどもあるかもしれない。
しかし、それら例外を除けば、単純にテキストベースで 大半のリクエストのサイズが 4 byte 増える ことを意味する。
この変更は、Web 全体のトラフィックで考えるとかなり大きいと言えるだろう。
プロトコルレベルでは、HPACK のように 1byte でもペイロードを減らそうとしている現状、この変化は無視できない。
ところが、追加したところで、対応しないトラフィックの方が多いうちは、オーバーヘッドの方が多くなる。
そのため、ちょっとしたフォーマットが提案されたからといって、ブラウザのリクエストのデフォルト値が簡単に変わるわけではない。
Accept ヘッダへの image/webp
の追加などもそうだが、相応の効果と普及を考えての変更と見ることができるだろう。
そして、前述の Safari の実装が済むと、主要ブラウザのサポートは完了する。
brotli の圧縮効果が 4byte 以上あるならば、このヘッダを見過ごす手はない。
Brotli 対応
本サイトは h2o でサーブしており、h2o はオンザフライの Brotli 圧縮に対応している。
Configure > Compress Directives > compress
しかし、本サイトは zopfli も含めビルドプロセスで圧縮をしているので、ここで Brotli 圧縮をあらかじめ行う構成をとる。
圧縮済みの .br
を用意すれば、以下の設定で Accept-Encoding ベースのコンテントネゴシエーションを経て Brotli を配信できる。
Brotli 圧縮
Brotli の実装は Google が公開している。
これを README の通りビルドし、実際にいくつかのコンテンツで圧縮結果を比較した。
予備実験とし、--quality
を変えて試したところ、基本的には高いほど効果があり、速度はほとんど変わらなかった。
そこで、以下は全て最高値である --quality 10
を採用している。
zopfli は、以前の検証で出した 当サイトの平均的なサンプルとして、一つ前の記事 の HTML を採用した。
zopfli と比べて、4 point 圧縮率が向上している。
highlight.min.js
zopfli と比べて、1 point 圧縮率が向上している。
サイズとしては 1K 程度減っているので、かなり圧縮が効いている。
mozaic.css
あまり大きなサイズの CSS を使っていなかったので微妙ではある。
zopfli と比べて、7 point 圧縮率が向上している。
本サイト用にビルド したフォントファイルを採用する。
NotoSansCJKjp-Jxck-Regular.woff
NotoSansCJKjp-Jxck-Regular.otf
OTF は圧縮効果が高いが、WoFF は逆効果となっている。
これは WoFF がそもそも圧縮を仕様に含んでいるからと考えられる。
mozaic.png
圧縮効果は高いが、zopfli と brotli では有意な差はなかった。
mozaic.webp
WebP も圧縮済みのフォーマットであるため、圧縮が逆効果となる場合が多いが、このファイルでは効果が出ている。
しかし、jpeg をベースにした別の webp では圧縮が逆効果になっているものもあったので、このあたりはファイルごとに見ていく必要がある。
mozaic.svg
テキストであるためかなり圧縮率は高いが、zopfli との差は小さい。
--i30
を採用している。
HTML
file type
size
ratio
.html
22260
100%
.html.gz
6347
29%
.html.br
5658
25%
JS
file type
size
ratio
.js
42536
100%
.js.gz
16289
38%
.js.br
15775
37%
CSS
file type
size
ratio
.css
1454
100%
.css.gz
503
35%
.css.br
402
28%
Web Font
file type
size
ratio
.otf
486132
100%
.otf.gz
382322
79%
.otf.br
344003
71%
file type
size
ratio
.woff
387528
100%
.woff.gz
387527
99%
.woff.br
387533
101%
PNG
file type
size
ratio
.png
37509
100%
.png.gz
3108
8%
.png.br
3103
8%
WebP
file type
size
ratio
.webp
9474
100%
.webp.gz
2609
28%
.webp.br
2544
27%
SVG
file type
size
ratio
.svg
2871
100%
.svg.gz
300
10%
.svg.br
269
9%
速度比較
同じパラメータで、本サイト全体の圧縮タスクの実行時間を比較した。
圧縮対象は、html/js/css/png/txt/md など 890 ファイルである。
zopfli: 190.33s user 2.77s system 98% cpu 3:15.28 total
brotli: 22.44s user 1.42s system 99% cpu 24.014 total
測定ミスではなく、圧倒的に brotli の方が速い。
単発で試しているうちから圧倒的に速いことは認識しており、サンプルを増やしたため歴然とした差となった。
Outro
本サイトのコンテンツに対しては、brotli の圧縮効果は概ね zopfli より高く、これは辞書との相性が大きく効いていると考えられる。
また、ブラウザは brotli への対応が進み、コンテントネゴシエーションによる配信が可能となりつつある。
本サイトは、コンテンツを全面的に brotli で事前圧縮し、対応ブラウザに配信するよう対応した。