Hatena::ブログ(Diary)

新卒インフラエンジニア2年目 このページをアンテナに追加 RSSフィード Twitter

2010-11-29 さくらVPSで一日6万PVを処理するためにしたこと

さくらVPSで一日6万PVを処理するためにしたこと

さくらVPSで6万PV程度のサイトを運用することになったので、その際の記録を残しておきます。


さくらレンタルサーバさくらVPS

さくらレンタルサーバで運用している時は、ちょくちょく503が発生しておりこれを解決するためにさくらVPSへの移行を行いました。


レンタルサーバの時は、ログ解析や監視ツールなどを導入していなかったので503の頻度やパターンは不明です。(安易な判断でVPSに移行したので、この点は反省です)


本来は原因を追及し、プログラムの改修やサーバ負荷の分散などをすべきですが時間の都合で省いてしまいました。


構成

運用するサイトはpukiwikiで構成されたサイトです。


pukiwikiは、PHPで書かれており大量のデータをRDBを利用せずに構築できる点が大きなメリットです。


今回は1サイトですが、複数のサイトを運用する可能性を考慮してVirtualHostも利用します。


さくらVPSの性能
  1. OS:CentOS
  2. CPU:XeonQuadを共有利用(2コア)
  3. メモリ:512M

Apacheインストール

CentOSにはyumがあるのですが、不要なモジュールやパッケージをインストールを避け最新版のApcheを利用したかたったのでソースからインストールしました。

Apacheの最新版

configure

pukiwikiに関わらず基本的なサイトであれば以下のオプションで動作するはずです。

"./configure" \

"--enable-so" \

"--enable-rewrite" \

"--enable-expires" \

"--disable-proxy" \

"--disable-deflate" \

"--disable-cache" \

"--disable-disk-cache" \

"--disable-auth-basic" \

"--disable-authn-file" \

"--disable-authn-default" \

"--disable-authz-groupfile" \

"--disable-authz-user" \

"--disable-filter" \

"--disable-autoindex" \

"--disable-negotiation" \

"--disable-actions" \

"--disable-asis" \

"--disable-cgi" \

"--disable-env" \

"--disable-include" \

"--disable-userdir" \

"--disable-imap" \

"--disable-cgid" \

"--disable-charset-lite" \

"--disable-imagemap" \

"--disable-setenvif" \

httpd.conf

次の設定ファイルのみ有効にします。

#プロセススレッドをコントロールするための設定

Include conf/extra/httpd-mpm.conf

#バーチャルホストの設定

Include conf/extra/httpd-vhosts.conf

#Apacheの基本的な設定セキュリティ設定

Include conf/extra/httpd-default.conf


httpd-mpm.conf

mpm_prefork_moduleのみに注目してください。

mpm_worker_moduleはマルチスレッド対応のmpmですが不安定な一面があるのでpreforkに移行しました。



StartServers 10 # Apache起動時に起動するプロセス

MinSpareServers 50 #最低待機プロセス

MaxSpareServers 70 #最大待機プロセス

MaxClients 110 #最大起動するプロセス数(これ以上はプロセスを起動しない)

MaxRequestsPerChild 1000

MaxMemFree 2048


MaxRequestsPerChildとMaxMemFreeについては後ほど説明したいと思います。



Apacheは起動するとデフォルトで5個ぐらいのプロセスを起動するのですが6万PVを処理するには平均で70プロセス程度、ピーク時で100プロセス程度起動します。


1プロセス1リクエストを処理した後にプロセスが終了するので、5⇔70プロセスの起動と終了を何度も繰り返すので非常にオーバーヘッドが大きくなってしまいます。


Apacheプロセス起動と終了に生じるオーバーヘッドを下げるためにmpmで予めプロセスを起動しておきます。

それがStartServers、MinSpareServers、MaxSpareServersの設定になります。


<IfModule mpm_prefork_module>

StartServers 10

MinSpareServers 50

MaxSpareServers 70

MaxClients 110

MaxRequestsPerChild 1000

MaxMemFree 2048

</IfModule>


httpd-default.conf

KeepAliveは諸刃の刃なので、ONにするときはよく検証しましょう。

できるかぎりサーバの情報は伏せておきたいので情報表示はOffにします。

Timeout 300

KeepAlive Off

MaxKeepAliveRequests 100

KeepAliveTimeout 5

UseCanonicalName Off

AccessFileName .htaccess

ServerTokens Prod

ServerSignature Off

HostnameLookups Off

TraceEnable Off


PHPインストール

PHPもソースからインストールします。

バージョン:5.2.14

PHPダウンロード

PHPも同様に必要最低限の機能のみインストールします。

configure

'./configure' \

'--with-apxs2=/usr/local/apache2/bin/apxs' \

'--enable-zend-multibyte' \

'--with-zlib' \

'--with-xmlrpc' \

'--with-gd' \

'--with-jpeg-dir=/usr/local' \

'--with-png-dir=/usr/local' \

'--enable-mbstring' \


cp php.ini-recommended /usr/local/lib/php.ini


zlibがないとエラーがでますが、zlibなどはyumからインストールしていただいて結構です。

やっておくと便利

ln -s /usr/local/lib/php.ini /etc/

ln -s /usr/local/lib/php/extensions/no-debug-non-zts-20060613/ ./extensions



サーバ停止

上記の設定後、3日にロードアベレージが60程度まで上昇しサーバが停止しました。


サーバ停止の原因を探るため、topを見たところ一部のApacheプロセスがメモリを30%程度占有していることが判明しました。


同時にSWAPもどんどん増え、メモリ不足に陥りサーバが停止している事がわかりました。


PHPのメモリを制限する

php.iniのmemory_limit = 128M と恐ろしいことになっていたのでApacheが平均的に使用しているメモリ+αのサイズを設定しました。


memory_limit = 128M ⇒ memory_limit = 16M


APCを入れてみる

PHPの中間キャッシュを行うAPCを導入しました。


その結果、極端にメモリを消費するPHPファイルを除き高速に処理されるようになりました。


約、2倍ぐらい処理速度が向上しました。


導入後、キャッシュ利用サイズが7M程度なのでAPCに8Mのメモリを割り当てる設定にしました。

php.iniの変更

追記

extension=apc.so

追記後、Apache再起動してください。

副作用

PHPが利用できるメモリを制限したところ、予想通りですが“Fatal error: Allowed memory size”のエラーが一部のPHPファイルで発生しているのが確認できました。


問題のファイル名を調べてみると、Wiki内にテーブルや内部リンクが多くある場合メモリリークが発生しやすいようです。


この副作用で、どのプログラムが問題を起こしているのかを発見することができました。


このプログラムに関しては、Pukiwikiに情報がありメモリリークを軽減させるパッチがあったので適用させることで、比較的テーブルや内部リンクが多いページでもメモリリークが発生することはなくなりました。


Apacheのメモリを制限する

PHP側のメモリリークはなくなったものの、Wikiのテーブルや内部リンクの多いページにアクセスされ続けるとApacheがどんどんメモリを利用して解放しない現象が発生しました。


メモリ利用と解放の動き

Apacheがメモリ要求

OS→lib→Apache


Apcheのメモリ使用終了

OS lib←Apache


OSがメモリを要求 Apacheがメモリ解放

OS←lib Apache



このような動作をしているようでOSがメモリを要求しない限りlib(メインメモリーアロケータ)がメモリを解放しないので、OSがメモリを要求してこない限りApacheが使用するメモリはどんどん増えていきます。


物理メモリに余裕があれば殆どの場合問題にはなりにくい問題なのですが512MしかないのでOSのメモリ要求とApacheのメモリ要求で使い果たしてしまうようです。


ApacheにはMaxMemFreeという機能があります。


MaxMemFree ディレクティブは free() が呼ばれない限り、 主アロケータが保持できる空のメモリの最大値をキロバイト単位で設定します。 設定されていないか、零に設定されているときは、無制限になります。


なんとも難解な日本語で書かれているのですが、つまりlib(メインアロケータ)が保持できるメモリを制限し設定値以上のメモリはlib(メインアロケータ)はOSに返すのでApacheがメモリを食い続けるという現象がなくなりロードアベレージがかなり下がりました。


メモリ使用量は多いがCPU使用量は低いプロセスが多くあったので、定期的にプロセスのメモリを解放することにしました。


MaxRequestsPerChild 0 ⇒ MaxRequestsPerChild 5000


MaxRequestsPerChildは、プロセスが最大処理できるリクエスト数を設定するための物です。


設定値以上のリクエストを処理するとプロセス再起動させるので、効率よく負荷の高いプロセスにメモリを割り振ることが可能です。



結果

平均ロードアベレージ:1.07

平均CPU使用率:22.1%

ブラウザがページを表示するまでの平均時間:0.87

平均未使用メモリ:42M

SWAP:30K

HTTP 503発生回数:0回


このような感じで現在も安定して動作しています。

WikiRDBを利用しないためメモリ使用量が抑えられましたが、MySQLを利用する場合は13%〜17%程度メモリ使用量が増加するのでmpmの設定でプロセス数を減らしメモリをどこかで浮かせる必要があります。

SWAP

SWAPが少し発生していたので、vmstatを見ていたところSWAPインが1日数十回発生するだけでSWAPアウトが発生していないのでメモリに置いていても利用頻度の低いデータはSWAPに移動されるのでそれが原因だと思われます。


監視

レンタルサーバでは、ログ解析や障害検知を行えていなかったのでZabbixとVISITORS Web Log Analyzerを導入しました。

Zabbixサーバは別のサーバに導入し、クライアントのみをインストールしています。


投稿したコメントは管理者が承認するまで公開されません。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/koujirou6218/20101129/1297320407