第15回 Apacheパフォーマンス・チューニングのポイント

Apacheをチューニングすることにより、Webサイトのパフォーマンスをより向上させることができる。しかし、その前に何をチューニングすべきなのかを見極める必要がある。

一志 達也<ichishi@pochi.tis.co.jp>
TIS株式会社
2002/6/29
Index
ApacheによるWebサーバ構築
チューニングへのアプローチ
 Apacheのチューニングポイント
 Webシステム固有の問題
  現状の測定(ベンチマーク)と結果の着眼点
 測定結果の分析

 この連載もいよいよ大詰めとなった。長く続けている間にApache 2.0のリリースまで迎えてしまったが、筆者が思い付く限りのことを紹介してきたつもりだ。

 最後に残したテーマは、「パフォーマンス・チューニング」である。より少ない資源でより高速なレスポンスを確保するために、パフォーマンス・チューニングは欠かせない。これは、あらゆるソフトウェアに当てはまる。設定が一通りできるようになればApacheを問題なく動作させることが可能だが、それをより効率よく動作させられなくては不十分だ。

 本サイトの読者であればよくご存じのことと思うが、パフォーマンスのチューニングは非常に奥深いものである。語り尽くすことなどできないが、皆さんの一助となれば幸いである。

チューニングへのアプローチ

 パフォーマンス・チューニングという言葉に敏感な人は多い。同じ処理であれば、できる限り短時間で終わる方がよいということは、共通認識たり得るからだろう。しかし、そのアプローチは実にさまざまであり、そう簡単にはできない。

コラム 非論理的思考
 周囲を見回してみると、暗やみの中を手探りで進むことを楽しんでいる人もいるように感じるときがある。論理的に思考することなく、ブラックボックス化されたソフトウェアの内部を想像し、想像のうえで議論しながら試行錯誤していないだろうか?

  筆者にもそうした時期はあったが、分からないものは分からないのだ。

 論理的に考えれば、パフォーマンスのチューニングといっても、できることは限られている。人間にとってはいくつもの意味を持った処理であっても、コンピュータにしてみれば、どれも「入出力を伴った計算」にすぎないのだ。つまり、次の4つの要素で構成された一連の作業でしかない。

  • CPUでの計算
  • ディスクの読み書き
  • メモリの読み書き
  • 周辺機器とのやりとり(ネットワークやプリンタなど)

 要は、それを「いかに速く終わらせるか」というだけの話である。

Apacheのチューニングポイント

 コンピュータが行う作業が明確になれば、後は1つ1つをいかに短時間で終らせるかを考えればいい。

 CPUの計算時間を短縮する方法は、2つしか存在しないと考えられる。「CPUを高性能なものに取り換える」か「プログラムコードの効率を上げる」かである。

 もちろん、Apacheはオープンソースのソフトウェアだから、プログラムコードを書き換えて効率を改善することはできる。しかし、それはあまり現実的ではないだろう。なぜなら、自分で作ったプログラムと違って、ボトルネックや改善点を見つけるのは容易ではないからである。人によっては難しくないのかもしれないが、ここでは現実的ではないとして除外することにする。

 CPUに続いて考えるべきはディスクの読み書き時間の短縮だが、これも2つの選択肢が存在する。「ディスクを高性能なものに取り換える」か「ディスクの読み書きを少なくするようにプログラムコードを改良する」かである。

 これも先ほどのCPUの場合と同じで、Apacheのプログラムコードを書き換えるのは現実的でない。もう想像に難くないと思うが、メモリの読み書きの時間を短縮することについても、同様の結論が導き出されてしまう。

 そうなると、「Apacheでは何もチューニングできないのか」と思われるかもしれないが、実はもう1つのアプローチが存在する。それは、「いかに多数の同時接続を処理するか」である。ご存じのとおり、Apacheは単独のリクエストを順次処理するのではなく、同時に多数のリクエストを受け入れる性質のソフトウェアである。これは、データベース・サーバでOLTPを行うのに似ている。1つ1つの処理速度を向上させるのと同様に、同時に多数のリクエストを処理できるようにすることが重要となるのである。

Webシステム固有の問題

 Apache単独で見れば、前述したチューニング・ポイントしかない。しかし、WebではApache以外の要素も関係してくる。クライアント(Webブラウザ)が処理を要求し、サーバ(Apache)がそれにこたえ、クライアントにWebページとして表示するまでが一連の処理といえるからだ。細かく挙げるとキリがないが、それを完了するまでには大まかに次のような時間が必要となる。

  • サーバ側(Apache+α)の処理時間
  • ネットワークの通信時間
  • クライアント側(Webブラウザ)の処理時間

 ここで、サーバ側を「Apache+α」としたのには理由がある。一般的なWebサーバであっても、昨今は動的なWebページ、すなわちプログラムの実行結果に基づくページを扱うものが多い。この場合、Apache単体の処理時間に加えて、ページを作成するプログラムやアプリケーションサーバの処理時間を必要とする。Apache単体でできるチューニングは限られていても、これらのプログラムの処理時間を短縮するために、CPUの計算時間やディスクの読み書きの時間を短縮する努力は意味があるだろう。

 クライアント側では、HTMLのレンダリングという処理が行われる。Webブラウザは、HTMLを受信するとその内容を解析して表示(レンダリング)する。そのHTMLファイル以外に画像や動画などのファイルが必要であれば、それも別途受信して表示する必要があるのだ。この時間には多くの場合、Apacheがファイルを送り返す時間よりも短縮の余地が残されているものである。きれいにデザインされた見栄えのいいページ作りと、Webブラウザのレンダリング時間の短縮。この相反する問題を解決するのは容易ではないが、シンプルで短いHTMLは、それだけネットワークの通信時間を短縮することにもつながる。

 HTMLのパフォーマンスを改善するなら、Webページを構成するファイルをすべてローカルコンピュータに準備し、Webブラウザで開いてみればいい。それにかかる時間が、Webサーバやネットワーク以外にかかっている、レンダリングの時間と考えられる(編注)。あまりにも遅いようなら、それを改善する努力をするべきだろう。

編注:もちろん、ここにはローカルディスクの読み込み時間も含まれる。

 ネットワークの通信時間の短縮についても考えたいところだが、これは閉鎖されたネットワーク(イントラネット)でしか意味を成さない。インターネットにおいてネットワークのパフォーマンスを上げようとしても、手の届かない(自分の管理範囲でない)問題になるからである。もちろん、サイト内のサーバ間やインターネットの出口(専用線の手前)までのパフォーマンスが悪ければチューニングするべきだが、できることは限られている。

 とにもかくにも、リクエストを発行してからWebブラウザにページが表示されるまでの時間が遅いと感じるならば、Apacheだけでなくこれらのポイントにも着目するべきである。


 

現状の測定(ベンチマーク)と結果の着眼点

 ここからはApacheに着目して、パフォーマンス・チューニングのための準備を行う。チューニングするに当たって、まず現状を十分に分析し、具体的な目標を定めることから始めたい。目標をどれだけ具体化するかはともかくとしても、現状を数値的に知りもせずに、漠然と「遅い遅い」と騒いでいても仕方がない。

 現状を数値的にとらえるにはツールが必要となる。いわゆるベンチマーク・ツールだ。Apacheには、標準で「ab」(Apache Bench)というツールが付属している。abの構文は、

ab [options] URL

のように、オプションとテストを実行するURLを指定する。

例:
ab -n 100 -c 10 http://172.16.1.2/index.html
一般的な実行
ab -n 100 -c 10 -w http://172.16.1.2/index.html > bench.html
結果をHTMLファイルに保存
ab -n 100 -c 10 -A user:password http://172.16.1.2/index.html
認証が必要なコンテンツでのテスト

 abのオプションは、基本的に「同時接続数」と「リクエスト数」を指定する(具体的なオプションは表1を参照)。例えば、同時接続数を100、リクエスト数を10000とすれば、同時に100のリクエストが発生したときに、10000リクエストを処理するまでの性能が測定されるわけだ。

オプション
意味
-n 数値 テストで発行するリクエストの回数を数値で指定
-c 数値 テストで同時に発行するリクエストの数を数値で指定
-t 数値 サーバからのレスポンスの待ち時間(秒)を数値で指定
-p ファイル名 サーバへ送信するファイルがある場合に指定
-T コンテンツタイプ サーバへ送信するコンテンツヘッダを指定
-v 数値 指定した数値に応じた動作情報を表示
-w 結果をHTMLで出力(出力をファイルに保存すればWebブラウザで表組みされたものが見られる)
-x 属性 HTML出力のtableタグに属性を追加(BORDERなど)
-y 属性 HTML出力のtrタグに属性を追加
-z 属性 HTML出力のtdまたはthタグに属性を追加
-C 'Cookie名称=' Cookie値を渡してテストする
-A ユーザー名:パスワード ベーシック認証が必要なコンテンツにテストする
-P ユーザー名:パスワード 認証の必要なプロキシを通じてテストする
-X プロキシサーバ名:ポート番号 プロキシ経由でリクエストする場合に指定
-V abのバージョン番号を表示
-k HTTP/1.1のKeepAliveを有効にしてテストする
-h abのヘルプを表示
表1 abのオプション

 ab実行時のサンプルをリスト1リスト2に示すが、ここで問題となるのは次の3点である。

abを実行するコンピュータの位置

 abがインストールされているコンピュータとなると、まずはWebサーバそのものということになるだろう。しかし、Webサーバでの実行は、効果測定に適しているとはいい難い。なぜなら、それは計算時間を測定しているだけであって、接続に要する時間などを測定できるわけではないからである。

 abは、少なくともWebサーバとは別のコンピュータで実行したい。できれば、ルータの直前か直後(図1)がいいだろう。そうすることで、より現実的なパフォーマンスを測定できるからである。

図1 abの測定位置

発生させる同時接続数量

 リクエスト数はサンプリング数量だから、あまり多過ぎない程度に大きめの値を指定すればいい。それに対し、同時接続数の指定は慎重に選択したい。そのWebサーバへの同時接続数があらかじめ予測できるようであれば、その数値の前後30%程度の範囲で測定すればいいだろう。予測がつかない場合は広い範囲で測定するしかないが、どちらにしても同時接続数の限界を測るのも重要なポイントの1つだ。

 また、1台のコンピュータが発生させられる同時接続数についても注意したい。例えば、高性能なUNIXサーバに対して測定する場合、相当な数の同時接続を発生させる必要がある。しかし、普通のPCサーバで発生させられる同時接続数には、おのずと限界がある。従って、複数台のコンピュータにabを入れて測定しなければならない。たとえ、1台のコンピュータでこなせる数だとしても、複数台での測定も試してみることを勧める。

リクエストするURL

 最後に、リクエストするURLであるが、これも十分に検討するべき項目だといえる。先にも述べたとおり、1つのWebページを表示するには、HTMLファイルとともに画像ファイルなども必要になる。しかし、abは単一かつ同一のファイルをリクエストすることしかできない。

 これは、Webサーバにとって有利な条件での測定となってしまう。そこで、複数台のコンピュータから、それぞれ別なファイルをリクエストするなどの工夫をしてみたい。また、リクエストするファイルの容量によって、どのような変化があるかなども、測定してみるといいだろう。

 さらには、静的なファイルだけでなく、プログラムを実行して作成されるページへのリクエストも測定したい。これも、単純なプログラムから、複雑なプログラムまで測定しておく。どんな場合でもいえることだが、さまざまなパターンの測定を、より多く集めた方が、結果の分析も多角的に行えるものである。

# ./ab -n 10000 -c 100 http://172.16.1.2:8000/HTML/INDEX.htm
This is ApacheBench, Version 1.3d <$Revision: 1.59 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd,
 http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking 172.16.1.2 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Finished 10000 requests
Server Software:        Apache/1.3.9
Server Hostname:        172.16.1.2
Server Port:            8000

Document Path:          /OA_HTML/US/ICXINDEX.htm
Document Length:        3413 bytes

Concurrency Level:      100
Time taken for tests:   11.662 seconds
Complete requests:      10000
Failed requests:        0
Broken pipe errors:     0
Total transferred:      36900274 bytes
HTML transferred:       34139446 bytes
Requests per second:    857.49 [#/sec] (mean)
Time per request:       116.62 [ms] (mean)
Time per request:       1.17 [ms] (mean, across all concurrent 
requests)
Transfer rate:          3164.15 [Kbytes/sec] received

Connnection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    10  155.7      0  3002
Processing:    26   106   60.6     98  3594
Waiting:       24   105   60.6     98  3593
Total:         26   115  165.2    100  3596

Percentage of the requests served within a certain time (ms)
  50%    100
  66%    114
  75%    122
  80%    129
  90%    144
  95%    174
  98%    226
  99%    254
 100%   3596 (last request)
リスト1 静的なコンテンツへのテスト(同時100接続で10000リクエストを処理)

# ./ab -n 10000 -c 100 http://172.16.1.2:8000/jsp/test.jsp
This is ApacheBench, Version 1.3d <$Revision: 1.59 $> apache-1.3
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd,
 http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking 172.16.1.2 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Finished 10000 requests
Server Software:        Apache/1.3.9
Server Hostname:        172.16.1.2
Server Port:            8000

Document Path:          /OA_HTML/services/login.jsp
Document Length:        5029 bytes

Concurrency Level:      100
Time taken for tests:   302.561 seconds
Complete requests:      10000
Failed requests:        2579
   (Connect: 0, Length: 2579, Exceptions: 0)
Broken pipe errors:     0
Non-2xx responses:      2579
Total transferred:      41028759 bytes
HTML transferred:       38870059 bytes
Requests per second:    33.05 [#/sec] (mean)
Time per request:       3025.61 [ms] (mean)
Time per request:       30.26 [ms] (mean, across all concurrent 
requests)
Transfer rate:          135.60 [Kbytes/sec] received

Connnection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0     8  152.4      0  2994
Processing:     2  2803 3308.1   1209 165915
Waiting:        2  2802 3308.1   1208 165914
Total:          2  2811 3340.7   1209 165915

Percentage of the requests served within a certain time (ms)
  50%   1209
  66%   1976
  75%   2837
  80%   3649
  90%   5479
  95%  11034
  98%  24299
  99%  28714
 100%  165915 (last request)
リスト2 動的なコンテンツ(JSP)へのテスト(同時100接続で10000リクエストを処理)。静的コンテンツに比べて、圧倒的に時間がかかっている点に注目

測定結果の分析

 abの結果(リスト1リスト2)の中で、着目すべき項目は次のとおりだ。ただし、利用するabのバージョンによっては表示内容が異なり、項目が存在しないこともある。abだけでも最新のものを使うといいだろう。その場合は、Apacheの最新版を入手して全体をコンパイルし、abだけを取り出して置き換えればいい。

  • リクエストの成否(Complete requestsとFailed requests)
     abで発生させたリクエストがすべて成功していればいいが、一部が失敗するようならWebサーバの処理が追い付いていない。これは、特にプログラムを実行してページを生成する場合に起こりやすく、同時接続数の限界を超えていると考えるべきだろう。

  • 1秒間に処理されたリクエスト数(Requests per second)
     Webサーバのベンチマークで、最も重視されるのがこの項目である。CPUのMIPSやデータベースのTPCと同じく、1秒間にどれだけ処理できたかが重要な数値になる。パラメータやプログラムを修正したりしてその効果を測る際にも、この項目の数値がどれだけ改善するか(数値が大きくなるか)で評価を行う。

  • 接続時間・処理時間・待ち時間の内訳(Connect/Processing/Waiting)
     これらの項目は、測定したリクエスト全体でのばらつきやリクエスト当たりの処理の内訳を見極めるために用いる。

 このほかに、転送速度(Transfer rate)を見て、ネットワーク環境の実効速度よりも遅いようであれば、ネットワーク環境のチューニングも考慮する。ネットワーク環境の実効速度は、そのネットワーク経路上の最も細い回線の60%程度とみればよい。例えば、経路の一部に10BASE-Tが交じっていれば6Mbit/秒程度、100BASE-TXが交じっていれば60Mbit/秒程度とみる。

 これらを総合的に見て、Webサーバの処理限界やチューニングのポイントを見極める。さらに、その見極めから目標を定め、チューニングを施していくわけだ。次回は、今回の内容を踏まえたうえで、チューニングのポイントを具体的に紹介する。