ページへ戻る

− Links

 印刷 

Gentoo Linuxな生活​/Webサーバ高速化で悩む のソース :: Nest Of Hawk

xpwiki:Gentoo Linuxな生活/Webサーバ高速化で悩むのソース

« Prev[3]  
*ふとしたキッカケ [#we75a40b]
Apache httpサーバが2.2系から2.4系にアップデートされた事がキッカケでした。せっかくなので、USEフラグを攻めてみようと。そしたらば…MPMという指定がOFFになっていたのです。ヽ(~~~ )ノ ハテ?MPMってなんだろう?
 Multi Processing Moduleという名称からも分かるように、mpmとはapacheの並列処理を行うmoduleです。

ほほう、なるほど…並列処理用のモジュールの指定、ということだったのね。せっかくアップデートするのであれば、ピカピカの状態で使用したい、と言うことで、Apache+PHPの実行環境を攻めて行くこととします。

*設計指針 [#i522c57d]
-入力が捌けなくて落ちない様に、奥(PHPやMySQL)は広く、入り口(Apache)を狭く設定しておく
-プロセス/スレッド/キャッシュ数は、なるべく理にかなった方法で

*Apache MPMの設定 [#ob0e20a5]
**MPMの種類 [#r18f8505]
ApacheのMPMにはいくつか種類があり、必ず実行プロセスについて1つだけを指定します。同時利用はNGです。さて、どんな種類があるか?
:prefork|HTTPリクエストに1つのプロセスを割り当てる。つまり、たくさんのリクエストを同時に捌きたい場合には、たくさんプロセスをたちあげておく
:worker|HTTPリクエストに1つのスレッドを割り当てる。起動しておくプロセス数、プロセス内のスレッド数は設定によって変更する
:itk|preforkと一緒だが、スクリプトを実行するユーザ権限を分けることができる。例えばApacheさんとか、rootさんとか、各ユーザさんとか
:perchild|workerと同じ考え方だが、バーチャルホスト毎にプロセス数/実行ユーザを割り当てる
:event|workerと同じく、プロセス/スレッドの組み合わせだが、非同期I/O型((リクエスト受信と応答送信を別のスレッドで処理する方式))となっており、設定如何では最も高速

一般的に使用されるのはprefork/worker。eventは2.2系ではExperimental(実験的)サポート、2.4系では標準推奨のMPMです。ちなみに、preforkよりもworkerの方が動作効率は良いです。何故ならば…プロセスの起動/停止/切り替えはOSにとって重い処理、スレッドの起動/停止/切り替えは軽い処理だからです。よし!それじゃあworkerかeventで決まり!と言いたいところですが、そうはなかなか行きません。スレッドは、メモリ空間を共有するため、きちんと排他処理されていないと誤動作する可能性が高いのです。きちんと処理されている処理系のことを、スレッドセーフな実装と言います。スレッドセーフじゃない処理系を使用する場合は使用するべきではありません。

**MPMを選択してコンパイルする [#v968b11e]
/etc/portage/make.confに、以下の記載を追加します。ちなみに、今回は攻めるので、event MPMで高速なWebサーバを目指します。
 APACHE2_MPMS=event

 # emerge apache2
**MPMのチューニング [#g3659aef]
/etc/apache2/modules.d/00_mpm.confにMPMの動作パラメータが記載されています。これをいろいろいじってやればOK。
:StartServers|最初に起動する子プロセスの数 
:MinSpareThreads|最小の待機スレッド数
:MaxSpareThreads|最大の待機スレッド数
:ThreadsPerChild|子プロセスの中のスレッド数
:MaxRequestWorkers|最大同時接続ワーカー数
:MaxConnectionsPerChild |子プロセスの最大数

だ、そうです。さて、うちではどうして言うかというと-。

 StartServers 4
 MinSpareThreads 25
 MaxSpareThreads 75
 ThreadsPerChild 25
 MaxRequestWorkers 150
 MaxConnectionsPerChild 10000


起動時、StartServers、MinSpareThreadsで待機していますが、同時接続数が増えていくと、ThreadsPerChild数を超えると、MaxRequestWorkersに到達するまで子プロセスを増やします。が、子プロセスのゾンビ化やメモリリークを防ぐために、MaxConnectionsPerChildで上限を決めているのですね。

ポイントは、MaxRequestWorkersで、同時接続の最大数。同時アクセスの最大数はココでサチるということですね。

*PHPの並列動作について [#x23dbc12]
PHPをマルチスレッドで動作させるのは非推奨だと、[[PHPホームページに記載されています>http://www.php.net/manual/ja/faq.installation.php#faq.installation.apache2]]。やるならFastCGIを使えとのこと。なわけで、FastCGIの設定をしてみます。

**FastCGIをやってみる [#ba4fc5cb]
さて、FastCGIの設定は、[[このページ:http://femt.ddo.jp/modules/xpwiki/?Gentoo%20Linux%E3%81%AA%E7%94%9F%E6%B4%BB%2F%E8%A4%87%E6%95%B0%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AEPHP%E5%90%8C%E6%99%82%E8%B5%B7%E5%8B%95%E3%81%A7%E6%82%A9%E3%82%80]]のApache&PHP7.1の部分だけ設定すると、うまくいきますよ~

**チューニング [#za32aded]
 pm = dynamic                     #下記パラメータに従って動作する
 pm.max_children = 100       #最大同時接続数
 pm.start_servers = 4           #最初に起動しておくプロセス数
 pm.min_spare_servers = 1  #待機させておくサーバの最小数
 pm.max_spare_servers = 4 #待機させておくサーバの最大数

さて。pm.max.childrenまで子プロセスを増やします。このプロセス数が、接続数の上限です。先程、Apacheの同時接続数を150にしておきましたので、うちでは2バージョンのPHPを起動しておきますので、2つで最大200まで。Apacheの奥にいるPHPに、余裕を作っておきます。

さらに、start_servers数だけ、最初に起動しておきます。全部埋まらないように、min_spare_serversで、最低限1つ、空きプロセスとして、次のリクエストに備えます。max_spare_serverで、待機しているPHPは4つまでにしておくので、使い終わったらプロセスを終了させます。

というわけで、忙しいときには増え、使い終わるとプロセスを減らすという、賢い動きをしてくれるわけですね♪

**PHPのキャッシュ(opcacheとPECL-APCu)を設定する [#j4b51446]
***opcache [#u827a9a1]
PHP5.5移行、PHPに組み込まれています。opcacheはコードキャッシュで、PHPのプログラムを中間コード化してメモリにキャッシュしておきます。そのため、一度実行されたコードを再度コンパイルしないため、応答速度が改善されます。

/etc/php/XXX-phpX.X/php.iniの以下の項を設定します。
 opcache.enable=1
 opcache.enable_cli=1
 opcache.memory_consumption=128
 opcache.interned_strings_buffer=8
 opcache.max_accelerated_files=10000
 opcache.revalidate_freq=1
 opcache.save_comments=1

**PECL-APCu [#o94d9b71]
PECL-APCuは、データキャッシュで、データの読み込みを高速化してくれます。

***コンパイル [#ob16f023]
 # emerge dev-php/pecl-apcu

さて、インストールされたAPCuを設定いたします。/etc/php/XXX-phpX.X/extの下にある、apcu.iniに、以下の項を追加。
 apc.shm_size=128M
 apc.ttl=86400
 apc.gc_ttl=86400

これで、php-fpmを再起動してあげます。どうですかね?かなり体感早くなったんじゃありませんか~??

*MySQLのチューニング [#i44d3b73]
さて、DBのチューニングってのも、課題になりますよね。そこで、こんな便利ツールがあるそうで。

**mysqltuner [#y25ba22d]
 # emerge mysqltuner

さて、mysqltunerをインストールしましたら、実行してみます。DBの管理ユーザ&パスワード聞かれますので、答えます。うちでは、こんな表示が出てきましたよ。

 General recommendations:
    Run OPTIMIZE TABLE to defragment tables for better performance
    Reduce or eliminate persistent connections to reduce connection usage
    Upgrade MySQL to version 4+ to utilize query caching
    Adjust your join queries to always utilize indexes
    Set thread_cache_size to 4 as a starting value
    Increase table_cache gradually to avoid file descriptor limits
 Variables to adjust:
    max_connections (> 151)
    wait_timeout (< 28800)
    interactive_timeout (< 28800)
    join_buffer_size (> 64.0M, or always use indexes with joins)
    thread_cache_size (start at 4)
    table_cache (> ) 

さて、このmysqltuner、サーバの運用実績から、改善事項を提示してきますので、mysqlを起動してから、24時間以上経ってから出したほうが良いみたいです。運用しながら、何回か実施してみて下さい。

***OPTIMIZE TABLE [#yb23c069]
テーブルがフラグメントされてるから、最適化しろ、だそうです。こんなコマンドでできます。
 # mysqlcheck -u <管理者ユーザ> -p<パスワード> --all-databases --optimize

ちなみに、InnoDBの場合は、最適化ができないので、ALTER TABLEで代用してくれるそうです。ありがたいことだ♪

***my.cnfの調整 [#la2a6cac]
指示に従って、/etc/mysql/my.cnfを変更してあげます。何回かmysqltunerを実行した結果、あれ直せ、これ直せと指示が出ましたので、以下を調整しました。
 join_buffer_size                      =1M
 table_open_cache                      = 8192
 max_connections                       = 150
 wait_timeout                  = 20000
 interactive_timeout           = 20000
 thread_cache_size             = 4
 query_cache_type                = 1
 query_cache_limit               = 16M
 query_cache_size              = 512M
 skip-name-resolve             = 1
 innodb_buffer_pool_instances = 7

調整が済んだら、mysqlを再起動しましょう。

 # /etc/init.d/mysql restart

join_buffer_sizeを大きくしろ、と散々言われます。が、そもそも、インデックス作る方が高速化につながるそうなので、join_bufferをいくら増やしても、アプリ側を変更しないと追いつかない、ということで、増やさなくてもOKというネット記事がありましたので、うちではココまでにしております。

*結果 [#id87c281]
正直、爆速になりました。以前は、正直Wehページが描画される様が目で見て解るぐらいちんたらしていて、まぁ、Webアプリだからこんなもんかな、と半ば諦めていたのですが、2回め以降のページ表示が人間の体感で一瞬で終わります。人の目で見てあきらかに違うので、かなり効果があったと言えるでしょう。超快適♪

« Prev[3]