一般的にWebサーバの応答時にコンテンツを圧縮することで、ネットワーク帯域の消費を抑えたり、応答時間を短縮したりすることが可能だ。Azure App Service on Linuxで内蔵のNGINXの設定を変えることで、さまざまな種類のコンテンツを圧縮したり、圧縮率を高めたりできる。その方法を紹介する。
対象:Azure App Service on Linux
Webサーバの性能を高める手段の一つとして、応答時のコンテンツ圧縮が挙げられる。クライアントに応答を返す際にコンテンツを圧縮することで、ネットワーク帯域の消費を抑えたり、応答時間を短縮したり、といった効果が期待できる。
Azureの「App Service on Linux」でも、デフォルトで「GZIP」による圧縮が「オン」なっている。ただ、圧縮されるのはHTMLだけで、圧縮率も最小レベルに限定されている。
そこで本Tech TIPSでは、Webサーバの構築/運用担当者を対象として、App Service内蔵のNGINXの設定を変更することで、コンテンツのGZIP圧縮をカスタマイズして、より性能を高める方法を紹介しよう。App Serviceの機能なので追加コストは不要だ。
App Service内蔵のNGINXの設定変更については、「【Azure】App ServiceのWebサーバ『NGINX』をカスタマイズする方法」を前提としているので、以下を読み進める前に参照していただきたい。また、「【Azure】App Service on LinuxでディレクトリごとにクライアントIP制限を実装する方法と注意点」も参考になるだろう。
App Service on Linuxが応答時に圧縮するコンテンツは、デフォルトでMIMEタイプが「text/html」すなわちHTMLファイルのみに限られる。そこで、CSS(スタイルシート)やJavaScript、XML、JSONといった他のフォーマットのデータも圧縮するように設定しよう。
それには、[/home/custom/etc/nginx/conf.d/gzip.conf]というファイルを新規作成し、以下の内容で保存した後、NGINXを再ロードする。[/home/custom/]というディレクトリの扱い方については、Tech TIPS「【Azure】App ServiceのWebサーバ『NGINX』をカスタマイズする方法」を参照していただきたい。
# conf.d/gzip.conf: GZIP圧縮の設定ファイル。httpコンテキストに自動でインクルードされる
gzip_types application/atom+xml application/javascript application/json application/rss+xml application/vnd.google-earth.kml+xml application/vnd.ms-fontobject application/xhtml+xml application/x-x509-ca-cert image/svg+xml image/x-ms-bmp text/css text/plain text/xml;
MIMEタイプ | データの種類 |
---|---|
application/atom+xml | Atom形式のフィード |
application/javascript | JavaScript |
application/json | JSON |
application/rss+xml | RSS(XML)形式のフィード |
application/vnd.google-earth.kml+xml | 地図上の地点座標などを記載する「KML」のデータ。Googleマイマップなどで利用 |
application/vnd.ms-fontobject | Webページに組み込めるOpenTypeフォント |
application/xhtml+xml | XHTML |
application/x-x509-ca-cert | 認証局の電子証明書 |
image/svg+xml | SVG(ベクター形式の画像フォーマットの一種) |
image/x-ms-bmp | BMP形式の画像 |
text/css | CSS(スタイルシート) |
text/plain | フォーマットのない(プレーンな)テキスト |
text/xml | XML |
上記リストに記した各MIMEタイプとデータ/フォーマットの種類との対応 筆者が主に利用している圧縮可能なデータ/フォーマットを一例として挙げておく。他にもあるはずなので、必要に応じて追加/削除していただきたい。 |
当然ながら、ZIPファイルやJPEG画像のように圧縮済みのデータは、応答時にGZIPで圧縮してもほぼサイズは減らないので、上記リストからは外している。
注意が必要なのは、NGINXが認識しているMIMEタイプを指定することだ。App Service on Linuxの場合、[/etc/nginx/mime.types]というファイルでMIMEタイプが定義されている。このファイルに記載されているMIMEタイプの中から選んで、gzip_typesのパラメーターに指定すること。
特に注意すべきはJavaScriptのMIMEタイプである。執筆時点では「text/javascript」が正式なものとされている半面、過去には「application/javascript」「application/x-javascript」「application/ecmascript」「text/ecmascript」「text/x-javascript」のようなたくさんのMIMEタイプがJavaScript向けに使われてきた。App Service on Linuxでも、デフォルトは「text/javascript」ではなく「application/javascript」の方である。前述のように、実際に[/etc/nginx/mime.types]で定義されているMIMEタイプを選んで指定しよう。
NGINXのGZIP圧縮では、圧縮率を9段階で変更できる。App Service on Linuxの場合、デフォルトでは最も低い圧縮率が設定されている。これを最大限に圧縮するように変更すれば、応答時のサイズを減らすことが可能だ。
それには、前述の[gzip.conf]ファイルに以下の記述を追加して、NGINXを再ロードする。
gzip_comp_level 9;
「gzip_comp_level」ディレクティブのパラメーターには、圧縮率のレベルとして、「1」(最小)から「9」(最大)までの整数値で指定できる。
一般的に圧縮率を高めるほど、データのサイズは小さくなる一方で、圧縮にかかる時間は長くなる。そこで、実際にApp Service on Linuxで圧縮率を変えながら、5MBのテキストファイルを読み出して、その応答時のサイズと応答にかかった時間を計測してみた。
Azureの西日本リージョンにP1v3スケールでデプロイしたApp Service on Linuxに、5MBの日本語混じりのプレーンテキストファイルを配置。東京都内の拠点にあるデスクトップPC(AMD Ryzen 7 5800X、Windows 11 Pro)にインストールしたPostmanアプリ版で対象のテキストファイルにGETリクエストを送信。その応答について、Postmanが表示した応答時のサイズと応答にかかった時間をそれぞれ5回ずつ計測し、その平均値を掲載している。応答時のサイズにはコンテンツ本体の他、レスポンスヘッダなども含めている。応答にかかった時間には、Postmanがデータを受信し終わった後の処理時間を含めていない。
まず、テストしたプレーンテキストのデフォルトである「圧縮なし」の場合、圧縮を「オン」にしたときと比べて、サイズは大きく時間も長い、つまり性能が良くないことが分かる。
圧縮を「オン」にした場合、圧縮率のレベル「1~3」「4~5」「6~9」とおおよそ3段階でサイズが大幅に減っていることが分かる。一方、応答時間については、圧縮率を変えてもサイズほどの差はついていない。これは、圧縮率を上げるほど、圧縮の処理に手間がかかって完了までの時間が延びる半面、圧縮後に小さくなったデータの転送時間は短くなる、という相反の関係があるからだ。
こうした結果から、圧縮率のレベルは「9」でよいように思える。ただし、圧縮率を上げるほど、応答を受け取ったクライアントが解凍する際の負荷も高くなる。特に、性能の低い古めのスマートフォンをサポートしなければならない案件では、圧縮率を上げ過ぎると、クライアント側での描画が完了するまでの時間がかえって延びかねないので注意したい。
もちろん、こうした傾向はデータの種類やサイズ、App Service on Linuxの設定などによって変動する。上記のベンチマーク結果は参考程度に捉えていただきたい。そして、今回計測できなかったCPU占有率やメモリ使用量なども含めて、実際のデータでベンチマーク測定をしながら圧縮率を決めていくのがよいだろう。
ここまでの設定では、クライアントとサーバ間のどこかにあるキャッシュにヒットしない限り、App Service on Linuxはリクエストのたびに、その場で動的にコンテンツを圧縮してクライアントに返すことになる。圧縮の処理中は、当然ながらApp Service on Linuxのインスタンスを実行しているCPUにその分の負荷がかかる。リクエストが増えれば、圧縮時のCPU負荷も増え、結果としてスケールアップまたはスケールアウトを強いられることになるかもしれない。
これに対し、NGINXでは、あらかじめ静的に圧縮しておいたコンテンツファイルを応答に直接利用できる機能がある。これにより、動的な圧縮の回数を減らしてCPU負荷を抑えることが可能だ。
それには、まず前述の[gzip.conf]ファイルに以下の記述を追加して、NGINXを再ロードする。
gzip_static always;
gunzip on;
次に、圧縮の対象となるコンテンツファイルを以下のコマンドラインで圧縮する。これは、App Service on LinuxにSSHで接続したり、WindowsクライアントPCのWSL(Windows Subsystem for Linux)を起動したりして、Linux環境で実行してほしい。
gzip -fc -9 <コンテンツファイル> > <コンテンツファイル>.gz
後は、圧縮された[<コンテンツファイル>.gz]ファイルを[<コンテンツファイル>]と同じディレクトリに配置すればよい。これで、[<コンテンツファイル>]がリクエストされると、動的な圧縮は実行されず、代わりに[<コンテンツファイル>.gz]の方がそのまま応答に用いられる。.gzファイルを配置していなければ、リクエスト時に動的な圧縮が実行され、応答に用いられる。
前述のベンチマークと同じ条件で、動的に圧縮した場合と事前に静的圧縮をした場合の応答時間を計測した結果を以下に記す。
あらかじめ静的に圧縮した場合、動的な圧縮時と比べて応答時間が半分以下で済んでいることが分かる。それだけ、CPUが動的な圧縮を処理するのに時間がかかることが伺える結果だ。ただし、テスト対象のファイルサイズが5MBと比較的大きいことは、この結果に作用しているだろう。対象ファイルのサイズが小さく、圧縮に時間がかからない場合は、ここまで顕著な違いにはならない可能性が高い。
この機能を利用する際に注意が必要なのは、元のコンテンツファイルを更新したとき、同時に.gzファイルの方も圧縮し直して更新する必要があることだ。これを怠ると、ファイルを更新したにもかかわらず、リクエストを送ったクライアントには元のバージョンの(静的圧縮された)ファイルが返ることになるので注意しよう。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.
Windows Server Insider 記事ランキング