Archive for the ‘Apache’ Category.

クエリ発行回数の削減(関連データ一括削除)

MySQLにはJOINで複数レコードをDELETEする機能まであります。

DELETEとFROMの間に削除するテーブル名を指定する事で、両方のテーブルからレコードを1クエリで削除出来ます。

これもクエリ発行回数の削減にはマストと言えるのですが注意点があります。
要はSELECT文と同じなので、全てを1クエリで済まそうとせずに対象レコードに注意して下さい。
親子関係のテーブルを想定します。
親(1)
子1(1)
子2(1)
子3(1)
1:1のテーブルがn件紐付いても1件なので1クエリでやっちゃって下さい。

親(1)
子1(2)
子2(3)
子3(4)
1:nのテーブルがn件紐づくと、2*3*4で24件として展開されます。
孫テーブルがあったりすると、ねずみ算式に増えてしまいます。

1クエリで削除して問題ない単位を考慮できる人じゃないとちょっと怖い事になります。

クエリ発行回数の削減(同一テーブルinsert)

MySQLには標準でバルクインサートという機能があります。
業務系出身の私はMySQLはあまり使いませんでしたので、本格的にソーシャルゲーム開発に携わって初めて知りました。
なんだこのvaluesの羅列は!って感じですねw
高速性を求めるならあって当然の機能と思えるようになりました。

INSERT INTO hoge (hoge_value) VALUES (‘1’),(‘2’),(‘3’);
みたいな感じで同一テーブルに1クエリで複数件登録出来ます。

この機能を利用すれば、フレームワーク側のモデルにinsert予定データをプールする機能を持っていれば、最後に1クエリだけで済みますね。
よくあるソーシャルゲームのシチュエーションで考えると、プレゼントがクエストのクリアやミッション達成で複数件同時に発生する時などに使えますね。
ある時はギルドメンバー全員にプレゼントを送るというシチュエーションが混ざってきても、モデル側でプールする仕組みがあれば全て最後に1クエリで済みます。
さすがにギルドメンバーの人数が多くて1人あたりn件送った結果、例えば10,000件超のプレゼントを一括登録とかになると分割insertも出来る機能も持ちたい所です。
1クエリの実行時間が長いとレプリ遅延を引き起こしますからハードウェアスペックにも左右されますね。
つーか例が大げさすぎてアレですけど、10,000件もプールするとweb(ap)サーバー側がメモリ使いすぎで悲鳴上げるかもしれないですねw

php extensionのススメ2(phalconフレームワーク)

結局phpロジック側で稼げるのは数msの積み重ねなので、諸悪の根源であるフレームワークをネイティブ化すれば最も効率が良いという結論にたどり着きます。
最速PHPフレームワークphalcon
早速インストールしてみました。
phalcon

公式サイトに各フレームワークとの速度比較も乗っています。
ライセンス問題がどうなったのかよく分からないCodeIgniterがPHPフレームワークとしては最速ですが、それと比較しても半分どころじゃない圧倒的ですね!
Hello World Benchmark

ドキュメントも充実していますし、これからこのフレームワークについて勉強してみたいと思います。
ソーシャルゲーム開発ではデファクトスタンダードになっても不思議ではありませんね。
キャッシュもMemcachedとAPCに標準で対応していますね。
https://github.com/phalcon/incubator
これを使えばRedisも対応出来るっぽいですけど、phpクラスになるので悩みどころですね。

VM開発環境におけるApache静的ファイル問題

VMと共有フォルダ開発でJavaScriptエラーになるメモ

VMとWindowsの共有フォルダを利用して開発をするとJavaScriptを編集するとエラーが発生します。
原因は、Apacheの静的ファイル転送オプション設定です。

この設定を追加するだけでOKです。
EnableMMapも合わせて書いているサイトが多いようですが、パラメーターの説明を見ても関係ないですね。
説明にSSI(既に過去の遺物ですね)が書かれているように、Apacheが別のファイルを読み込みするパターン(apache非純正mod_hoge系プログラム内のロードは別物だと思います)ですね。
↑の意味が分からない人は、例えばmod_phpの各種ファイル制御ロジックにApacheの設定を見て動きを変える制御が入っているか?考えて貰えば分かりやすいんじゃないですかね。
NFSで問題があった場合に設定をオフにすれば良いので、EnableSendfileだけでは問題が解決しなければオフにしてみては?って感じでしょうか。

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

さて、思い出した時にサクっと書いちゃいましょう
nginxはfastcgiなので、ローカルにapサーバーを立ち上げてsocket接続しない限りはネットワークを介する事になります
これはメリットであるか否か?でネットワークの話をする予定で放置していました。
まずhttpレイヤーで見ると、このページ見たい→どうぞして!という流れは1アクセスですね
tcpレイヤーで見ると、これは1通信ではなくパケット分割されているという事をまずは理解して下さい。
そして、パケットは道路=LANケーブルを通っていく訳ですが、途中でスイッチを経由します。
よく探偵漫画に出てくる線路の切り替えを想像して貰えば良いのですが、スイッチというハードウェアはポートA,B,C,Dがあったとしたら、
AとB、CとDは同時に接続可能です。
AとB、CとB、DとBという接続は同時に接続できません。
線路の切り替えを同時に線を結ぶなんて出来ないので当たり前ですよね?
つまり目的のサーバーが同じ=Bに向けて同時に接続できないという前提条件がある訳です。
よく同時接続がどうたら言いますが、こういう仕組みを知っていれば本当の同時接続なんてのは物理的に無いっつーのは常識ですね。
同時に処理するけど時間差がある同時接続というのが正しい?表現でしょうか?w
パケットの渋滞が出来る可能性もある訳ですから、単純にサーバーを分ければ負荷分散出来るっつー話ではないという事です。
APサーバーなんて物が本当に必要か?を十分考慮した上で検討したい物ですので、nginxが有利とは言えない点です。
個人的には、そもそもロードバランサーで負荷分散してるのにweb=apサーバーで何が困るのか?
足りないならweb=apを足せよ!としか思わないんですが、まぁ正解なんてないですからねw
web != apだと管理が煩雑になるのとネットワークを介するのがデメリットで、それに見合うメリットが特に無さそうって事ですね。
nginxを使うにしてもローカルにfcgiを立てれば良いんですが、管理が煩雑な点は解消出来ませんからねぇ。

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

あまり放置するのも何だと思ってFF14のログイン待ち時間に書こうと思ったら今日は一発でログインできたでござるの巻

ネットワークの話に移ろうかと思っていたのだが、時間が空いたのと他のサイトで書かれている事で気になった点を簡単に書こうかと。

ブロッキングとノンブロッキングの話ですが、私が前回書いたセマフォの観点でいう「ここは同時処理しちゃ駄目ブロック」と違う観点で捉えている人もいるようです。
webの同期通信と非同期通信のブロッキングとノンブロッキングで捉えているようですが、これは違うんじゃないでしょうかねぇ?
マルチスレッドプログラミングをした事がある人は分かりますが、スレッド=関数です。
windowsもlinuxもスレッド生成APIは関数を別スレッドとして動かすものです。
別スレッドとして動かした処理が終わるまで待つのがブロッキング!!
え?それってスレッドじゃなくて普通に関数呼ぶでしょ?

という事で、大なり小なりの差はあれどnginxもapacheも私の書いていたブロッキングは発生するハズですね。
例えばログを書くとしたら、ファイル管理はOSの機能です。
OSの機能としてファイルロックが提供されていますので、書き込みの為にロックする=ブロッキングが発生します。
まぁこういう部分は置いといて、スタックメモリを使う部分を考慮しながら作られてるからnginxはブロッキングが少ないと言われてるんでしょう。
ソースを見た訳じゃないので事実かは知らんけど。

では新生エオルゼアへ旅立とうノシ

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問題は無いんですかね?

GETメソッドは危険という都市伝説

よく盲目的にGETメソッドは危険だからPOSTメソッドをすべきだと教育されたりするだろう?
これは間違いでは無いが間違いである。

GETメソッドが危険というそもそもの意味を知っている人間自体がいないのだ。
今となってはググっても出てこなくなってしまっているので、IT業界の生き字引な私が記憶を掘り起こして書き記そう。
対象バージョンがapache0.8未満だったと記憶している。
getパラメータに確か1000バイト超だったと記憶している。
要するにgetパラメータのバッファオーバーフローがあり、コマンドを記述するとやりたい放題という致命的すぎるバグがあったのですよ。
これがそもそものGETパラメーターは危険と言われていた話であり、この時代からインターネット関係の作業や勉強をしていた人間は少数の為あまり知られていない。

現在では、ブラウザのアドレスバーに記憶されるからIDやパスワード等を入力させると危険という別の意味での危険性を問われています。
これはこれで正しい話ですのでGETメソッドのデメリットと言えます。
後は、簡単に値を変更出来てしまうと言う事もデメリットとしてありますね?

ではGETメソッドのメリットはあるでしょうか?
例えばGETメソッドの場合はアクセスログにクエリーパラメーターも一緒に記録されるので、後からバッチで解析する事が可能です。
簡単にパタメータ値を変更出来るのはデメリットでもありますが、メリットでもあります。
urlを引用して転載して貰えるなどもメリットでしょう?
用途次第では当然GETメソッドを利用するメリットはあるのです。