Apacheのチューニング
Apacheをより有効的に利用するためのノウハウメモです。設定に用いたマシンはMacOSX、Apacheのバージョンは2.2としています。
http headers
http://www.yahoo.co.jp/ GET / HTTP/1.1 Host: www.yahoo.co.jp User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.5) KDDI-TS01 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KDDI-TS01; Windows Phone 6.5.3.5) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 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 Connection: keep-alive Cookie: B=XXXXXXXXXXX HTTP/1.1 200 OK Date: Sun, 09 Oct 2011 03:16:08 GMT P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV" Expires: -1 Pragma: no-cache Cache-Control: no-cache, private, no-store, must-revalidate X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds Vary: Accept-Encoding Connection: close Transfer-Encoding: chunked Content-Type: text/html; charset=utf-8 Content-Encoding: gzip ---------------------------------------------------------- http://news.c.yimg.jp/images/topics/20111009-00000003-sph-000-thumb.jpg GET /images/topics/20111009-00000003-sph-000-thumb.jpg HTTP/1.1 Host: news.c.yimg.jp User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.5) KDDI-TS01 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KDDI-TS01; Windows Phone 6.5.3.5) Accept: image/png,image/*;q=0.8,*/*;q=0.5 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 Connection: keep-alive Referer: http://www.yahoo.co.jp/ HTTP/1.1 200 OK Date: Sat, 08 Oct 2011 23:58:52 GMT Cache-Control: max-age=2592000 Expires: Mon, 07 Nov 2011 23:58:52 GMT Last-Modified: Sat, 08 Oct 2011 23:58:51 GMT Accept-Ranges: bytes Content-Length: 4013 Content-Type: image/jpeg Age: 11836 Via: HTTP/1.1 l7cache4047.img.bbt.yahoo.co.jp (YahooTrafficServer/1.18.6 [cHs f ]), HTTP/1.1 l7switch4008.img.bbt.yahoo.co.jp (YahooTrafficServer/1.19.8 [cHs f ]) Server: YTS/1.19.8 Connection: keep-alive
- yahooのTopページにアクセスした時のHttp Request/Response Headerの情報。
- サイトにアクセスした時のHttpHeaderでサーバサイドの設定をなんとなく理解する事が可能。Cacheの設定、KeepAliveの有効期限、動的コンテンツと静的コンテンツの切り分けなど。
- yahooでは動的コンテンツ配信するサーバと静的な画像やCSSを配信するサーバを別ドメインで構えていて、それぞれに対して設定を分けている様子。ドメインを分けるとブラウザは並列してリクエストが可能。また画像配信のサーバは間にキャッシュ専用のProxyサーバを挟んでいるみたい。
- 現在Yahooのトップページにアクセスすると402ms(onload :1.56s)でコンテンツの閲覧が可能。とても早い。
- 今日の記事ではApacheのチューニング/http header周りについて記録する。
preforkとworkerモデル
- Apache2.0以降、サーバでリクエストする処理がモジュール化(MPM:マルチプロセッシングモジュール)され数種類から選ぶ事が可能になった。代表的なものとしてpreforkとworkerがある。
- preforkとはクライアントからのリクエストを子プロセスで起動し、子プロセスがフリーズしても他のプロセスには影響しないモデル。
- workerはApacheの子プロセスがマルチスレッドで動作。クライアントに対してはスレッドが応答。1つのプロセスがマルチスレッドを利用して複数の通信を受け付ける。preforkと比較して子プロセスの起動を少なくできるのでメモリの使用量を減らす事が可能。
- 場合にもよるがworkerモデルを扱う場合は注意が必要。不安定という話もある。(PHPのいくつかのモジュールが動かない)workerモデルがテストして問題なければメリットはある。
vailable, but does not work with some modules (such as PHP).
$ httpd -V Server version: Apache/2.2.17 (Unix) Server built: Dec 1 2010 09:58:15 Server's Module Magic Number: 20051115:25 Server loaded: APR 1.3.8, APR-Util 1.3.9 Compiled using: APR 1.3.8, APR-Util 1.3.9 Architecture: 64-bit Server MPM: Prefork threaded: no forked: yes (variable process count) Server compiled with.... -D APACHE_MPM_DIR="server/mpm/prefork" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_FLOCK_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=128 -D HTTPD_ROOT="/usr" -D SUEXEC_BIN="/usr/bin/suexec" -D DEFAULT_PIDLOG="/private/var/run/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_LOCKFILE="/private/var/run/accept.lock" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="/private/etc/apache2/mime.types" -D SERVER_CONFIG_FILE="/private/etc/apache2/httpd.conf"
- 読み込まれているモジュールを確認するのはhttpd -l prefork.cが設定されているのが分かる。
$ httpd -l Compiled in modules: core.c prefork.c http_core.c mod_so.c
- MacOSXの場合、以下のようにport installコマンドを実行するとworkerモデルに設定し、起動してくれる。起動時に切り替えれると便利だなと思っているのだが、やり方を現在調査中。
$ port variants apache2 apache2 has the variants: eventmpm: Use event MPM (experimental) * conflicts with preforkmpm workermpm no_startupitem: Do not create a startup item openldap: Enable LDAP support through OpenLDAP [+]preforkmpm: Use prefork MPM * conflicts with eventmpm workermpm universal: Build for multiple architectures workermpm: Use worker MPM * conflicts with eventmpm preforkmpm $ sudo port install apache2 +workermpm $ port installed | grep apache apache2 @2.2.21_0+workermpm (active
$ sudo vim /etc/sysconfig/httpd HTTPD=/usr/sbin/httpd.worker #これを指定する $ sudo /etc/init.d/httpd restart
- prefork,workerの切り替えでStartServersなどのパラメータを変更できるような仕組みになっている。
$ vi -R /private/etc/apache2/extra/httpd-mpm.conf # prefork MPM # StartServers: number of server processes to start # MinSpareServers: minimum number of server processes which are kept spare # MaxSpareServers: maximum number of server processes which are kept spare # MaxClients: maximum number of server processes allowed to start # MaxRequestsPerChild: maximum number of requests a server process serves <IfModule mpm_prefork_module> StartServers 1 MinSpareServers 1 MaxSpareServers 10 MaxClients 150 MaxRequestsPerChild 0 </IfModule> # worker MPM # StartServers: initial number of server processes to start # MaxClients: maximum number of simultaneous client connections # MinSpareThreads: minimum number of worker threads which are kept spare # MaxSpareThreads: maximum number of worker threads which are kept spare # ThreadsPerChild: constant number of worker threads in each server process # MaxRequestsPerChild: maximum number of requests a server process serves <IfModule mpm_worker_module> StartServers 2 MaxClients 150 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestsPerChild 0 </IfModule>
設定ファイルチューニング
httpd.confに設定するパラメータをチューニングする。パラメータの説明は次の通り
パラメータ | 説明 | |
---|---|---|
StartServers | Apache起動時のプロセス数 | |
MinSpareServers | 予め待機させておくプロセス起動の最小値 | |
MaxSpareServers | 予め待機させておくプロセス起動の最大値 | |
MaxRequestsPerChild | プロセスの処理数が値を超えたらプロセスを終了させる | |
ThreadsPerChild | プロセスあたりのスレッド数 | |
ServerLimit | プロセスの最大数 | |
ThreadLimit | スレッドの最大数 | |
MaxClients | 同時接続可能数 | |
Timeout | システム処理のTimeout | |
KeepAlive | 通信状態を保持する機能 | |
MaxKeepAliveRequests | KeepAliveで接続している間に処理するリクエスト数 | |
KeepAliveTimeout | KeepAliveの有効時間 |
設定値サンプル
StartServers 2 ServerLimit 32 ThreadLimit 128 MaxClients 4096 ThreadsPerChild 128 MinSpareServers 25 MaxSpareServers 75 MaxRequestsPerChild 0 Timeout 60 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5
- 重要な項目はThreadsPerChild,MaxClients,KeepAlive,ServerLimit,ThreadLimit
- ThreadsPerChild,MaxClientsはサーバのリソース消費量に影響は与えない。
- ServerLimit,ThreadLimitは共有メモリのサイズに依存。
- パラメータの算出式は MaxClients = プロセス数 × ThreadsPerChild。上の例の場合 4096 = 32 × 128
- メモリが充実しているマシン(4GBとか)なら10000クライアント接続ぐらい可能。(リバースProxyサーバなら)
mod_ほにゃらら
以下apacheのモジュールで導入するとよりシステム処理がより高速になったりセキュリティレベルを高める事ができる。
モジュール名 | 役割 | |
---|---|---|
mod_rewrite | 特定の条件を指定し、アクセスを振り分ける事ができる。Redirect/Rewrite等が可能 | |
mod_perl/mod_php | サーバ内部でプロセスを常駐 | |
mod_gzip/mod_deflate | クライアント側への転送データを圧縮し、データ通信量を削減 | |
mod_dosdetector | Dos攻撃を判定。特定のIPから閾値以上のアクセス等をabuse | |
mod_proxy | リバースProxyの設定が可能 | |
mod_ssl | ApacheをSSL対応にする事が可能 |
keepAlive
- httpの仕様でサーバとのConnectionをまとめる事ができる。例えばHTMLの内部に多数の画像を取得するタグが埋め込まれている時に都度同じサーバに対してConnectionを確立してしまうと接続のOverHeadが発生し処理が遅くなってしまう。それを回避するために一度確立したConnectionを特定の時間内で再利用することが出来る仕組み。
- KeepAliveをONにするとWebサーバ側に負担がかかる。なぜならば特定クライアントとの接続を占有してしまうから。
- リバースProxyを使う場合、クライアント-リバースProxy間はKeepAliveをOnに設定し、リーバスProxy-Webサーバ間はKeepAliveをOffにする。これはリバースProxyサーバ内部のメモリ使用率は低く、Webサーバはメモリ負荷が高くなるという処理の特性を考えての設定。
- KeepAliveの設定例
KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5
gzip,deflate
- Apache1.3系ならmod_gzip,2系ならmod_deflateを利用し、データ転送量を圧縮する。
- データ転送量を抑える反面、サーバサイドのCPUが高負荷になる可能性がある。
- 設定は簡単でhttpd.confにLoadModuleとどのファイルにdeflate処理をかけるかを記述するだけ。
- deflateの設定例
LoadModule deflate_module libexec/apache2/mod_deflate.so AddOutputFilterByType DEFLATE text/html text/plain text/xml
- gzipの設定例
LoadModule gzip_module libexec/mod_gzip.so AddModule mod_gzip.c mod_gzip_on Yes mod_gzip_keep_workfiles No mod_gzip_minimum_file_size 1002 mod_gzip_maximum_file_size 0 mod_gzip_maximum_inmem_size 60000 mod_gzip_dechunk Yes mod_gzip_temp_dir "/tmp"(注1) mod_gzip_item_include mime "application/x-httpd-cgi" mod_gzip_item_include mime "application/x-httpd-php" mod_gzip_item_include mime text/* mod_gzip_item_include mime "httpd/unix-directory" mod_gzip_item_include file "\.shtml$" mod_gzip_item_include file "\.htm$" mod_gzip_item_include file "\.html$" mod_gzip_item_include file "\.php$" mod_gzip_item_include file "\.pl$" mod_gzip_item_include file "\.cgi$" mod_gzip_item_exclude file "\.css$" mod_gzip_item_exclude file "\.js$" mod_gzip_item_exclude mime "image/.*" mod_gzip_min_http 1001
Apache Bench
- ApacheのBenchマークスクリプト(ab)を使う。
- abを得た結果から重たいページが一目瞭然となる。
- PHPのcodeのパフォーマンス状態を解析したいのであればxdebug + webgrindという方法もある。
- abの使い方
$ ab -option URL
- オプション一覧
オプション | 説明 | |
---|---|---|
-n int | リクエストする総数 | |
-c int | 同時リクエスト数 | |
-t int | レスポンスの待ち時間を秒で指定 | |
-p filename | ファイル送信名を指定 | |
-T content-type | Content-Typeを指定 | |
-v int | 動作情報を表示 | |
-w | テスト結果をHTMLで出力 | |
-x attribute | HTML出力のtableタグに属性を追加 | |
-y attribute | HTML出力のtrタグに属性を追加 | |
-z attribute | HTML出力のtd/thタグに属性を追加 | |
-C CookieName=value | Cookieを送信 | |
-A UserName:Pass | ベーシック認証を特定のUser/Passで通過させる | |
-P UserName:Pass | 認証の必要なプロキシを通してテストさせる | |
-X ProxyServer:Port | プロキシ経由でのリクエスト | |
-V | abバージョン番号表示 | |
-k | KeepAliveを有効化 |
$ ab -n 100 -c 10 http://www.yahoo.co.jp/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.yahoo.co.jp (be patient).....done Server Software: Server Hostname: www.yahoo.co.jp Server Port: 80 Document Path: / Document Length: 25674 bytes Concurrency Level: 10 Time taken for tests: 2.956 seconds Complete requests: 100 Failed requests: 92 (Connect: 0, Receive: 0, Length: 92, Exceptions: 0) Write errors: 0 Total transferred: 2625836 bytes HTML transferred: 2570936 bytes Requests per second: 33.83 [#/sec] (mean) Time per request: 295.561 [ms] (mean) Time per request: 29.556 [ms] (mean, across all concurrent requests) Transfer rate: 867.60 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 28 42 11.8 38 66 Processing: 212 250 18.8 249 299 Waiting: 33 49 9.2 49 82 Total: 240 292 19.1 290 337 Percentage of the requests served within a certain time (ms) 50% 290 66% 301 75% 302 80% 303 90% 330 95% 335 98% 336 99% 337 100% 337 (longest request)
- パフォーマンスの重要となる指標はRequests per second(秒間あたりの処理数),Time per request(1リクエストあたりの処理時間)。rpsは数値が大きい方が良いし、tprは少ない方がより良い。
リバースProxyを使う
- リバースProxyとはクライアントとWebサーバ間に設置して、事前/事後処理を行うProxyサーバ。リバースProxyはWebサーバ間の処理振り分けが可能。
- リーバスの意味はWAN→LANの流れで処理を要求するから(通常のProxyサーバLAN→WANで働くから)。
- httpリクエスト処理の振り分け、メモリの効率的な使用、データのバッファリング、キャッシュなどが導入のメリット
- Apache,lighttpd,squidを利用することで実現が可能。
- Apacheの場合はmod_proxyを利用する。
- 静的/動的コンテンツを含むページの場合は導入した方が良い。コンテンツの特性によりリクエスト先を分ける等。
mod_proxy
- mod_proxyの簡単な設定について記述する。
- httpd.confにモジュールを追加する。
LoadModule proxy_module libexec/apache2/mod_proxy.so
- 覚えておくべきディレクティブ
名前 | 説明 | |
---|---|---|
ProxyRequests | フォワードプロキシサーバとしての動作の有効/無効の設定 | |
ProxyPass | リモートサーバをローカルサーバの名前空間にマッピング | |
ProxyPassReverse | HTTP リダイレクト応答の Location, Content-Location, URI ヘッダの調整 | |
ProxyPassReverseCookieDomain | リバースProxyサーバからのSet-CookieヘッダのDomain文字列を調整 | |
ProxyPassReverseCookiePath | リバースProxyサーバからのSet-Cookie ヘッダの Path 文字列を調整 |
- ProxyPassを使っている場合はProxyRequestsのディレクティブはoffにすべき。
- 単純なディレクティブ設定例
ProxyRequests Off ProxyPass /foo http://www.example.com ProxyPassReverse /foo http://www.example.com ProxyPassReverseCookieDomain www.example.com www.example1.com ProxyPassReverseCookiePath / /proxy/
-
- /fooへのアクセスをwww.example.comにプロキシリクエストに変換(ProxyPass)。
- /fooへのアクセスでwww.example.comがリダイレクトした時にリダイレクト先の情報をHttpHeaderに書き込む(ProxyPassReverse)
- ヘッダのURLの代わりにSet-CookieヘッダのDomain文字列を書き換え。www.example.comをwww.example1.comに変更 (ProxyPassReverseCookieDomain)。
- ヘッダのURLの代わりにSet-Cookieヘッダのpath文字列を書き換え。 / を/proxyに変更(ProxyPassReverseCookiePath)