アーカイブ

‘Apache’ カテゴリーのアーカイブ

PHPでFatal error: Allowed memory size of …が出た場合の対処方法

2009 年 11 月 7 日 oinume コメントはありません

あまりPHPのことわからないのですが、WordPressで

Fatal error: Allowed memory size of 8388608 bytes exhausted

というエラーメッセージが出ました。ぐぐると「php.iniのmemory_limitを64Mとか大きな値に設定すべし」とあるのですが、Ubuntuの /usr/share/php5/php.ini を

memory_limit = 64M

と直しても改善しませんでした。で、さらに調べてみるとどうやら /etc/php5/apache2/php.ini なんていうファイルが… これを上記と同じように64Mにしてapacheを再起動すると、めでたくエラーは出なくなりました。紛らわしいからphp.iniは一つにしておいてほしい…

カテゴリー: Apache, PHP タグ: ,

Apacheでリバースプロキシ(mod_proxy)を活用する(3) – 負荷分散編

2009 年 4 月 12 日 oinume コメントはありません

前回のApacheでリバースプロキシ(mod_proxy)を活用する(2) – 設定編ではフロントエンドのリバースプロキシとバックエンドのCGIサーバの設定を行ないました。今回は、サイトの負荷が大きくなってきた時にバックエンドのサーバを複数台にする設定を説明します。イメージ図としては下記のような感じです。

リバースプロキシでの負荷分散のイメージ

バックエンドの準備

まずは負荷分散が確認できるようにバックエンドのサーバを2台に増やします。前回作成した /etc/apache2/httpd_backend_8080.conf をコピーして /etc/apache2/httpd_backend_8081.conf を作成し、このhttpd_backend_8081.confがListenするポートを以下のように8080から8081にします。

--- httpd_backend_8080.conf     2009-04-07 00:32:55.000000000 +0900
+++ httpd_backend_8081.conf     2009-04-07 00:36:09.000000000 +0900
@@ -1,5 +1,5 @@
 #
-# /etc/apache2/httpd_backend_8080.conf
+# /etc/apache2/httpd_backend_8081.conf
 #
 User www-data
 Group www-data
@@ -12,15 +12,15 @@
 LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so
 
 ServerRoot "/etc/apache2"
-Listen 8080
-ServerName localhost:8080
-PidFile /tmp/httpd_backend_8080.pid
+Listen 8081
+ServerName localhost:8081
+PidFile /tmp/httpd_backend_8081.pid
 ServerAdmin example_at_example.com
 DocumentRoot "/var/www/html"
 TypesConfig /etc/mime.types
 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
-ErrorLog /tmp/error_8080.log
-CustomLog /tmp/access_8080.log combined
+ErrorLog /tmp/error_8081.log
+CustomLog /tmp/access_8081.log combined
 UseCanonicalName Off
 AddHandler cgi-script .pl

ポートを変更したら、下記のコマンドでこの8081でListenするApacheを立ち上げておきます。

$ sudo /usr/sbin/apache2ctl -f /etc/apache2/httpd_backend_8081.conf -k start

8080のサーバも停止しているようであれば起動しておきましょう。

$ sudo /usr/sbin/apache2ctl -f /etc/apache2/httpd_backend_8080.conf -k start

リバースプロキシで負荷分散の設定

バックエンドのサーバを2台に増設したら、その2台にリクエストを振り分けられるようにフロントエンドのリバースプロキシを設定し直します。やり方は色々ありますが、まずは一番シンプルな「リクエストをランダムに2台に振り分ける」というやり方を試してみたいと思います。

前回の設定では

RewriteEngine on
RewriteRule ^/(.+)\.pl$ http://localhost:8080/index.pl [L,P,QSA]
RewriteRule ^/(.+)\.(gif)$ /var/www/html/$1.$2 [L,QSA]

というように、.plファイルへのアクセスを localhost:8080 に振り分ける設定でした。今回はこの部分を変更して、localhost:8080とlocalhost:8081に振り分けるように設定します。具体的には、前回のhttpd.confに対して

RewriteMap server rnd:/usr/local/httpd_proxy_2.2.11/conf/server.txt

という設定をRewriteRuleの前に追加し、RewriteRuleを下記のように変更します。

RewriteRule ^/(.+)\.pl$ http://localhost:8080/index.pl [P,QSA]
            ↓
RewriteRule ^/(.+)\.pl$ http://${server:backend}/index.pl [L,P,QSA]

つまり前回のhttpd.confの設定との差分は下記のようになります。

--- httpd.conf.entry246 2009-04-12 17:22:07.000000000 +0900
+++ httpd.conf  2009-04-12 17:29:49.000000000 +0900
@@ -421,6 +421,7 @@
 </Directory>
 
 RewriteEngine on
-RewriteRule ^/(.+)\.pl$ http://localhost:8080/index.pl [P,QSA]
+RewriteMap server rnd:/usr/local/httpd_proxy_2.2.11/conf/server.txt
+RewriteRule ^/(.+)\.pl$ http://${server:backend}/index.pl [L,P,QSA]
 RewriteRule ^/(.+)\.(gif)$ /var/www/html/$1.$2 [L,QSA]

httpd.confを書き換えたら、RewriteMapで指定した /usr/local/httpd_proxy_2.2.11/conf/server.txt というファイルを作成します。

# echo 'backend localhost:8080|localhost:8081' >  /usr/local/httpd_proxy_2.2.11/conf/server.txt

これらの設定は何を意味するかというと

RewriteRuleで指定したパターンにマッチするリクエストがあった場合、RewriteMapで定義したサーバのどれか1台にランダムでリクエストを転送する

ということです。RewriteMapというディレクティブでは /usr/local/httpd_proxy_2.2.11/conf/server.txt というファイルを指定して、そのファイルの中身は

backend localhost:8080|localhost:8081

となっています。ここで定義したバックエンドのサーバをその後ろのRewirteRuleで ${server:backend} として参照しているわけです。前回の設定では1台にしかリクエストを転送していませんでしたが、このような設定をすることで「どれか1台にランダムで」という形で負荷分散することが可能になります。

というわけで、設定が完了したら mod_proxyサーバを再起動します。

$ sudo /usr/local/httpd_proxy_2.2.11/bin/apachectl -k restart

動作確認

サーバが起動したらブラウザから http://example/index.pl に何回かアクセスしてみましょう。(exampleの部分は自身のホスト名に適宜変更してください)

/tmp/access_8080.logと/tmp/access_8081.log の両方に下記のようなログが残っているはずです。

127.0.0.1 - - [12/Apr/2009:17:46:35 +0900] "GET /index.pl HTTP/1.1" 200 129 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ja-JP-mac; rv:1.9.0.8) Gecko/2009032608 Firefox/3.0.8"

これが確認できれば localhost:8080 と localhost:8081 の2台のバックエンドのサーバでの負荷分散環境が構築できたということになります。(なお、例によってそのままの設定だとセキュリティに問題があるので、作業が終了したら起動したApacheのプロセスは止めておくことをお奨めします)

まとめ

mod_proxyを使った負荷分散環境の構築は、バックエンドのサーバさえしっかり準備ができていればリバースプロキシの設定はかなり簡単だったのではないでしょうか。このような複数台のバックエンドのサーバにリクエストを振り分けるような設定は負荷分散としても有効ですが、その他の使い道として「バックエンドのサーバを1台メンテナンスで一時的に止めたい」というような時にサイトを止めることなくメンテナンスが可能になります。(具体的には、server.txtからメンテナンス対象のサーバを削除するだけでリクエストが転送されなくなります)

このように、リバースプロキシの用途は単純な負荷分散以外にもあるので、設定の仕方を知っておくだけでサイトの運用に非常に役立つと思います。

Apacheクックブック 第2版 ―Webサーバ管理者のためのレシピ集

著者/訳者:Ken Coar Rich Bowen

出版社:オライリージャパン( 2008-09-26 )

大型本 ( 308 ページ )


カテゴリー: Apache タグ: ,

Apache + mod_fcgid + tDiaryでrubyプロセスが残りっぱなし

2009 年 2 月 16 日 oinume コメントはありません

古いおいぬま日報(不定期)のtDiaryなのですが、Ubuntu 8.10にしてからどうも調子が悪くて悩んでいます(*1)。というのは、tDiaryをapacheのmod_fcgid で動かしているのですが、CPU使用率100%近くなっているFastCGIのrubyプロセスがずっと残りっぱなしになっているようなのです。おかげで無駄にCPUリソースを食って非エコ状態になっています。
*1) 環境はUbuntu 8.10 + Apache 2.2.11 + mod_fcgid 2.2 + tDiary 2.2.0

apacheのエラーログには

[Mon Feb 16 20:17:26 2009] [notice] mod_fcgid: process /home/kazuhiro/www/diary/htdocs/index.fcgi(30333) exit(communication error), get stop signal 9

と何やらあやしげなログが出ているのですが、なぜ communication errorになるのかさっぱりわかりません。

該当プロセスをkillすればCPUリソース使い過ぎな状態は回避できるので、10分以上経ったrubyプロセスを強制的にkillするスクリプトをでっち上げてcronで動かすように。

#!/usr/local/bin/perl
 
# $ sudo aptitude install libproc-processtable-perl
use strict;
use Proc::ProcessTable;
 
my $pt = Proc::ProcessTable->new('cache_ttys' => 1);
for my $p (@{ $pt->table }) {
    if ($p->cmndline =~ /^ruby.+index\.fcgi/) {
        my $elapsed = time() - $p->start;
        if ($elapsed > 60 * 10) {
            $p->kill(9);
            print sprintf "%s (%s) killed!\n", $p->pid, $p->fname;
        }
    }
}

mod_fcgidじゃなくてmod_fastcgiにすれば改善しそうな気もしますが、もうちょっと切羽詰まってから試してみようと思います。それにしてProc::ProcessTableモジュールは便利でした。

カテゴリー: Apache タグ: , ,

Apacheでリバースプロキシ(mod_proxy)を活用する(2) – 設定編

2009 年 2 月 5 日 oinume コメントはありません

Apacheでリバースプロキシ(mod_proxy)を活用する(1) – インストール編に続いて、今回は実際にリバースプロキシサーバを構築してみたいと思います。

まずはバックエンドのサーバを準備

リバースプロキシを構築する前に、リバースプロキシサーバからリクエストが転送されるバックエンドのアプリケーションサーバを用意しておきます。今回はUbuntuでaptからインストールできるApacheを使用します。apache2パッケージがインストールされていない場合は、まずはこれをインストールしておきましょう。

$ sudo apt-get install apache2

インストールが完了したら下記のようなアプリケーションサーバ(といってもただCGIスクリプトを動かすだけのサーバ)の設定ファイルを /etc/apache2/httpd_backend_8080.conf として用意します。

#
# /etc/apache2/httpd_backend_8080.conf
#
User www-data
Group www-data
# modules
LoadModule authn_default_module /usr/lib/apache2/modules/mod_authn_default.so
LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so
LoadModule authz_host_module /usr/lib/apache2/modules/mod_authz_host.so
LoadModule cgi_module /usr/lib/apache2/modules/mod_cgi.so
LoadModule dir_module /usr/lib/apache2/modules/mod_dir.so
LoadModule mime_module /usr/lib/apache2/modules/mod_mime.so
 
ServerRoot "/etc/apache2"
Listen 8080
ServerName localhost:8080
PidFile /tmp/httpd_backend_8080.pid
ServerAdmin example_at_example.com
DocumentRoot "/var/www/html"
TypesConfig /etc/mime.types
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
ErrorLog /tmp/error_8080.log
CustomLog /tmp/access_8080.log combined
UseCanonicalName Off
AddHandler cgi-script .pl
 
<IfModule prefork.c>
    StartServers         1
    MinSpareServers      1
    MaxSpareServers      5
    MaxClients          20
    MaxRequestsPerChild 50
</IfModule>
<Directory /var/www/html>
    Options ExecCGI FollowSymLinks
    AllowOverride None
</Directory>

設定ファイルを用意したら以下のコマンドでDocumentRootで指定したディレクトリを作成し、その下にCGIスクリプトである index.pl を用意します。

$ sudo mkdir -p /var/www/html
$ sudo chmod 755 /var/www/html
$ sudo vi /var/www/html/index.pl
#!/usr/bin/perl
 
use strict;
use CGI;
 
my $q = CGI->new;
print $q->header(
    -type => 'text/html',
);
 
print <<"EOS";
<html>
<head>
<title>Hello world</title>
</head>
<body>
<h1>Hello world!!</h1>
<img src="httpd_logo_wide.gif" />
</body>
</html>
EOS

index.pl を作成したら実行権限を付与します。そしてサンプルのための画像を Apache のサイトからダウンロードして /var/www/html/httpd_logo_wide.gif として保存します。

$ sudo chmod +x /var/www/html/index.pl
$ cd /var/www/html
$ sudo wget http://httpd.apache.org/images/httpd_logo_wide.gif

これで準備が整いました。アプリケーションサーバの Apache を起動しましょう。

$ sudo /usr/sbin/apache2ctl -f /etc/apache2/httpd_backend_8080.conf -k start

起動したら http://example:8080/index.pl にアクセスして Hello world!! なページが表示されることを確認します。example のホスト名は例なので、お手持ちのマシン名に置き換えてください。これでバックエンドのサーバの設定は完了です。もし起動しない場合はエラーログが /tmp/error.log にあるので、これを確認してみてください。

リバースプロキシの準備

次は肝心のリバースプロキシの設定です。前回 /usr/local/httpd_proxy_2.2.11 にインストールしたので、/usr/local/httpd_proxy_2.2.11/conf/httpd.conf を以下のように修正します。
リバースプロキシの設定については ProxyPassReverse を使うやり方と mod_rewrite の [P] を使う2種類のやり方があると思いますが、今回は mod_rewrite でやりたいと思います。

--- httpd.conf.orig     2009-02-01 13:06:48.000000000 +0900
+++ httpd.conf  2009-02-04 22:40:14.000000000 +0900
@@ -106,7 +106,7 @@
 # documents. By default, all requests are taken from this directory, but
 # symbolic links and aliases may be used to point to other locations.
 #
-DocumentRoot "/usr/local/httpd_proxy_2.2.11/htdocs"
+DocumentRoot "/var/www/html"
 
 #
 # Each directory to which Apache has access can be configured with respect
@@ -412,3 +412,15 @@
 SSLRandomSeed startup builtin
 SSLRandomSeed connect builtin
 </IfModule>
+
+<Directory /var/www/html>
+    Options Indexes FollowSymLinks MultiViews
+    AllowOverride Indexes Limit
+    Order allow,deny
+    Allow from all
+</Directory>
+
+RewriteEngine on
+RewriteRule ^/(.+)\.pl$ http://localhost:8080/index.pl [L,P,QSA]
+RewriteRule ^/(.+)\.(gif)$ /var/www/html/$1.$2 [L,QSA]

修正内容を順番に大雑把に解説すると

  1. DocumentRootの変更
  2. /var/www/htmlディレクトリの設定
  3. mod_rewriteによるリバースプロキシの設定

となります。詳しく見ておきたいのは3.の部分で

RewriteEngine on

というディレクティブで mod_rewrite によるURLの書き換えを有効にし

RewriteRule ^/(.+)\.pl$ http://localhost:8080/index.pl [L,P,QSA]

で 拡張子が .pl のファイルを先ほど設定したバックエンドのサーバに転送し

RewriteRule ^/(.+)\.(gif)$ /var/www/html/$1.$2 [L,QSA]

拡張子が .pl 以外の .gif ファイルはこのリバースプロキシサーバ自体が処理する、という設定になっています。つまり、index.pl 内で使用しているスタティックな画像ファイル httpd_logo_wide.gif はプロキシサーバによって処理されますが、index.pl のファイルは動的にコンテンツを生成するCGIスクリプトなので、バックエンドのアプリケーションサーバにリクエストが転送されます。

ちなみに RewriteRule で使っている L, P, QSA のようなオプションの意味ですが

  • L – このルールが適用されたらそれ以降のルールは実行されない
  • P – プロキシとしてURLの書き換えを行う
  • QSA – URLの?以降のQUERY_STRINGを転送先のURLに常につける

という意味になります。詳しくはmod_rewrite – Apache HTTP Serverに書いてあるので参照してみてください。

動作確認

これで全ての準備が整ったので mod_proxy サーバを起動します。

$ sudo /usr/local/httpd_proxy_2.2.11/bin/apachectl -k start

そしてブラウザから http://example/index.pl にアクセスしてみましょう。Hello world!! のあとにApache のロゴが表示されているでしょうか。表示されていればリバースプロキシサーバの構築は完了ですが、念のため本当にリバースプロキシで動いているのか、アクセスログを見て確認してみましょう。リバースプロキシのログは /usr/local/httpd_proxy_2.2.11/logs/access_log にあります。

192.168.1.54 - - [05/Feb/2009:02:12:43 +0900] "GET /index.pl HTTP/1.1" 200 129
192.168.1.54 - - [05/Feb/2009:02:12:44 +0900] "GET /httpd_logo_wide.gif HTTP/1.1" 200 -

このログには上のような2つのログが出ているはずです。次にバックエンドのサーバのログを見てみます。これは /tmp/access.log にあります。

127.0.0.1 - - [05/Feb/2009:02:12:43 +0900] "GET /index.pl HTTP/1.1" 200 129 "-" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ja-JP-mac; rv:1.9.0.5) Gecko/2008120121 Firefox/3.0.5"

こちらのログには index.plのアクセスのみで httpd_logo_wide.gif へのアクセスはないはずです。これが確認できれば mod_proxy によるリバースプロキシサーバ構築に成功ということになります。ここまで設定できれば、あとは応用で「バックエンドのサーバを2台にして運用する」ということも可能になります。次回はそういう負荷分散も視野にいれたエントリを書きたいと思います。

なお、今回記載した Apache の設定は、簡潔なサンプルであるためセキュリティ的にはよろしくありません。なので、インターネットにつながっているサーバではこの記事の内容を試す場合、動作確認後すみやかに Apache のプロセスを落としておいた方が良いかと思います。

2009/04/06: 後世のためにバックエンドの設定ファイルの名前を /etc/apache2/httpd_backend.conf から /etc/apache2/httpd_backend_8080.conf に変更しました。

Apacheクックブック 第2版 ―Webサーバ管理者のためのレシピ集

著者/訳者:Ken Coar Rich Bowen

出版社:オライリージャパン( 2008-09-26 )

大型本 ( 308 ページ )


カテゴリー: Apache タグ: ,

Apacheでリバースプロキシ(mod_proxy)を活用する(1) – インストール編

2009 年 1 月 29 日 oinume コメントはありません

Apacheはとてもとても有名なWeb Serverですが、今日はそのチューニング方法の一つであるリバースプロキシについて書きたいと思います。

Webサーバの種類

一口にWebサーバと言っても、ダイナミックなWebコンテンツを生成するサイトにおいてWebサーバがserveするものは2種類あります。一つはプログラムで動的に生成されるHTMLファイル。もう一つがGIFやJPEG, PNGなどの画像、および Flash, JavaScript, CSSなどの静的なファイルです。

プログラムで動的にHTMLを生成するためには、そのプログラムを動かす実行環境がWebサーバ(Apache)と連携する必要があります。いわゆるCGIとか最近だとFastCGI, mod_php, mod_perl, mod_rails, mod_pythonなどのスクリプト環境がよく使われています。これらの環境は昨今では「事前に実行環境(インタープリター)の起動をしてプログラムをコンパイルしておきそれを再利用する」というような使われ方をするため、Apacheがクライアントからの要求を処理するために生成する子プロセスのメモリ使用量が肥大化し、プロセスを起動する処理が重くなる傾向にあります。

一方で、単純にファイルの中身をそのままクライアントに渡せばいいようなスタティックなファイルが、このような肥大化したプロセスで処理されることには非常に無駄があります。そこでリバースプロキシの出番です。リバースプロキシの動作は凄くシンプルで、リクエストを受けたら、ダイナミックなページのリクエストのみバックエンドのアプリケーションサーバに渡し、それ以外のスタティックなファイルは自分自身で直接処理します(*1)。図にするとこんな感じでしょうか。

リバースプロキシのイメージ

このような単純な動作なので、リバースプロキシ自体にはmod_perlやmod_phpなどを組み込む必要がなくなり、プロセスのサイズは非常にスリムになります。実際このブログを動かしているマシンでも

  • リバースプロキシのプロセスサイズは3.5MB程度
  • mod_phpのプロセスサイズは25MB程度

となっており、一プロセスあたりで20MBも違います。

さらに、リバースプロキシは動作がシンプルなので、ApacheのMPM(Multi-Proccessing Module)にworkerというものを選択することができます。worker mpmはクライアントからのリクエストを処理するのにプロセスより軽量なスレッドを使用するため(*2)、prefork mpmと比べて動作が軽いという特徴があります。

*1)これは設定自体でどうにでも変更できます
*2)厳密に言うとプロセス+スレッドのハイブリッド方式です

また、フロントエンドのリバースプロキシ+バックエンドのアプリケーションサーバという構成にしておくことで、リバースプロキシは止めずにバックエンドのサーバを増やしたり交換したりすることが可能です。このため負荷分散のためのメンテナンスが非常にやりやすくなります。このあたりはmod_proxy_balancerというモジュールの話になるので今回は割愛しますが、また機会があればということで。

Apache 2.2.11のインストール

前置きが長くなりましたが、リバースプロキシを導入するメリットがわかったところで実際にApacheをインストールしてみたいと思います。環境は Ubuntu 8.10 Interpid です。
まずは最新版である2.2.11のソースを Apache本家 からダウンロードしておきます。

$ tar xvzf httpd-2.2.11.tar.gz
# ちょっとでも最適化する
$ export CFLAGS="-O3"
$ cd httpd-2.2.11
$ ./configure --prefix=/usr/local/httpd_proxy_2.2.11 \
 --with-mpm=worker \
 --enable-shared \
 --enable-so \
 --disable-asis \
 --disable-cgid \
 --disable-proxy-connect \
 --disable-proxy-ftp \
 --disable-proxy-ajp \
 --disable-userdir \
 --disable-actions \
 --enable-modules='rewrite proxy proxy_balancer proxy_http cgi deflate headers expires' \
 --enable-mods-shared='ssl cache disk_cache mem_cache' \
 && make && sudo make install

でインストールが完了です。configureにいろいろとオプションを渡していますが、これらは

  • 確実に使用するモジュールを静的にリンクさせる
  • 不要なモジュールは無効にする
  • 必要になるかもしれないモジュールはDSOとして組み込めるようにしておく

という指定です。/usr/local/httpd_proxy_2.2.11 にApacheのファイル一式がインストールされているので、起動確認を行いましょう。

$ sudo /usr/local/httpd_proxy_2.2.11/bin/apachectl start

でサーバが起動するので、http://localhost/ にアクセスしてみてください。”It works!”と表示されればインストール成功です。次回は具体的なリバースプロキシの設定方法を説明します。

Apache辞典 (DESKTOP REFERENCE)

著者/訳者:松本 光春

出版社:翔泳社( 2004-09-17 )

単行本 ( 463 ページ )


カテゴリー: Apache タグ:

Apacheが出力するServerヘッダを隠す

2009 年 1 月 10 日 oinume コメント 3 件

Apacheでは何も設定しないとデフォルトでレスポンスヘッダーに

Server: Apache

のような情報を残してしまいます。ServerTokens ProductOnly としてもApacheであることは隠せないので、mod_headersを使って

Header unset Server

とするのが正解なのか一応ぐぐってみたところ、ここのような「ソースを修正する」という残念なアドバイスが載っていました。それmod_headersでできるよ!とつっこんであげたかったのですが、解答が締め切られていたのが残念です。

ちなみにPHPは何も設定しないと

X-Powered-By: PHP/5.2.6-2ubuntu4

というようなヘッダーを出してしまうので、これもあわせて

Header unset X-Powered-By

しておきました。php.iniを修正すればいいらしいのですが、Ubuntuだとどこにあるのか調べるのが面倒だったのでApache側で対処。しかしデフォルトの設定っていうのは本当に怖いなぁと思いました。

2009/6/28 追記:Header unset Serverはリバースプロキシの環境でしかunsetできなさそうです。Header set Server hogeのようにして隠すことはできるはずです(未検証ですが)

カテゴリー: Apache タグ: