Apacheで圧縮してコンテンツ配信しよう
最近、スマートフォン向けのサイトなどが多くなりつつありますが、スマートフォンの場合、「(携帯キャリアの3G回線などの)細い回線」かつ「(JavaScriptなどを含んだ)リッチコンテンツ」という事情から、コンテンツのダウンロードが重く感じるということがあります。
その対策として、Webサイトの高速化 ルール4 コンポーネントを圧縮しよう! にある通り、JavaScript、CSSの外部ファイルを圧縮して送信することで、パフォーマンスを向上しようという話です。
但し、導入時には、運用しているサーバのCPUリソース状況を確認する必要があります。なぜなら、圧縮する度にCPU消費する事になり、結果CPU使用率は上がるからです。CPU使用率は余裕で、かつ、ネットワーク帯域は節約したい場合にはいい手段だと思います。
以降で、Apacheへの圧縮用モジュール追加、設定内容、動作確認の順で説明していきます。
Apacheへのモジュール追加
mod_so の確認
まず、モジュール追加するには、「mod_so」というモジュールが必須ですので、その存在確認を行います。*1
[root]# /usr/local/apache2/bin/httpd -l ・ ・ mod_alias.c mod_so.c
追加モジュールのコンパイル
今回利用するモジュールは、以下の2つです。
- mod_deflate.so(※要モジュール追加)
- コンテンツを圧縮するモジュール
- mod_filter.so(※Apache本体に組み込まれているはずなので追加不要)
- コンテンツタイプによって、圧縮対象を指定するためのモジュール
apxs を使って、mod_deflate.so をコンパイルします。「-c」オプションはコンパイル、「-i」オプションはインストール(/usr/local/apache/modules に移動などしてくれる)という意味です。
参考にしたサイトでは、「-a」オプションがつけられていることが多かったのですが、個人的には勝手に、httpd.confにLoadModuleディレクティブを追加されたりするのは嫌なのでつけていません。
[root]# /usr/local/apache2/bin/apxs -c -i /root/modules/httpd-2.2.11/modules/filters/mod_deflate.c /usr/local/apache2/build/libtool --silent --mode=compile gcc -prefer-pic -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -g -O2 -pthread -I/usr/local/apache2/include -I/usr/local/apache2/include -I/usr/local/apache2/include -c -o /root/modules/httpd-2.2.11/modules/filters/mod_deflate.lo /root/modules/httpd-2.2.11/modules/filters/mod_deflate.c && touch /root/modules/httpd-2.2.11/modules/filters/mod_deflate.slo /usr/local/apache2/build/libtool --silent --mode=link gcc -o /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la -rpath /usr/local/apache2/modules -module -avoid-version /root/modules/httpd-2.2.11/modules/filters/mod_deflate.lo /usr/local/apache2/build/instdso.sh SH_LIBTOOL='/usr/local/apache2/build/libtool' /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la /usr/local/apache2/modules /usr/local/apache2/build/libtool --mode=install cp /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la /usr/local/apache2/modules/ cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.so /usr/local/apache2/modules/mod_deflate.so cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.lai /usr/local/apache2/modules/mod_deflate.la cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.a /usr/local/apache2/modules/mod_deflate.a chmod 644 /usr/local/apache2/modules/mod_deflate.a ranlib /usr/local/apache2/modules/mod_deflate.a PATH="$PATH:/sbin" ldconfig -n /usr/local/apache2/modules
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
mod_deflate.so ができたかどうか確認してみます。
[root]# pwd /usr/local/apache2/modules [root]# ls -ltr -rwxr-xr-x 1 root root 129705 5月 14 2009 mod_rewrite.so -rwxr-xr-x 1 root root 42292 5月 14 2009 mod_headers.so -rwxr-xr-x 1 root root 30367 5月 14 2009 mod_expires.so -rwxr-xr-x 1 root root 13191193 5月 14 2009 libphp5.so -rwxr-xr-x 1 root root 48770 11月 12 12:44 mod_deflate.so
Apache設定変更
モジュールのコンパイルが完了したので、httpd.confを修正します。設定の際に配慮するのは、以下の4点です。
- 追加モジュールのロード
- 圧縮コンテンツ非対応ブラウザ(古いブラウザ)への配慮
- 画像コンテンツは圧縮しない(元々圧縮されているので)
- 対象コンテンツのタイプを指定して圧縮を行う
[root]# vi /usr/local/apache2/conf/httpd.conf ##### 追加モジュールのロード ##### # mod_filterは「BASE」モジュールなので含まれているはずです。 # LoadModule filter_module modules/mod_filter.so*2 LoadModule deflate_module modules/mod_deflate.so ##### 圧縮コンテンツ非対応ブラウザ(古いブラウザ)への配慮 ##### BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html ##### 画像コンテンツは圧縮しない(CPUを節約) ##### SetEnvIfNoCase Request_URI\.(?:gif|jpe?g|png)$ no-gzip dont-vary ##### 対象コンテンツのタイプを指定して圧縮 ##### FilterDeclare Compression CONTENT_SET FilterProvider Compression DEFLATE Content-Type $text/css FilterProvider Compression DEFLATE Content-Type $application/javascript FilterChain Compression
[設定内容の補足]
- FilterDeclareディレクティブ
- Compressionという名前のフィルター群のタイプがCONTENT_SETであると宣言しています。
- FilterProviderディレクティブ
修正後、Apacheプロセスを再起動します。
[root@sidgen01 conf]# /etc/init.d/httpd restart apache restart use /usr/local/apache2/conf/httpd.conf... OK.
動作確認
FireFoxの「Live HTTP headers」で確認できます。確認の観点は以下の3点です。
以下が「Live HTTP headers」での確認例です。
http://example.com/prototype.js GET /prototype.js HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 Accept: */* Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive HTTP/1.0 200 OK Date: Fri, 12 Nov 2010 05:37:27 GMT Last-Modified: Wed, 24 Oct 2007 01:33:59 GMT Etag: "41da34-17837-43d331c950fc0"-gzip Accept-Ranges: bytes x-ua-compatible: IE=7 Cache-Control: no-cache,max-age=0 Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 22037 Content-Type: application/javascript Connection: close
または、Apacheのアクセスログでも確認可能です。例えば、「prototype.js」で絞り込んだ上で、ファイルサイズの部分を確認するといいでしょう。設定変更前よりも、ファイルサイズが小さくなっていると思います。
[root]# grep prototype.js accesslog.20101112 ・ ・ 192.168.1.1 - - [12/Nov/2010:16:58:29 +0900] "GET /prototype.js HTTP/1.0" 200 96311 192.168.1.1 - - [12/Nov/2010:16:58:31 +0900] "GET /prototype.js HTTP/1.0" 200 96311 ---------- 設定変更を実施 ---------- 192.168.1.1 - - [12/Nov/2010:17:00:57 +0900] "GET /prototype.js HTTP/1.0" 200 22037 192.168.1.1 - - [12/Nov/2010:17:00:57 +0900] "GET /prototype.js HTTP/1.0" 200 22037
負荷検証
今回の対応によるサーバ負荷状況について、以下の観点で確認しておいたほうがいいと思います。
- CPU消費
- Apacheの各プロセスのメモリ消費
方法としては、Apacheのabコマンドを使って、負荷をかけます。
[root]# /usr/local/apache2/bin/ab -n 1000 -c 50 -H 'Accept-Encoding: gzip,deflate' 'http://localhost/prototype.js'
そして、負荷をかけている状態で、topコマンドを使って、以下の3つの値を確認します。
参考URL:httpd.confによるWebサーバの最適化 (3/3):実用 Apache 2.0運用・管理術(3) - @IT
環境によって異なりますが、おそらく、この対応で極端に負荷が上昇することはないと思います。手元の環境では、CPU使用率が元の2割程度(4X%⇒5X%)上昇していました。
但し、サーバ構成として、前段にキャッシュサーバがあれば、圧縮された結果をキャッシュしてくれますので、毎回圧縮処理が走ることにはなりません。JavaScript、CSSの外部ファイルはほとんどの画面で共通に読み込まれるものですので、高いキャッシュヒット率が期待できます。
この対応の効果
大きめのJavaScriptライブラリであるprototype.js(約95K)のサイズが、75%程度削減され、22K程度になっていました。大量にアクセスがあるサイトで考えるとかなりのネットワークリソースの節約になります。サーバのCPUにある程度余裕があれば、ぜひ導入すべき設定だと思います。
*1:mod_so は、apache コンパイル時にしか組み込む事ができないため、もし存在しなければApache本体の再コンパイルになります。
*2:この行を有効にすると、設定ファイル修正後、Apache再起動の際、「httpd: Syntax error on line 19 of /usr/local/apache2/conf/httpd-rewrite.conf: module filter_module is built-in and can't be loaded」というエラーが出ます。つまりもう組み込まれているよというエラーです。「/usr/local/apache2/bin/httpd -l」で確認しておくとよいです。もし無ければ、「/usr/local/apache2/bin/apxs -c -i /root/modules/httpd-2.2.11/modules/filters/mod_filter.c」でコンパイルしましょう。
*3:mod_deflateモジュールを読み込むと、ap_register_output_filter関数でDEFLATEというプロバイダー名が自動的に登録されます(そのプロバイダーがdeflateを行います)
*4:今回はHTTPレスポンスヘッダのContent-typeがtext /plainに部分一致した場合のみ、フィルターを実行するという条件をつけています。
*5:つまりFilterChainディレクティブを使わないと、定義されたフィルター群は実行されません