ページへ戻る

− Links

 印刷 

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

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

ページ内コンテンツ
  • ふとしたキッカケ
  • 設計指針
  • Apache MPMの設定
    • MPMの種類
    • MPMを選択してコンパイルする
    • MPMのチューニング
  • PHPの並列動作について
    • FastCGIをやってみる
    • チューニング
    • PHPのキャッシュ(opcacheとPECL-APCu)を設定する
      • opcache
    • PECL-APCu
      • コンパイル
  • MySQLのチューニング
    • mysqltuner
      • OPTIMIZE TABLE
      • my.cnfの調整
  • 結果

ふとしたキッカケ anchor.png[1]

Apache httpサーバが2.2系から2.4系にアップデートされた事がキッカケでした。せっかくなので、USEフラグを攻めてみようと。そしたらば…MPMという指定がOFFになっていたのです。ヽ(~~~ )ノ ハテ?MPMってなんだろう?

Multi Processing Moduleという名称からも分かるように、mpmとはapacheの並列処理を行うmoduleです。

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

Page Top

設計指針 anchor.png[2]

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

Apache MPMの設定 anchor.png[3]

Page Top

MPMの種類 anchor.png[4]

ApacheのMPMにはいくつか種類があり、必ず実行プロセスについて1つだけを指定します。同時利用はNGです。さて、どんな種類があるか?

prefork
HTTPリクエストに1つのプロセスを割り当てる。つまり、たくさんのリクエストを同時に捌きたい場合には、たくさんプロセスをたちあげておく
worker
HTTPリクエストに1つのスレッドを割り当てる。起動しておくプロセス数、プロセス内のスレッド数は設定によって変更する
itk
preforkと一緒だが、スクリプトを実行するユーザ権限を分けることができる。例えばApacheさんとか、rootさんとか、各ユーザさんとか
perchild
workerと同じ考え方だが、バーチャルホスト毎にプロセス数/実行ユーザを割り当てる
event
workerと同じく、プロセス/スレッドの組み合わせだが、非同期I/O型*1となっており、設定如何では最も高速

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

Page Top

MPMを選択してコンパイルする anchor.png[5]

/etc/portage/make.confに、以下の記載を追加します。ちなみに、今回は攻めるので、event MPMで高速なWebサーバを目指します。

APACHE2_MPMS=event
# emerge apache2
Page Top

MPMのチューニング anchor.png[6]

/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で、同時接続の最大数。同時アクセスの最大数はココでサチるということですね。

Page Top

PHPの並列動作について anchor.png[7]

PHPをマルチスレッドで動作させるのは非推奨だと、PHPホームページに記載されています[8]。やるならFastCGIを使えとのこと。なわけで、FastCGIの設定をしてみます。

Page Top

FastCGIをやってみる anchor.png[9]

さて、FastCGIの設定は、このページ[10]のApache&PHP7.1の部分だけ設定すると、うまくいきますよ~

Page Top

チューニング anchor.png[11]

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つまでにしておくので、使い終わったらプロセスを終了させます。

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

Page Top

PHPのキャッシュ(opcacheとPECL-APCu)を設定する anchor.png[12]

Page Top

opcache anchor.png[13]

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
Page Top

PECL-APCu anchor.png[14]

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

Page Top

コンパイル anchor.png[15]

# 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を再起動してあげます。どうですかね?かなり体感早くなったんじゃありませんか~??

Page Top

MySQLのチューニング anchor.png[16]

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

Page Top

mysqltuner anchor.png[17]

# 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時間以上経ってから出したほうが良いみたいです。運用しながら、何回か実施してみて下さい。

Page Top

OPTIMIZE TABLE anchor.png[18]

テーブルがフラグメントされてるから、最適化しろ、だそうです。こんなコマンドでできます。

# mysqlcheck -u <管理者ユーザ> -p<パスワード> --all-databases --optimize

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

Page Top

my.cnfの調整 anchor.png[19]

指示に従って、/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というネット記事がありましたので、うちではココまでにしております。

Page Top

結果 anchor.png[20]

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


*1 リクエスト受信と応答送信を別のスレッドで処理する方式

Last-modified: 2018-02-21 (水) 22:48:21 (JST) (2227d) by maruo