kazuhoさんが「プロのサーバ管理者の間では存在価値が疑問視されて久しい (Min|Max)SpareServers だと思う」と書いたり、hirose31さんが去年のYAPC::Asiaで{Start,{Min,Max}Spare}Servers,MaxClientsは同じにしているよと発表したり、実際前職のサーバはそのように設定されていたのですが、自分でうまく説明ができてなかったので、調べながら書いてみた。
本当はイントラブログ用に書いていたものですが、がんばったので転載。
前提として、CPUの使用率におけるsystemとfork Re: クラウドがネットワークゲーム開発者にもたらしてくれたもの - blog.nomadscafe.jpでも書いている通りforkってのはサーバにとって重い部類の処理になります。つまり負荷の高いときにforkを大量に行うのはしてはならないことの1つです。
StartServers 60
MinSpareServers 50
MaxSpareServers 100
MaxClients 300
上記のように設定があると、サーバ起動時にまず、StartServersの60個の子プロセスが作られます。子プロセスがリクエストを処理し、MaxRequestsPerChildに達するとその子プロセスは終了します。
子プロセスが終了した際に、親プロセスは次の条件により新規に子プロセスをforkするか決定します。
- IDLEしているプロセスの数がMinSpareServersよりも少なくて、かつ全てのプロセス数がMaxClientsより少なければ新しいプロセスを作成
- IDLEプロセスがMaxSpareServersよりも多ければプロセスを1つKILLする
子プロセスの数は、サーバが暇な時はStartServers(60)からMinSpareServers(50)まで徐々に減っていく(プロセスが死んでも何もしないので)。忙しくなりBusyのプロセスが増えるとIDLEのプロセスがMinSpareServers(50)より少なくなるのでforkする。さらにIDLEがMinSpareServers(50)より少なければBusyとIdleの合計がMaxClients(300)を上限に子プロセスをforkしていく。やがてピークタイムを過ぎ、Busyのプロセスが減りIDLEのプロセスが増える、その数がMaxSpareServers(100)よりも多ければプロセスをKILLする。MaxSpareServers(300)以下になると初期状態と同じく徐々にプロセスが減っていきます。
StartServers、(Min|Max)SpareServers, MaxClientsが同じ値の場合、プロセス数が固定されるので忙しいからといってMinSpareServersを確保するためだけに必要以上にforkを行うことはないし、余ったプロセスがKILLされることもない。IDLEのプロセスがCPUリソースを消費することはほぼないので余計なCPUは使いません。
StartServers 60
MinSpareServers 60
MaxSpareServers 60
MaxClients 60
このような設定がおすすめです
CPUは使わなくてもIDLEのプロセスが多くなると、メモリがもったいないとか思うかもしれないけれど、CoW(Copy On Write)があるのでそこまでメモリは喰わないはずです。それでもメモリを多く使うならプロセスが不足しない範囲でStartServers, (Min|Max)SpareServers, MaxClientsを全て下げればいいと思います。そもそもそんな状態ではピークタイムにSWAPする可能性があります。経験上、MaxClientsは一日の最大のBUSYプロセス数の倍あればいいと思います。CloudForecastやCactiなどを使って利用しているプロセス数をモニタリングするのはもはや必須課題です。
あと、memcachedとアプリケーションサーバが同居している場合、アプリケーションサーバの負荷が高くなって、MaxClientsまでジリジリと上がりメモリ使用量が増えるとmemcachedが確保するメモリもswapしてしまう危険もあります。メモリ使用の上限値を確認しておく上でもStartServers, (Min|Max)SpareServers, MaxClientsを同じにしておいた方がいいですね