Archive for 8月 2013

nginxとapacheはどちらを使うべきか?3

今までは元々C10K問題の走りとなったapache1で敢えて説明をしてきました。
apache2だとまた事情が変わるという件について今日は論じたいと思います。
MPMという機能が搭載されていますので、実は1プロセス中のスレッド管理というのが出来ます。
そして2.4からはイベントというnginxと同じ考え方のアプローチも提供しています。
apache1:fork
 新しいプロセスを都度立ち上げます
apache2:pre-fork
 プロセス管理ですが、nginxが最初にマスタ+n件のプロセスを立ち上げるのと同じで事前にプロセスを立ち上げるのでプロセス起動のオーバーヘッドを削減します。
apache2:worker
 1プロセス中でn件の通信をスレッド管理しますので、プロセス数消費の問題はこの設定で無くなります。
apache2:event
 nginxのイベント管理手法と同じアプローチで、1プロセス中でスレッド管理します。

元々Linuxカーネルにはスレッド管理という概念が無かったのでマルチプロセスのアプローチをしていたapacheですが、今ではマルチスレッドも実装しています。
workerのスレッドとイベントのスレッドは何が違うのか?
FastCGIで考えてみます。
ブラウザ:これ見たい>マスタープロセス:お前が相手しろ>スレッド:APサーバーと通信>APサーバー:結果どぞ>スレッド:結果どぞ>ブラウザ
お前が相手しろ以降の一連の処理単位がスレッドとして実行されるんだと思います。

次にeventですが、もっと細かい単位でスレッド分割されてるんだと思います。
TCPパケットの説明までするのは面倒なので単純に通信すると結果を得るまでに待ち時間があるのを想像して下さい。
APサーバーと通信するリスナースレッド
結果を処理するスレッド
ブラウザに結果を返すリスナースレッド

マルチスレッドプログラミングでは、同じプログラムが同時に動くので同一メモリにアクセスするプログラミングなどはご法度です。
ブロックする必要すらないのが理想的ですが、どうしてもそういう必要があるならセマフォという概念でブロックする必要があります。
前者も後者もスレッドセーフと呼ばれますが、前者をノンブロッキング、後者をブロッキングと言います。
せっかくマルチコアなら同時処理が可能な仕組みですが、ブロッキングだと処理を待つ必要があります。
nginxはノンブロッキングで作られており、apacheはブロッキングの部分があるそうです。
こればかりは、ソースを見た訳じゃないので噂を信用するしか無さ気ですね。

nginxとapacheはどちらを使うべきか?2

昨今のハードウェア事情として、仮想サーバーを利用するというシチュエーションが増えています。
VT(バーチャライゼーション・テクノロジー)によりCPUによる仮想化機能の提供で、昔のフルエミュレートの仮想PCと比べると随分マシになったみたいです。
仮想化技術により実装は異なりますが、大抵さくらVPSでお世話になってるKVM+QUEMの構成なんじゃないですかね?
その前提で昨日の話のおさらいをしましょう。
KVMはKernel Based Virtual Machineという名前のようにLinux Kernelに組み込まれた仮想化機能です。
ホストOSのコア機能として実装されてる仮想化技術ですので、VMはホストから見れば1プロセスにすぎません。
昨日の話だとプロセス単位にCPUリソースを割り当てるのがOSの機能でした。
じゃあCPUリソースが割り当てられたタイミングで初めて動く単なるエミュレータかよ?
と思っちゃいそうですが、違う技術だからカーネルベースとか偉そうに名乗ってるんですね。
私が使ってるさくらVPSだと2コアなんですが、これは2コアの仮想CPUです。
便宜上VCPU1とVCPU2という名前にします。
VCPU1は物理CPUの1番コア、VCPU2は物理CPUの2番コアという形で割り当てるので、ホストOSの基本機能のタスク管理の時点で仮想OSを意識したリソース割り当てが実施されます。
VMは物理サーバーと比べてオモチャなのは事実ですが、技術の進歩でそこそこ使えるオモチャになってるのは間違いない訳です。

で、nginxとapacheの話に戻りますが、CPUリソースを消費させようにもapacheとnginxではアプローチが違います。
CPUリソースを消費する(APサーバーを使わずにwebサーバー自身に動的処理をさせる)方法がnginxでは提供されていません。
cgiからmod_hoge系まで何でも対応しているapacheとFastCGIのみのnginx
CPU負荷がかかったケースを作ってベンチマークでも取ろうかと思っても、FastCGI(APサーバー)だと根本的に話が変わるので比較自体がナンセンス
あくまでCPU負荷が焦点なので静的HTMLのベンチマークなんて論外ですw
実はここがnginxを使う必要がない一番の理由だったので後日整理したいと思います。

VMだとCPUリソースもメモリも分割されてしまうのでスレッド駆動の方がマシに思える可能性はありますね。
ただ話の前提条件が同時10000アクセスでしたからねw
その状況でVMなんて使うなよって話になった上で、貧乏人はnginxでも使ってろって感じになるのかも。

nginxとapacheはどちらを使うべきか?

C10K問題で台頭してきたnginxだがapacheの代わりに使うか?
そもそもC10Kの10000クライアントを1webサーバーで処理するという前提の時点でナンセンスな話だと鼻で笑い飛ばしたい話なんですがw
ただし、C10K問題が話題に上がった当時と今とではハードウェアの性能が違うので、2013年現在で考えるならという前提での話だと言うのを勘違いしてはいけない。

C10K問題の話を簡単にすると
apacheはマスタープロセス→ワーカープロセスを新規で立ち上げ処理を任せる。
・プロセス毎にスタックメモリを消費する
・32bitOSのプロセス番号がパンクする
という問題から同時接続数が多くなるとOS死んじゃうね
これに対して、nginxだとマスタープロセス→ワーカープロセス内でイベントドリブン
1プロセス中でマルチスレッドしちゃうからapacheの抱える問題はないよ

上のような話を踏まえた上で、今現在の事情で考えてみましょう。
プロセス番号の問題は64bitOSで回避出来るので何ら問題は無くなっていますので論外です。
スタックメモリの問題は相変わらず重要ですが、搭載メモリ量は増えていく一方なのと最初に書いたように10000も同時接続させないですw
あとapache2系からMPMが提供されスレッド管理可能な上に2.4系からnginxと同じイベント駆動も実装されました。
が、MPMの話は置いといて、あえてここではapache1系のpre-forkですらないfork起動を前提に考えていく事にしましょう。

まずnginxのマルチスレッドですが、タスク管理はそもそもOSの役割です。
windowsであればOSがイベント(メッセージ)を管理するのですが、Linuxはそんな機能はないのでアプリとしてイベントを実装しないといけないんじゃ?
コンピューターの動作原理は昔の1CPU1コアの時代のマルチタスクで考えればOKです。
脳みそは1つなので同時に考えれる=処理出来るのは本当は1つですが、CPUのアイドルタイム(空時間)をうまい具合に各プロセスに割り当てる。
CPUリソースの割り当て=タスク管理をプロセス内で複数の処理(イベント)を管理しようというアプローチです。
古いLinuxカーネルはスレッド自体サポートしていませんでした。
(多分)2.4系の場合は、スレッドという単位にはCPUリソースは割り当てられません。
(多分)2.6以降であれば、ライトウェイトプロセスの採用によりスレッドは擬似プロセスとして扱われます。
これに対してapacheはプロセス管理ですので、OSがCPUリソースをプロセスに割り当てたタイミングでその処理に専念して処理します。
OSがCPUリソースを割り当てるタスクの単位はプロセスだと言う前提の説明がここまで。

最近は複数コアのCPUが当たり前になってしまったというハードウェア事情があり、困った事に本当にパラレルでプログラムが動いてしまいます。
まずapacheとnginx双方でマスタープロセスという物を書きましたが、こいつがport80で無限ループ待ち受けしてる本体ですね。
apacheの場合はワーカープロセスを立ち上げ、この子の相手は君がしてね!とプロセス移譲(fork)するのでCPUリソースはOSのタスク管理機能に任せてフルに活かせます。
次にnginxの場合は、ワーカープロセスが1つだと仮定するとCPUコアが8つでも古いカーネルでは1コアで処理してしまうのでCPU性能を活かせない事がありました。
ここでの話題は今現在のハードウェア事情で考えるですがら、LWPが前提となりワーカープロセスが1でもスレッドにCPUリソースが割り当てられるのでこれも問題ありません。

メモリ消費の点でnginxが有利に思われますが、問題点とされるプロセス毎にスタックやヒープが消費されるという話があります。
スレッドの場合はプロセスに割り当てられたスタックメモリを共有するのでスレッド数に注意する必要があります。
スタックメモリはOS等が勝手に割り当てるメモリなので、いくら必要か分からない部分ですからスレッド管理だとパンクするのが怖いです。
windows9X時代にやたらとスタックメモリーのエラーでDrワトソンが出てきたのは懐かしい思い出でしょうか?
今現在のハードウェア事情では搭載出来るメモリもどんどん増えていきます。
プロセス毎にスタックを消費するのと、プロセス内でスレッド数をいくらに制限すれば良いのか不透明な運用。
どちらに重きを置くかで考え方が変わる部分では無いでしょうか?

ただ、ここで不思議になってくるのは、ロードバランサーやL3スイッチなどのwebサーバーよりも上位のハードウェアです。
まずL3スイッチは機種にもよるんでしょうけど、中にlinux入ってますよね?
ロードバランサーは私は設定した事が無いので知らないですけどlinuxベース臭いですよね?
webサーバーは複数台に分けても、分散するまでの経路上のハードウェア達ってC10K問題は無いんですかね?