ksaitoの日記

日々試したことの覚え書き

Apacheの帯域制御とアクセス制御

サイズが大きいコンテンツをApacheで公開している場合、アクセスが集中すると無応答になることがあります。
原因は、いろいろと考えられますがアクセスが集中しても、無応答になる前に利用者に「アクセスが集中しているので暫くしてからアクセスして欲しい」といった内容のメッセージを表示したいものです。
また、大量なデータを制限なく流すとルータやProxyサーバといったネットワーク機器が耐えられなくなるためサイズの大きなコンテンツについては、データを流す量を制限したいところです。(こうした制御が必要になるのは、まれなケースだとは思いますが...)
アクセスの集中からサーバやネットワークを守るための帯域制御とアクセス制御をするためのApacheモジュールを調べてみました。

どんな手段があるか?

Apacheの帯域制御をするモジュールは、何種類かあるようです。
このサイトに非常に良くまとまっていますが「これで間違いなし」というものはないようです。
ubuntuでパッケージが用意されているのはmod_bwとmod_bwshareです。
mod_bwshareは、1つのクライアントからの大量のアクセスを制限するためのもので、DoS攻撃への対抗手段なので用途が違います。
mod_bwがApacheからのデータを流す量を制限したり、同時接続数の上限を制限するようです。

mod_bwのインストール

aptでインストールしてApacheを再起動します。

$ sudo aptitude install libapache2-mod-bw
$ sudo a2enmod bw
Enabling module bw.
Run '/etc/init.d/apache2 restart' to activate new configuration!
$ sudo /etc/init.d/apache2 restart
 * Restarting web server apache2
 ... waiting    ...done.
$ 

帯域の制御

帯域の制御は、下記の設定を追加してApacheを再起動します。
この設定では、/test.movについて100Kbpsに制限します。

$ pwd
/etc/apache2/conf.d
$ cat bw.conf
<Location /test.mov>
      BandwidthModule On
      ForceBandWidthModule On
      Bandwidth all 102400
</Location>
$ 

abで確認してみると、ほぼ100Kbpsになっていることが確認できます。

$ ab -n 1 -c 1 http://ubuntu/test.mov
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 ubuntu.sa.local (be patient).....done

Server Software:        Apache/2.2.14
Server Hostname:        ubuntu
Server Port:            80

Document Path:          /test.mov
Document Length:        219245500 bytes
..省略..
Transfer rate:          99.23 [Kbytes/sec] received
..省略..
$ 

接続数を制限する

帯域の制御をするとネットワークの帯域を無尽蔵に使うことはなくなりますが、ブラウザでアクセスしてみると応答が遅くなりイライラするだけです。
このままでは、利用者がリロードボタンを押して状況を悪化させかねません。
下記の設定で同時接続数を設定して、ある一定以上のアクセスがあった場合には、503ステータスを返してサーバがビジー状態であることを利用者に知らせます。
下記の設定では、同時5接続以上になったら503を返すように設定します。

$ cat bw.conf
<Location /~ksaito/test.mov>
      BandwidthModule On
      ForceBandWidthModule On
      Bandwidth all 102400
      MaxConnection all 5
</Location>
$

再びabで同時10クライアントでアクセスするとアクセスログには、下記のように503が返されていることが分ります。

$ tail access.log 
 - - [23/Sep/2010:21:38:49 +0900] "GET /test.mov HTTP/1.0" 503 629 "-" "ApacheBench/2.3"
 - - [23/Sep/2010:21:38:49 +0900] "GET /test.mov HTTP/1.0" 503 629 "-" "ApacheBench/2.3"
$

ブラウザでアクセスすると下記のような画面が表示されます。

ユーザフレンドリなメッセージにする

デフォルトのメッセージでは、ユーザフレンドリではないので、ErrorDocumentディレクティブで分りやすいメッセージを表示したり、soryページに飛したりします。
下記が、メッセージを変更する場合の設定です。

$ cat bw.conf
<Location /~ksaito/test.mov>
      BandwidthModule On
      ForceBandWidthModule On
      Bandwidth all 102400
      MaxConnection all 5
      ErrorDocument 503 "I'am busy!"
</Location>
$

こちらが、soryページに飛す設定です。

$ cat bw.conf
<Location /~ksaito/test.mov>
      BandwidthModule On
      ForceBandWidthModule On
      Bandwidth all 102400
      MaxConnection all 5
      ErrorDocument 503 /index.html
</Location>
$

帯域と同時接続数は、いくつにしたら良いか?

結論から言うと、やってみないと分らないということになります。
必要なことは、同時アクセス数と送受信のデータ量を常にモニタリングしていること。
これらのデータから得られるピーク時の同時アクセス数とデータ量に安全係数(2倍までOKとするとか)と制約条件(契約している回線の帯域が上限とか、サーバリソースとか)を考慮して設定していきます。
正解はないので、モニタリングを続けて手持ちのリソースでの限界に近づけていきます。