改訂版 新卒ネットワークエンジニア

IT企業で働く残業しないゆるふわ系ネットワークエンジニアのBlog

クックパッドに入社した話をしよう

without comments

Hatena Bookmark for this entryHatena Bookmark - クックパッドに入社した話をしよう

入社して3ヶ月ぐらい経ちました。

前職と同様にインフラとしてサービスを支えるお仕事をしています。地味かもしれませんが僕はインフラが大好きです。

こう言えるようになったのもクックパッドのおかげかもしれません。

クックパッドは「やりたい」「得意」「すべき」という3つの輪が重なるところが最も個人の能力が発揮され成果が出ると信じています。

僕は入社前からこれまで培ってきた技術と経験をインフラとしてシステムの安定化という課題に取り組むつもりでいたので、「やりたい」「得意」は見つけることができた。

でも、本当にこれを「すべき」なのか?という疑問は今でも持ち続けています。

システムの安定化はサービスの品質に関わることなのでやるべきことなのですが、プログラムをガリガリ書いたほうが多分もっとユーザの役にもたてるし会社としてのメリットも大きい事があると思うんですよね。

クックパッドはまだまだ小さい会社で、これからどんどん大きくなっていくと思いますしそれが社会からみた会社の意義でもあると思います。

クックパッドのインフラだからプログラムは書けないっていう話しではないです。僕の両サイドに座っている方々はインフラでプログラムを書きまくっています。

インフラというチームはただその中心的な役割であってアプローチはなんでもいいじゃなでしょうか。彼らはプログラムが得意なんですから。

クックパッドの本質は「毎日の料理を楽しみにすることで心からの笑顔を増やす」じゃないでしょうか。

僕の得意はネットワークやLinuxシステムの知識や経験を活かしたシステムを開発することです。

得意を活かしてシステムを安定化させればユーザにとってもメリットだし、僕にとっても最大限のパフォーマンスを出せるフィールドだと確信しています。

「耐障害性を向上させいつでもユーザに見てもらえるクックパッドにする」 これは僕が入社してからずっと思ってきてることですが、自分の本当にやりたいこと、得意なこと、やるべきことに邁進できる最高の環境です。

クックパッドは周りを見渡せば世界でも有名なスーパーヒーローのような方々がたくさんいてその道の超エキスパート集団が揃っています。

ここが僕は結構ミソだと思っていて普通の会社やベンチャーだ幅広くなんでも出来る人を求めるじゃないですか。その逆なんですよね。

エキスパート集団が周りにいて、そいう空気だから何も疑問を抱かずに今の仕事を続けれてるんだと思います。

そいう集団の中にいると自分の小ささを目の当たりにして不安になることもよくあります。

そのたびにもっと勉強して進んでいかないとって思える環境が一番エンジニアとして成長できると思っています。まだまだ努力が足らないんだなと感じますしね。

ストイックで冷静に成功までのプロセスをたてて、時にはがむしゃらに頑張れる人が多いと思います。

優秀な人を見つけたり「人」に通ずる環境をよくしようと一番努力しているのは人事とかなので社員の事を本当によく考えていてくれてありがたいです。

会社体制の話しです。

前職はトップダウンでしたがクックパッドではボトムアップで個々が意思決定である事が求められます。

トップダウンで何もしなくても指示される環境に慣れてしまっていた僕には全てにおいて最初の一歩が恐怖でした。

全ての意志と行動が自分の責任となって返ってくるわけですから当然だと思います。

クックパッドには優秀な人が揃っています。悩んで自分の意見をまとめて相談すれば誰でも話を聞いてくれます。

しかし最終的な決定者は自分自身であるべきだと思っています。

最後に。

クックパッドは本当にいい会社です。

企業理念と言えば堅苦しくなりますが会社としての考え方、ユーザに対する思いや、僕達のTOPはユーザであるという精神が社員一人ひとりに浸透していると思います。

テクノロジーは使って喜んでくれる人がいるから遣う意味があるんだと思うんですよね。

今以上の物を作るためにあらゆるテクノロジーを使いこなし努力を惜しまない集団です。

こいう事に共感できて料理を通じて世界を変えたい、人を楽しませたいと心から思うのであればクックパッドは向いているかもしれません。

クックパッド 採用

Written by koujirou

May 1st, 2012 at 10:01 pm

Posted in おもうたこと

回線遅延やパケットロスをシュミレートする方法

without comments

Hatena Bookmark for this entryHatena Bookmark - 回線遅延やパケットロスをシュミレートする方法

回線遅延(帯域)を考慮しない負荷試験なんて意味あるの?って思い使ってみました。
負荷試験はLAN内で行う事が殆どだと思いますが実際はインターネット経由でユーザからのアクセスがあり、それぞれ回線速度もバラバラのはずです。

この回線速度の違いはシステムにどのような影響を与えるかというと1アクセスに対して1プロセスが長時間専有されることでシステムリソースを消費するということです。

これらを考慮せずに安易にKeepAliveを有効にしてWebサーバを高速化しよう!なんてしてしまうと高負荷になり返ってレスポンスが遅くなったという人も多いと思います。

Linux2.6系(だったはず)からiproute2などが組み込まれてネットワーク系が強化されました。
その一部としてtc(Traffic Control)コマンドがあります。

tcコマンドでできること

・回線遅延
・パケットロス
・パケット入れ替え
・パケットの破損
・etc…

このコマンドはそのサーバに対して適応されるので、遅延速度を大きくしすぎるとSSHがタイムアウトすることもあるので注意してください。
複数NICがある環境が望ましいです。

eth0を100ms遅延させる場合

#tc qdisc add dev eth0 root netem delay 100ms
//Delete Command
#tc qdisc del dev eth0 root netem delay 100ms

qdisc=>’queueing discipline’
kernelがNICから送信する必要がある場合、一旦qdiscに格納されkernelはqdiscからNICドライバーへと引き渡そうとします。
その順番はキューに入った順に引き渡され、NICはできるだけ速くキューを送信しようとします。
それを操作して送信を遅延させてやろうというコマンドです。

別の端末からCurlを実行してみます。
通常の速度は9000msぐらいです。

# curl -o /dev/null -w time_total 10.0.60.24
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     9    0     9    0     0   2572      0 --:--:-- --:--:-- --:--:--  9000

tcコマンドを実行すると。
綺麗に100ms遅延した結果が得られました。

# curl -o /dev/null -w time_total 10.0.60.24
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     9    0     9    0     0     44      0 --:--:-- --:--:-- --:--:--    90

遅延をランダムにさせることもできます。100ms〜10msの遅延。

# tc qdisc add dev eth0 root netem delay 100ms 10ms

パケットロスはランダムにパケットをロスさせることができる。
このランダムというところが厄介なのでNICが1つしかない場合はSSHのパケットとHTTPのパケットが混ざってしまい正確な値の計測が難しい。
NICが1つの場合はlossの確率を10%程度まで上げても殆ど変化がみられないと思う。
NICが2つあり、殆どパケットがながれていない場合1%以下から検証することを勧める。

#  tc qdisc del dev eth0 root netem loss 0.00003%

delayと組み合わせて使うこともできます。

# tc qdisc add dev eth0 root netem delay 100ms 10ms loss 0.00003%

パケットの破損はパケットの1bitを破壊する事ができる。TCPの場合は輻輳の機能があるので観測しづらいのでPingで試すのが吉。

# tc qdisc del dev eth0 root netem corrupt 10%

tcpdumpを実行しながらPingを打つとwrong data byteが発生して一定の確率で破損しているのが伺える。

# tcpdump -n -p icmp &
# ping 10.0.60.24
PING 10.0.60.24 (10.0.60.24) 56(84) bytes of data.
20:59:15.942681 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 1, length 64
20:59:15.943743 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 1, length 64
64 bytes from 10.0.60.24: icmp_seq=1 ttl=64 time=2.05 ms
20:59:16.942993 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 2, length 64
20:59:16.943303 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 2, length 64
64 bytes from 10.0.60.24: icmp_seq=2 ttl=64 time=0.342 ms
20:59:17.943496 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 3, length 64
20:59:17.943813 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 3, length 64
64 bytes from 10.0.60.24: icmp_seq=3 ttl=64 time=0.347 ms
20:59:18.943501 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 4, length 64
20:59:18.943841 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 4, length 64
64 bytes from 10.0.60.24: icmp_seq=4 ttl=64 time=0.372 ms
20:59:19.943514 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 5, length 64
20:59:19.943854 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 5, length 64
64 bytes from 10.0.60.24: icmp_seq=5 ttl=64 time=0.372 ms
20:59:20.943554 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 6, length 64
20:59:20.943952 IP 10.0.60.24 > 10.0.74.150: ICMP echo reply, id 47365, seq 6, length 64
64 bytes from 10.0.60.24: icmp_seq=6 ttl=64 time=0.431 ms
wrong data byte #45 should be 0x2d but was 0xd
#16	10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c d 2e 2f
#48	30 31 32 33 34 35 36 37
20:59:21.943526 IP 10.0.74.150 > 10.0.60.24: ICMP echo request, id 47365, seq 7, length 64

Written by koujirou

April 26th, 2012 at 9:17 pm

Posted in サーバ,小技

NHKにお金を払うこと。Webコンテンツにお金を払うこと。

without comments

Hatena Bookmark for this entryHatena Bookmark - NHKにお金を払うこと。Webコンテンツにお金を払うこと。

就職して一人暮らしを始めてから真面目に?NHKの料金を払い続けてるのですが去年9月の引越しから引き落としがうまく行かず振込用紙で支払っていました。

3ヶ月ぐらい前からでしょうか、色々と忙しくなり支払うのを忘れて毎月NHKの集金係の人に料金を支払っています。

NHKへの支払うんぬんは置いておき、お金を支払うという事はその対価として何かを得るという事は幼い子供でも知っていることだと思います。
殆どの人はその対価として自身が等価またはそれ以上の価値があると思うからお金を支払うと思うんですよね。

NHKの問題点はいくつかあると思いますが、TVを通じて彼らはコンテンツを配信していますがそのコンテンツに対する対価と見合わないから払わない人、お金の使途が気に入らない人、色々いると思います。
おそらくニュースなどで取り上げられる一部の不真面目人を除いて、NHKの中の人はその対価と見合ったコンテンツを配信するために必死になっていると信じているのですが、その努力が少なくとも僕の目には見えないし、成果もでていないんじゃないかと思っています。

僕はNHKと同様にユーザから金を頂いてサービスを展開している企業に勤めています。
インフラでシステムの安定化という事に取り組んでいるので直接ユーザに触れるようなサービスを開発しているわけではないですが、どうやってシングルポイントを無くすのか、いかにしてダウンタイムを短くするかという事を常に考えて行動してます。

実際にピークタイムになるとサーバの負荷が高くなりユーザのアクセスも相当なものになっていることを実感し、その中にはお金を払って使ってくれているユーザもたくさんいます。
Webサイトだとバーチャルな繋がりでしか無いものが目に見えて負荷が高くなったりログがたくさんでてたりとかで人がいるってよく実感するんですよね。
そいうのを想像するとシステムは絶対落とせないし、ユーザに申し訳ないって気持ちが凄く強くなって、そのためにより高度のテクノロジーを使う必要があったり、そして自分自身成長する必要があるって考えると凄くプレッシャーの掛かる仕事なんですが自分自身の成長が実感できるし、なにより何気なく使ってくれてるユーザ人がいると凄く嬉しんですよね。
当たり前のように使えるサービスを作ることは本当に大変な事なんだけど、そのバックグラウンドの努力って中の人じゃないと見えないんですよ。これはエンジニアだけではなくて、僕達を支えてくれている総務だったり人事だったりも同じなんです。

だから、NHKも実はバックグラウンドで凄く努力をしているのかもしれないんですよ。それを僕は信じてお金を払ってます。
ただユーザが僕達を信じてお金を払ってくれているということを絶対忘れてはいけないし、そのための努力惜しんではいけないんですよね。

集金係にお金を払うのは意味があって、自動引き落としやカード決済だとお金を払うっていう重さが伝わりにくいと僕は思っています。
ユーザがお金を払うってどいう気持ちなんだろうかという事を知るために、毎月数千円手渡しで払っています。別にNHKでなくともいいのですが、数百円だと自分にプレッシャーにならないし、少し財布に痛い料金であるNHKをいつも僕は使っています。

信じるは悪いことじゃないので、好きなWebコンテンツに思い切ってお金を払うのはありかもしれません。

Written by koujirou

April 18th, 2012 at 2:00 am

Posted in おもうたこと

ドワンゴを退職しました

with one comment

Hatena Bookmark for this entryHatena Bookmark - ドワンゴを退職しました

はじめに
1月いっぱいで株式会社ドワンゴを退職することになりました。
20日が最終出社日で2月からは新しい職場でお世話になることになりました。

ドワンゴには2010年4月に新卒として入社しサーバインフラエンジニアとして配属されました。

ドワンゴは企画から開発、インフラまで全てを内製している会社です。
そのため高いクオリティかつスピーディにサービスを提供できる環境にあり開発者自身も驚くべきスピードで成長していきます。
そんな環境に憧れて新卒として入社しました。

入社後は研修として短い期間でサービスを作りそのサービスをリリースすることもでき、辛かったですが優秀な仲間たちと一つの物を作り上げ生放送を行いユーザに触っていただくこともできました。

研修終了後は複数のプロジェクトを担当させて頂き、インフラとして困難なプロジェクトもありましたが私のわがままなどもよく受け入れて頂きメンバーの方には迷惑をかけたと思います。
しかし、その困難を乗り越えていく事で自分自身が大きく成長していくのを実感しより高みへと志が移り変わりチャレンジしてきたつもりです。

311
2011年3月11日に関東大震災が起きました。実はこの地震、私は人生で二回目の大きな地震でした。
一度目の被災は小学二年生の時に起きた阪神大震災です。家も潰れ死に物狂いで公園まで逃げました。
その時人生で初めて死というものを身近に感じ、死という目に見えないものに怯えて過ごしてきました。
しかし、人は慣れるものです。
慣れから傲慢になったり怠けたりすることも何度もあり、いつしかこの経験は忘れるほど記憶から薄れていきました。
その中で3月11日の地震は薄れた記憶を再び呼び覚まし死というものを以前より増して意識するようになり今の自分を見直すきっかけとなりました。

NOの日
昨年亡くなったスティーブ・ジョブズがスタンフォード大でのスピーチを思い出しました。

“No” for too many days in a row, I know I need to change something.

このスピーチを聞いたのは大学生の頃ですが、義務教育から大学と決められたカリキュラムと経験者から示される道筋からNoと判断することは殆どなくそれに対して疑問を抱くことも殆どありませんでした。

社会に入りカリキュラムもなく、目標や将来についても全て自らの責任として時間は進んでいきます。
日々業務をする中で自分自身のやっていることについてNoが続いている事に気づきました。

同じような業界で務めている方はよくお分かりかもしれませんが、この業界の技術は進化も早く成熟も非常に早いのです。
新卒で入社した頃は最新の技術であっても一年も経てばより効率的な技術が生み出され、常にアンテナを張り巡らせている企業はいち早く取り入れ実績を上げていきます。

自分自身で勉強したりするものの、組織としてやっているような所と比べるとなかなかついていくのが難しいのが現状です。
そして検証できた頃には成熟し新しい技術が注目され始めてるという事が多くあり、エンジニアとして挑戦できない事も増え変化の早い業界で自分自身の将来への不安が徐々に募り始め又それが、不満であったのは事実です。

これが私の”No”であったと思っています。

今ある枠組み
新卒で入社し1年半程度で退職する事については、多くの方から貴重なご意見をいただきました。
今ある枠組の中で優秀なエンジニアと切羽琢磨しながらシステムを創り上げるは素晴らしいことだと思います。

表面的な価値観だけに囚われていてはだめで本当に自分は何がやりたいのか、それに本当の価値を見出すことが大切なんじゃないかと思っています。厳しい環境で自分自身の技術を磨きインフラとしてだけではなくサービス提供者の一人としてサービスをユーザに送り届けたい。それが自分自身に今できる最大の価値なんじゃないかと思いました。

最後に
1年半という短い期間でしたが、お世話になった方々には本当に感謝しています。
ドワンゴという会社と仲間がいなければここまで自分は成長出来なかったんじゃないかと思っています。

そして、これまで使っていただいたユーザの方もドワンゴは時より寄り道をすることもありますがユーザとしてどんどん意見を発してよいサービスを作るための手助けをしたいただけたらいいなと思います。

まだまだ未熟者ですがこれからも応援していただけば励みになります。

長文となりましたが、以上です。

Written by koujirou

January 23rd, 2012 at 11:56 am

Posted in 愚痴

EXT2をEXT3に変換する

without comments

Hatena Bookmark for this entryHatena Bookmark - EXT2をEXT3に変換する

Linux上でディスクの増設やパーティションの分割を行う時に利用partedコマンドを利用する事が多いと思います。

# parted /dev/hdd
(parted) mkpartfs
Partition name?  []? 1
File system type?  [ext2]? ext3
Start? 14k
End? 10G
No Implementation: Support for creating ext3 file systems is not implemented yet.

真面目にpartedコマンドでやると

No Implementation: Support for creating ext3 file systems is not implemented yet.

このようなerrorがでると思います。

そう、partedコマンドはext3に対応していないのでpartedコマンドだけでEXT3のファイルシステムを作ることはできません。

partedコマンドではEXT2としてパーティションだけ作ることにしてそこからEXT3へ変換することにします。

ext3になっていますが完成形はEXT2になります

# parted /dev/hdd
(parted) mkpart primary ext3 14k 10G
(parted) print free 

Number  Start   End     Size    File system  Name     Flags
 1      14kB   10GB     10GB    ext2         primary

EXT3に変換します

# mkfs -t ext3 /dev/hddp01
mke2fs 1.39 (29-May-2006)
Filesystem label=
OS type: Linux
略......

最後にfstabに書き忘れないようにしましょう。

Written by koujirou

November 21st, 2011 at 11:04 pm

Posted in 小技

Macで作った秘密鍵をWindowsのPuttyで使う方法がわからなかった

without comments

Hatena Bookmark for this entryHatena Bookmark - Macで作った秘密鍵をWindowsのPuttyで使う方法がわからなかった

MacにはOpensslが入っているのでターミナルから簡単に秘密鍵(id_rsa)と公開鍵(id_rsa.pub)を作ることができます。

ssh-keygen -t rsa

この秘密鍵をWindowsで使う必要がありPutyyで読み込もうとしたのですがUnable to use key fileと怒られログインできません。

ちなみに秘密鍵を書いたファイルの拡張はなんでも大丈夫です。

結果としてPuttyGenでMacで作成した秘密鍵を読み込ませPutty用に生成すれば普通に使えました。

Puttygen起動->Load->適当にパスワードを付ける->Macで作った秘密鍵を選択->Save Private Key -> マウスを動かす -> 保存 -> 先ほど保存したキーを使ってアクセス

これで1時間ぐらい悩んでしまった。。。。。

Written by koujirou

November 2nd, 2011 at 8:55 pm

Posted in 小技

nginx+PHP-FPMでどこまでチューニングできるか

with 2 comments

Hatena Bookmark for this entryHatena Bookmark - nginx+PHP-FPMでどこまでチューニングできるか

このサイトもnginx+PHP-FPM+MySQLで動作しているのですがphpをfastcgiで動かしている例は多くあったのですがPHP-FPMで書いている記事があまりない。

yumなどは使わずにソースから全てインストールします。MySQLは事前にインストールされている物とします。

nginx

nginxユーザを追加します

adduser -u 500 nginx

使わないオプションは全てOFFにします。

./configure \
--with-http_stub_status_module \
--without-http_upstream_ip_hash_module \
--without-http_gzip_module \
--without-http_autoindex_module \
--without-http_geo_module \
--without-http_map_module \
--without-http_split_clients_module \
--without-http_referer_module \
--without-http_proxy_module \
--without-http_uwsgi_module \
--without-http_limit_zone_module \
--without-http_limit_req_module \
--without-http_browser_module \

特に–with-http_stub_status_module のオプションはサーバのステータスを見てチューニングするのには必須なので必ずいれます。

nginx設定ファイル

user  nginx;
worker_processes  2;

error_log  /var/log/nginx/blog/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
        include /usr/local/nginx/conf/mime.types;
        default_type  application/octet-stream;
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/blog/access.log  main;

        sendfile        on;
        keepalive_timeout  0;
        server_tokens off;

        server {
                listen       80;
                server_name  blog.kubox.info;
                root   /home/blog/public_html;
                index  index.php;
                error_page  404              /404.html;
                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                root   html;
        }

        location ~*\.php$ {
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /home/blog/public_html$fastcgi_script_name;
        }

        location = /status {
                include /usr/local/nginx/conf/fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /status;
                fastcgi_pass 127.0.0.1:9000;
                access_log off;
      }

        location /nginx_status {
                stub_status on;
                access_log   off;
                allow all;
                deny all;
        }

        location ~ /\.ht {
                deny all;
       }

        }
}

コンピュータはCPUの数を超えて並列処理はできないのでworker_processesはCPUの数に合わせます。2Coreなので2します。

worker_connectionsはworker_processesが同時に処理できる接続数です。

以下の行を追加するとhttp://URL/statusでPHP-FPMのステータス、http://URL/nginx_statusでnginxのステータスを見ることができます。
deny allになっているので許可するIPをAllowしてください。

location = /status {
                include /usr/local/nginx/conf/fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /status;
                fastcgi_pass 127.0.0.1:9000;
                access_log off;
      }

        location /nginx_status {
                stub_status on;
                access_log   off;
                allow all;
                deny all;
        }

PHP-FPM
PHP-FPMはPHP5.3.3から組み込まれており、オプションを追加するだけでPHP-FPMが利用できます。

fastcgiは別途lighttpdをmakeして抜き出したりする手間がありましたがその必要がなくなりより高負荷サイト用に機能が追加されました。

  • 緩やかな (graceful) 停止/起動 機能を含む高度なプロセス管理
  • 異なる uid/gid/chroot/environment でのワーカーの開始、 異なるポートでのリスン、異なる php.ini の使用 (safe_mode の代替)
  • 標準出力および標準エラー出力へのログ出力
  • opcode キャッシュが壊れた場合の緊急再起動
  • 高速なアップロードのサポート
  • “slowlog” – 非常に低速に動作するログ出力スクリプト (名前から想像される内容だけでなく、ptrace やそれと同等の仕組みを使ってリモートプロセスの execute_data からの PHP バックトレースも出力します)
  • fastcgi_finish_request() – リクエストを終わらせてすべてのデータを出力した後で 何か時間のかかる処理 (動画の変換や統計情報の処理など) をさせるための特殊な関数
  • 動的/静的 な子プロセスの起動
  • 基本的な SAPI の動作状況 (Apache の mod_status と同等)
  • php.ini ベースの設定ファイル

http://www.php.net/manual/ja/install.fpm.php

configureでenable-fpmオプションを追加してください。

'./configure' \
'--with-mysql=/usr/local/mysql' \
'--enable-zend-multibyte' \
'--with-pdo-mysql' \
'--with-zlib' \
'--with-xmlrpc' \
'--with-gd' \
'--with-curl' \
'--with-jpeg-dir=/usr/local' \
'--with-png-dir=/usr/local' \
'--enable-mbstring' \
'--enable-fpm' \
'--with-fpm-user=nginx' \
'--with-fpm-group=nginx' \
'--without-SQLite' \

PHP-FPM設定ファイル

[global]
pid = /var/run/php-fpm.pid
error_log = /var/log/php/php-fpm.log
log_level = notice
emergency_restart_threshold = 0
emergency_restart_interval = 0
process_control_timeout = 0
daemonize = yes

[www]
listen = 127.0.0.1:9000
listen.backlog = -1
listen.allowed_clients = 127.0.0.1

listen.owner = nginx
listen.group = nginx
listen.mode = 0666

user = nginx
group = nginx

pm = dynamic
pm.max_children =  10
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500
pm.status_path = /status

request_slowlog_timeout = 2
request_terminate_timeout= 5
slowlog = /var/log/php/$pool.log.slow

注目するところはpmから始まる設定です。

PHP-FPMはWebサーバ(nginx)がユーザから受け取ったリクエストをPHPでればPHP-FPMに処理を投げ処理をするので、nginxとPHP-FPMが同程度処理できるのが理想です。

ひとまず負荷試験を行うまでどこにボトルネックがあるかわからないので適用な値にしておきます。

メモリ
nginxとPHP-FPMが無事に起動できたら一旦メモリの状態を見てみます。

# free -m
             total       used       free     shared    buffers     cached
Mem:           497        385        111          0         75        154
-/+ buffers/cache:        156        341
Swap:         1027          0       1027

予想以上にメモリを使っていたのでちょっとpsしてみます。

# ps axu | grep php
root     32717  0.0  0.7 124672  3708 ?        Ss   13:45   0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
nginx    32718  0.2  9.0 139960 46368 ?        S    13:45   0:00 php-fpm: pool www
nginx    32719  0.0  5.7 132708 29424 ?        S    13:45   0:00 php-fpm: pool www
nginx    32720  0.1  4.6 129440 23700 ?        S    13:45   0:00 php-fpm: pool www
nginx    32721  0.1  5.0 129928 25940 ?        S    13:45   0:00 php-fpm: pool www
nginx    32722  0.0  5.2 130212 26900 ?        S    13:45   0:00 php-fpm: pool www

PHP-FPMが結構メモリを使っているみたいです。

pmapコマンドでプロセスのメモリ利用状況をさらに詳しくみてみます。

# pmap 32717
32717:   php-fpm: master process (/usr/local/etc/php-fpm.conf)
0000000000400000   8396K r-x--  /usr/local/sbin/php-fpm
0000000000e33000    464K rw---  /usr/local/sbin/php-fpm
0000000000ea7000    120K rw---    [ anon ]
0000000010021000   2288K rw---    [ anon ]
0000000040456000      4K -----    [ anon ]
0000000040457000  10240K rw---    [ anon ]
00000030f0c00000    112K r-x--  /lib64/ld-2.5.so
00000030f0e1c000      4K r----  /lib64/ld-2.5.so
00000030f0e1d000      4K rw---  /lib64/ld-2.5.so
00000030f1000000   1336K r-x--  /lib64/libc-2.5.so
00000030f114e000   2048K -----  /lib64/libc-2.5.so
00000030f134e000     16K r----  /lib64/libc-2.5.so
00000030f1352000      4K rw---  /lib64/libc-2.5.so
00000030f1353000     20K rw---    [ anon ]
00000030f1400000      8K r-x--  /lib64/libdl-2.5.so
00000030f1402000   2048K -----  /lib64/libdl-2.5.so
00000030f1602000      4K r----  /lib64/libdl-2.5.so
00000030f1603000      4K rw---  /lib64/libdl-2.5.so
00000030f1800000    520K r-x--  /lib64/libm-2.5.so
00000030f1882000   2044K -----  /lib64/libm-2.5.so
00000030f1a81000      4K r----  /lib64/libm-2.5.so
00000030f1a82000      4K rw---  /lib64/libm-2.5.so
00000030f1c00000     88K r-x--  /lib64/libpthread-2.5.so
00000030f1c16000   2044K -----  /lib64/libpthread-2.5.so
00000030f1e15000      4K r----  /lib64/libpthread-2.5.so
00000030f1e16000      4K rw---  /lib64/libpthread-2.5.so
00000030f1e17000     16K rw---    [ anon ]
00000030f2000000     80K r-x--  /usr/lib64/libz.so.1.2.3
00000030f2014000   2044K -----  /usr/lib64/libz.so.1.2.3
00000030f2213000      4K rw---  /usr/lib64/libz.so.1.2.3
00000030f2400000    236K r-x--  /lib64/libsepol.so.1
00000030f243b000   2048K -----  /lib64/libsepol.so.1
00000030f263b000      4K rw---  /lib64/libsepol.so.1
00000030f263c000     40K rw---    [ anon ]
00000030f2800000     84K r-x--  /lib64/libselinux.so.1
00000030f2815000   2048K -----  /lib64/libselinux.so.1
00000030f2a15000      8K rw---  /lib64/libselinux.so.1
00000030f2a17000      4K rw---    [ anon ]
00000030f2c00000     28K r-x--  /lib64/librt-2.5.so
00000030f2c07000   2048K -----  /lib64/librt-2.5.so
00000030f2e07000      4K r----  /lib64/librt-2.5.so
00000030f2e08000      4K rw---  /lib64/librt-2.5.so
00000030f3000000     52K r-x--  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f300d000   2048K -----  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f320d000      4K rw---  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f3800000     36K r-x--  /lib64/libcrypt-2.5.so
00000030f3809000   2044K -----  /lib64/libcrypt-2.5.so
00000030f3a08000      4K r----  /lib64/libcrypt-2.5.so
00000030f3a09000      4K rw---  /lib64/libcrypt-2.5.so
00000030f3a0a000    184K rw---    [ anon ]
00000030f4c00000   1204K r-x--  /lib64/libcrypto.so.0.9.8e
00000030f4d2d000   2044K -----  /lib64/libcrypto.so.0.9.8e
00000030f4f2c000    132K rw---  /lib64/libcrypto.so.0.9.8e
00000030f4f4d000     16K rw---    [ anon ]
00000030f5000000     84K r-x--  /lib64/libnsl-2.5.so
00000030f5015000   2044K -----  /lib64/libnsl-2.5.so
00000030f5214000      4K r----  /lib64/libnsl-2.5.so
00000030f5215000      4K rw---  /lib64/libnsl-2.5.so
00000030f5216000      8K rw---    [ anon ]
00000030f6000000     68K r-x--  /lib64/libresolv-2.5.so
00000030f6011000   2048K -----  /lib64/libresolv-2.5.so
00000030f6211000      4K r----  /lib64/libresolv-2.5.so
00000030f6212000      4K rw---  /lib64/libresolv-2.5.so
00000030f6213000      8K rw---    [ anon ]
00000030f6800000      8K r-x--  /lib64/libcom_err.so.2.1
00000030f6802000   2044K -----  /lib64/libcom_err.so.2.1
00000030f6a01000      4K rw---  /lib64/libcom_err.so.2.1
00000030f6c00000      8K r-x--  /lib64/libkeyutils-1.2.so
00000030f6c02000   2044K -----  /lib64/libkeyutils-1.2.so
00000030f6e01000      4K rw---  /lib64/libkeyutils-1.2.so
00000030f7c00000   1228K r-x--  /usr/lib64/libxml2.so.2.6.26
00000030f7d33000   2048K -----  /usr/lib64/libxml2.so.2.6.26
00000030f7f33000     36K rw---  /usr/lib64/libxml2.so.2.6.26
00000030f7f3c000      4K rw---    [ anon ]
00000030f8400000    144K r-x--  /usr/lib64/libk5crypto.so.3.1
00000030f8424000   2044K -----  /usr/lib64/libk5crypto.so.3.1
00000030f8623000      8K rw---  /usr/lib64/libk5crypto.so.3.1
00000030f8800000     32K r-x--  /usr/lib64/libkrb5support.so.0.1
00000030f8808000   2044K -----  /usr/lib64/libkrb5support.so.0.1
00000030f8a07000      4K rw---  /usr/lib64/libkrb5support.so.0.1
00000030f8c00000    584K r-x--  /usr/lib64/libkrb5.so.3.3
00000030f8c92000   2044K -----  /usr/lib64/libkrb5.so.3.3
00000030f8e91000     16K rw---  /usr/lib64/libkrb5.so.3.3
00000030f9400000    176K r-x--  /usr/lib64/libgssapi_krb5.so.2.2
00000030f942c000   2048K -----  /usr/lib64/libgssapi_krb5.so.2.2
00000030f962c000      8K rw---  /usr/lib64/libgssapi_krb5.so.2.2
00000030fa400000    280K r-x--  /lib64/libssl.so.0.9.8e
00000030fa446000   2048K -----  /lib64/libssl.so.0.9.8e
00000030fa646000     24K rw---  /lib64/libssl.so.0.9.8e
0000003100a00000    140K r-x--  /usr/lib64/libpng12.so.0.10.0
0000003100a23000   2048K -----  /usr/lib64/libpng12.so.0.10.0
0000003100c23000      4K rw---  /usr/lib64/libpng12.so.0.10.0
00002aaaaaac4000     40K r-x--  /lib64/libnss_files-2.5.so
00002aaaaaace000   2044K -----  /lib64/libnss_files-2.5.so
00002aaaaaccd000      4K r----  /lib64/libnss_files-2.5.so
00002aaaaacce000      4K rw---  /lib64/libnss_files-2.5.so
00002aaaaaccf000  32768K rw-s-  /dev/zero (deleted)
00002aaaacccf000      4K rw-s-  /dev/zero (deleted)
00002b9f39d31000      8K rw---    [ anon ]
00002b9f39d33000      4K rw-s-  /dev/zero (deleted)
00002b9f39d3f000      4K rw---    [ anon ]
00002b9f39d40000   2904K r-x--  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002b9f3a016000   1020K -----  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002b9f3a115000    524K rw---  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002b9f3a198000     24K rw---    [ anon ]
00002b9f3a19e000    132K r-x--  /usr/lib64/libjpeg.so.62.0.0
00002b9f3a1bf000   2044K -----  /usr/lib64/libjpeg.so.62.0.0
00002b9f3a3be000      4K rw---  /usr/lib64/libjpeg.so.62.0.0
00002b9f3a3bf000      4K rw---    [ anon ]
00002b9f3a3c0000    324K r-x--  /usr/local/lib/libcurl.so.4.2.0
00002b9f3a411000   2044K -----  /usr/local/lib/libcurl.so.4.2.0
00002b9f3a610000     12K rw---  /usr/local/lib/libcurl.so.4.2.0
00002b9f3a613000      4K rw---    [ anon ]
00002b9f3a614000    196K r-x--  /usr/lib64/libidn.so.11.5.19
00002b9f3a645000   2044K -----  /usr/lib64/libidn.so.11.5.19
00002b9f3a844000      4K rw---  /usr/lib64/libidn.so.11.5.19
00002b9f3a845000     28K rw---    [ anon ]
00002b9f3a88d000    316K rw---    [ anon ]
00002b9f3a8dc000    128K r-x--  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002b9f3a8fc000   2048K -----  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002b9f3aafc000     12K rw---  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002b9f3aaff000     36K rw---    [ anon ]
00002b9f3ab08000     76K r-x--  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/oauth.so
00002b9f3ab1b000   2048K -----  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/oauth.so
00002b9f3ad1b000      8K rw---  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/oauth.so
00007fff4a564000     84K rw---    [ stack ]
00007fff4a5fc000     16K r-x--    [ anon ]
ffffffffff600000   8192K -----    [ anon ]
 total           132860K

apc.soはAPCを使う上で必要なのでしょうがないですがoauth.soはそんなに頻繁にOAuthしないので一旦php.iniでコメントアウトしておきます。

PHP-FPMを再起動後、再度pmapしてみます。

pmap 11238
11238:   php-fpm: master process (/usr/local/etc/php-fpm.conf)
0000000000400000   8396K r-x--  /usr/local/sbin/php-fpm
0000000000e33000    464K rw---  /usr/local/sbin/php-fpm
0000000000ea7000    120K rw---    [ anon ]
000000001a798000   2252K rw---    [ anon ]
00000000406da000      4K -----    [ anon ]
00000000406db000  10240K rw---    [ anon ]
00000030f0c00000    112K r-x--  /lib64/ld-2.5.so
00000030f0e1c000      4K r----  /lib64/ld-2.5.so
00000030f0e1d000      4K rw---  /lib64/ld-2.5.so
00000030f1000000   1336K r-x--  /lib64/libc-2.5.so
00000030f114e000   2048K -----  /lib64/libc-2.5.so
00000030f134e000     16K r----  /lib64/libc-2.5.so
00000030f1352000      4K rw---  /lib64/libc-2.5.so
00000030f1353000     20K rw---    [ anon ]
00000030f1400000      8K r-x--  /lib64/libdl-2.5.so
00000030f1402000   2048K -----  /lib64/libdl-2.5.so
00000030f1602000      4K r----  /lib64/libdl-2.5.so
00000030f1603000      4K rw---  /lib64/libdl-2.5.so
00000030f1800000    520K r-x--  /lib64/libm-2.5.so
00000030f1882000   2044K -----  /lib64/libm-2.5.so
00000030f1a81000      4K r----  /lib64/libm-2.5.so
00000030f1a82000      4K rw---  /lib64/libm-2.5.so
00000030f1c00000     88K r-x--  /lib64/libpthread-2.5.so
00000030f1c16000   2044K -----  /lib64/libpthread-2.5.so
00000030f1e15000      4K r----  /lib64/libpthread-2.5.so
00000030f1e16000      4K rw---  /lib64/libpthread-2.5.so
00000030f1e17000     16K rw---    [ anon ]
00000030f2000000     80K r-x--  /usr/lib64/libz.so.1.2.3
00000030f2014000   2044K -----  /usr/lib64/libz.so.1.2.3
00000030f2213000      4K rw---  /usr/lib64/libz.so.1.2.3
00000030f2400000    236K r-x--  /lib64/libsepol.so.1
00000030f243b000   2048K -----  /lib64/libsepol.so.1
00000030f263b000      4K rw---  /lib64/libsepol.so.1
00000030f263c000     40K rw---    [ anon ]
00000030f2800000     84K r-x--  /lib64/libselinux.so.1
00000030f2815000   2048K -----  /lib64/libselinux.so.1
00000030f2a15000      8K rw---  /lib64/libselinux.so.1
00000030f2a17000      4K rw---    [ anon ]
00000030f2c00000     28K r-x--  /lib64/librt-2.5.so
00000030f2c07000   2048K -----  /lib64/librt-2.5.so
00000030f2e07000      4K r----  /lib64/librt-2.5.so
00000030f2e08000      4K rw---  /lib64/librt-2.5.so
00000030f3000000     52K r-x--  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f300d000   2048K -----  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f320d000      4K rw---  /lib64/libgcc_s-4.1.2-20080825.so.1
00000030f3800000     36K r-x--  /lib64/libcrypt-2.5.so
00000030f3809000   2044K -----  /lib64/libcrypt-2.5.so
00000030f3a08000      4K r----  /lib64/libcrypt-2.5.so
00000030f3a09000      4K rw---  /lib64/libcrypt-2.5.so
00000030f3a0a000    184K rw---    [ anon ]
00000030f4c00000   1204K r-x--  /lib64/libcrypto.so.0.9.8e
00000030f4d2d000   2044K -----  /lib64/libcrypto.so.0.9.8e
00000030f4f2c000    132K rw---  /lib64/libcrypto.so.0.9.8e
00000030f4f4d000     16K rw---    [ anon ]
00000030f5000000     84K r-x--  /lib64/libnsl-2.5.so
00000030f5015000   2044K -----  /lib64/libnsl-2.5.so
00000030f5214000      4K r----  /lib64/libnsl-2.5.so
00000030f5215000      4K rw---  /lib64/libnsl-2.5.so
00000030f5216000      8K rw---    [ anon ]
00000030f6000000     68K r-x--  /lib64/libresolv-2.5.so
00000030f6011000   2048K -----  /lib64/libresolv-2.5.so
00000030f6211000      4K r----  /lib64/libresolv-2.5.so
00000030f6212000      4K rw---  /lib64/libresolv-2.5.so
00000030f6213000      8K rw---    [ anon ]
00000030f6800000      8K r-x--  /lib64/libcom_err.so.2.1
00000030f6802000   2044K -----  /lib64/libcom_err.so.2.1
00000030f6a01000      4K rw---  /lib64/libcom_err.so.2.1
00000030f6c00000      8K r-x--  /lib64/libkeyutils-1.2.so
00000030f6c02000   2044K -----  /lib64/libkeyutils-1.2.so
00000030f6e01000      4K rw---  /lib64/libkeyutils-1.2.so
00000030f7c00000   1228K r-x--  /usr/lib64/libxml2.so.2.6.26
00000030f7d33000   2048K -----  /usr/lib64/libxml2.so.2.6.26
00000030f7f33000     36K rw---  /usr/lib64/libxml2.so.2.6.26
00000030f7f3c000      4K rw---    [ anon ]
00000030f8400000    144K r-x--  /usr/lib64/libk5crypto.so.3.1
00000030f8424000   2044K -----  /usr/lib64/libk5crypto.so.3.1
00000030f8623000      8K rw---  /usr/lib64/libk5crypto.so.3.1
00000030f8800000     32K r-x--  /usr/lib64/libkrb5support.so.0.1
00000030f8808000   2044K -----  /usr/lib64/libkrb5support.so.0.1
00000030f8a07000      4K rw---  /usr/lib64/libkrb5support.so.0.1
00000030f8c00000    584K r-x--  /usr/lib64/libkrb5.so.3.3
00000030f8c92000   2044K -----  /usr/lib64/libkrb5.so.3.3
00000030f8e91000     16K rw---  /usr/lib64/libkrb5.so.3.3
00000030f9400000    176K r-x--  /usr/lib64/libgssapi_krb5.so.2.2
00000030f942c000   2048K -----  /usr/lib64/libgssapi_krb5.so.2.2
00000030f962c000      8K rw---  /usr/lib64/libgssapi_krb5.so.2.2
00000030fa400000    280K r-x--  /lib64/libssl.so.0.9.8e
00000030fa446000   2048K -----  /lib64/libssl.so.0.9.8e
00000030fa646000     24K rw---  /lib64/libssl.so.0.9.8e
0000003100a00000    140K r-x--  /usr/lib64/libpng12.so.0.10.0
0000003100a23000   2048K -----  /usr/lib64/libpng12.so.0.10.0
0000003100c23000      4K rw---  /usr/lib64/libpng12.so.0.10.0
00002aaaaaac4000     40K r-x--  /lib64/libnss_files-2.5.so
00002aaaaaace000   2044K -----  /lib64/libnss_files-2.5.so
00002aaaaaccd000      4K r----  /lib64/libnss_files-2.5.so
00002aaaaacce000      4K rw---  /lib64/libnss_files-2.5.so
00002aaaaaccf000  32768K rw-s-  /dev/zero (deleted)
00002aaaacccf000      4K rw-s-  /dev/zero (deleted)
00002aac041d0000      8K rw---    [ anon ]
00002aac041d2000      4K rw-s-  /dev/zero (deleted)
00002aac041d3000      4K rw-s-  /dev/zero (deleted)
00002aac041d4000      4K rw-s-  /dev/zero (deleted)
00002aac041d5000      4K rw-s-  /dev/zero (deleted)
00002aac041de000      4K rw---    [ anon ]
00002aac041df000   2904K r-x--  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002aac044b5000   1020K -----  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002aac045b4000    524K rw---  /usr/local/mysql/lib/libmysqlclient.so.18.0.0
00002aac04637000     24K rw---    [ anon ]
00002aac0463d000    132K r-x--  /usr/lib64/libjpeg.so.62.0.0
00002aac0465e000   2044K -----  /usr/lib64/libjpeg.so.62.0.0
00002aac0485d000      4K rw---  /usr/lib64/libjpeg.so.62.0.0
00002aac0485e000      4K rw---    [ anon ]
00002aac0485f000    324K r-x--  /usr/local/lib/libcurl.so.4.2.0
00002aac048b0000   2044K -----  /usr/local/lib/libcurl.so.4.2.0
00002aac04aaf000     12K rw---  /usr/local/lib/libcurl.so.4.2.0
00002aac04ab2000      4K rw---    [ anon ]
00002aac04ab3000    196K r-x--  /usr/lib64/libidn.so.11.5.19
00002aac04ae4000   2044K -----  /usr/lib64/libidn.so.11.5.19
00002aac04ce3000      4K rw---  /usr/lib64/libidn.so.11.5.19
00002aac04ce4000     28K rw---    [ anon ]
00002aac04d2c000    316K rw---    [ anon ]
00002aac04d7b000    128K r-x--  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002aac04d9b000   2048K -----  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002aac04f9b000     12K rw---  /usr/local/lib/php/extensions/no-debug-non-zts-20090626/apc.so
00002aac04f9e000     36K rw---    [ anon ]
00007fffbee97000     84K rw---    [ stack ]
00007fffbeffc000     16K r-x--    [ anon ]
ffffffffff600000   8192K -----    [ anon ]
 total           130704K

2Mダイエットできました。

負荷試験
nginxとPHP-FPMを少しキャッシュなどで太らせたいので別のマシンからApacheBenchしてみます。

./ab -n 1000 -c 20 -t 10 http://blog.kubox.info/
# free -m
             total       used       free     shared    buffers     cached
Mem:           497        346        151          0         11        126
-/+ buffers/cache:        208        289
Swap:         1027          9       1017

結構メモリを消費したみたいです。

LoadAverageも結構あがりました。

top - 17:16:48 up 7 days,  2:56,  3 users,  load average: 4.12, 1.24, 0.44
Tasks: 107 total,  23 running,  75 sleeping,   8 stopped,   1 zombie
Cpu(s): 89.5%us,  4.5%sy,  0.0%ni,  0.0%id,  0.0%wa,  2.5%hi,  3.5%si,  0.0%st
Mem:    509792k total,   299092k used,   210700k free,    12056k buffers
Swap:  1052248k total,    10232k used,  1042016k free,   102124k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
11823 nginx     16   0  124m  23m  15m R 63.8  4.7   0:02.69 php-fpm
11810 nginx     16   0  124m  23m  15m R 31.9  4.6   0:02.31 php-fpm
11805 nginx     16   0  124m  23m  15m R 25.9  4.6   0:03.59 php-fpm
11824 nginx     16   0  125m  23m  15m R 21.9  4.8   0:01.19 php-fpm
11806 nginx     16   0  124m  23m  15m R 19.9  4.6   0:03.96 php-fpm
11807 nginx     16   0  125m  23m  15m R 15.0  4.8   0:02.25 php-fpm
11825 nginx     16   0  125m  23m  15m R 15.0  4.8   0:01.55 php-fpm
10715 nginx     15   0 21728 2180  756 S  5.0  0.4   0:01.02 nginx
11123 mysql     15   0  452m  50m 5684 S  1.0 10.1   0:01.65 mysqld

エラーがでるまでApacheBenchのスレッドを上げていきます。

同時に先ほどnginxでstatusとnginx_statusを設定したページにアクセスしてプロセスの状態を見ます。

#nginx_status
Active connections: 19
server accepts handled requests
 815 815 815
Reading: 0 Writing: 19 Waiting: 0

Readingはnginxがリクエストのヘッダーを読み込んでいる数、Writingはレスポンス用のリクエストを生成している数、WaitingはKeepAliveで待っている数です。

KeepAliveは0(無効)にしているので必ず0になります。KeepAliveはDoS攻撃などの耐性が低くなるのでできるだけ無効で運用します。

100スレッド目からエラーが出始めました。

Server Software:        nginx
Server Hostname:        blog.kubox.info
Server Port:            80

Document Path:          /
Document Length:        119439 bytes

Concurrency Level:      100
Time taken for tests:   11.310 seconds
Complete requests:      100
Failed requests:        2
   (Connect: 0, Receive: 0, Length: 2, Exceptions: 0)
Write errors:           0
Non-2xx responses:      2
Total transferred:      11742858 bytes
HTML transferred:       11705790 bytes
Requests per second:    8.84 [#/sec] (mean)
Time per request:       11309.898 [ms] (mean)
Time per request:       113.099 [ms] (mean, across all concurrent requests)
Transfer rate:          1013.95 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       10   21   6.5     20      34
Processing:   475 6205 3240.7   6199   11285
Waiting:      129 5687 3298.2   5759   11123
Total:        489 6227 3241.4   6226   11304

Percentage of the requests served within a certain time (ms)
  50%   6226
  66%   8179
  75%   9103
  80%   9653
  90%  10643
  95%  11059
  98%  11106
  99%  11304
 100%  11304 (longest request)

クライアント側のログを見てみます。

 [error] 5717#0: *5587 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: IP, server: blog.kubox.info, request: "GET / HTTP/1.0", upstream: "fastcgi://127.0.0.1:9000", host: "hostname"

どうやらnginxが受け取ったリクエストをPHP-FPMに処理を投げたときにconnectionを切られているみたいです。

このエラーの場合はnginxはユーザからリクエストを受け取り、PHP-FPMに処理を投げているのでボトルネックはPHP-FPMだと分かります。

PHP-FPMの設定を見直すとrequest_terminate_timeout= 5が悪さをしているようでタイムアウトを少し長めします。

request_terminate_timeout= 10

150スレッド目で同様のエラーが出力されました。

PHP-FPMのステータスを負荷試験中に見るとmax children reached: 1となっているのでPHP-FPMのプロセスが常時最大に達しているのが確認できました。

pool:                 www
process manager:      dynamic
accepted conn:        317
listen queue len:     0
max listen queue len: -1
idle processes:       0
active processes:     10
total processes:      10
max children reached: 1

PHP-FPMのプロセスを増やしたいと思います。

ApacheやnginxやPHP-FPMはforkしてプロセス間で負荷分散しつつメモリの消費を節約します。

サーバが落ちる時は大体この辺りの設定ミスです。

実際にどれぐらいforkさせるのかはサービスによって異なりますが物理リソースを無駄なく利用するにはforkで生じるメモリ使用量を把握する必要があります。

メモリのお話については割愛しますが今回のPHP-FPMでいうとforkされたプロセスが使うメモリはおおよそ7M程度です。

物理メモリ100Mは残して起きたいのでさらに20プロセス増やす事にしました。

pm = dynamic
pm.max_children =  30
pm.start_servers = 11
pm.min_spare_servers = 10
pm.max_spare_servers = 15
pm.max_requests = 500

PHP-FPMを再起動後メモリの状態を見てみます。
予想に反してあまりメモリを消費しなかったみたいです。

# free -m
             total       used       free     shared    buffers     cached
Mem:           497        400         97          0         52        140
-/+ buffers/cache:        207        290
Swap:         1027          9       1017

プロセス数を3倍にしたので論理的には3倍のアクセスを処理できることになります。

再度ApacheBenchで今度は450スレッドまで引き上げて負荷試験をしてみます。

Server Software:        nginx
Server Hostname:        blog.kubox.info
Server Port:            80

Document Path:          /
Document Length:        119439 bytes

Concurrency Level:      350
Time taken for tests:   10.132 seconds
Complete requests:      82
Failed requests:        0
Write errors:           0
Total transferred:      10160997 bytes
HTML transferred:       10128261 bytes
Requests per second:    8.09 [#/sec] (mean)
Time per request:       43245.804 [ms] (mean)
Time per request:       123.559 [ms] (mean, across all concurrent requests)
Transfer rate:          979.37 [Kbytes/sec] received

心なしかレスポンスが良くなりました。

vmstatを見てみるとrがCPUコア数を超えているのでCPUの負荷がかなり高い状態になっています。
メモリはswapは少々発生していますがswap inもoutも発生していないのでとりあえず問題はありません。
procsのbとSWAPのsoが発生し始めると大幅に性能が劣化しますので注意が必要です。

nginxのエラーログとvmstatを見る限りエラーもなしでCPUのみが高負荷なので理想な負荷です。

# vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0  10144  73552  54424 147776    0    0     1     3    2   16  0  0 99  0  0
31  0  10144  59592  54424 147776    0    0     0     0 2099  858 57 10 33  0  0
31  0  10144  60948  54424 147792    0    0     0     0 1744  762 94  6  0  0  0
31  0  10144  58468  54424 147868    0    0     0     4 1897  681 94  6  0  0  0
31  0  10144  59212  54424 147876    0    0     0     0 1904  842 94  6  0  0  0
34  0  10144  59708  54428 147948    0    0     0   460 1777  828 94  6  0  0  0
32  0  10144  59832  54428 147944    0    0     0     0 1785  835 94  6  0  0  0
32  0  10144  59212  54428 148020    0    0     0     0 1971  763 93  7  0  0  0
31  0  10144  59832  54428 148024    0    0     0     0 1891  896 94  6  0  0  0
31  0  10144  59708  54428 148100    0    0     0     0 2010  769 94  6  0  0  0
32  0  10144  59832  54436 148080    0    0     0   480 1943  855 93  7  0  0  0
34  0  10144  70760  54436 148232    0    0     0     0 2099 1320 92  9  0  0  0
35  0  10144  69560  54436 148444    0    0     0     0 1020 1727 95  5  0  0  0

Too many open files

800スレッド目からnginxのエラーログにToo many open filesが出力され始めました。

nginxのファイルオープン数の制限に引っかかったようです。

設定ファイルにworker_rlimit_nofile 10240;を追加します。

設定を追加後もエラーが消えないのでどうやらLinuxのファイルディスクリプタに引っかかっているようです。

#vi /etc/security/limits.conf
nginx       soft    nofile  10240
nginx       hard    nofile  10240

これでエラーはでなくなりました。

最終的に1000スレッドまで達し24時間負荷をかけ続けましたが(これはJmeterで)レスポンスタイムは平均で3秒程度まで落ちたものの安定したアクセスでエラーも出力されていませんでした。

expireを使いユーザのブラウザにキャッシュさせる方法も画像が多いサイトには有効です。

1000スレッド目で負荷を与える側の限界に達したので今回はこれ以上行う事はできませんがApacheと比べて最初はメモリ使用量がやや多いですが、高負荷時は一定のペースを保つので負荷の高いサイトにnginxはオススメです。

その他やったこと
libjpeg-turboに差し替え

libjpeg-truboはlibraryを差し替えるだけで簡単にjpeg系の処理を高速化できます。
http://sourceforge.jp/projects/freshmeat_libjpeg-turbo/

tar -zxvf nasm-2.09.02.tar.gz
cd nasm-2.09.02
./configure
make
make install

tar -zxvf libjpeg-turbo-1.0.90.tar.gz
cd libjpeg-turbo-1.0.90
./configure
make
make install

/opt/libjpeg-turbo/ にインストールされるので、一旦 /usr/lib/libjpeg* をtmpなどに待避させてから入れ替えます。

mkdir /tmp/libjpeg-backup/
mv /usr/lib/libjpeg* /tmp/libjpeg-backup/
cp -aL /opt/libjpeg-turbo/lib/lib* /usr/lib/
ldconfig

WordPressは接続の度にDBを叩くのでクエリーキャッシュを多めに設定しています。

skip-name-resolve
key_buffer_size = 20M
max_allowed_packet = 1M
table_open_cache = 1024
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 8M
thread_concurrency = 8
character-set-server = utf8
skip-character-set-client-handshake
max_connect_errors=10000
max_connections=300
table_cache=256
thread_cache_size = 30
query_cache_size = 32M
wait_timeout = 60

innodb_data_file_path = ibdata1:1024M;ibdata2:2048M:autoextend
innodb_buffer_pool_size = 128M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method=O_DIRECT

負荷試験中のMySQLの状態を見てみます。

この3つの値が増え始めるとMySQLの負荷が高くなってくるので上記の設定で予めキャッシュさせておきます。

mysql> SHOW GLOBAL STATUS;
 Max_used_connections                     | 2
 Opened_tables                            | 45
 Opened_files                             | 121

Written by koujirou

July 27th, 2011 at 5:30 pm

オープンソースで構築する仮想ファイアーウォール IPS編

without comments

Hatena Bookmark for this entryHatena Bookmark - オープンソースで構築する仮想ファイアーウォール IPS編

前回の記事でVyattaのF/Wの基本的な使い方を解説いたしましたが、今回はより強固なネットワークを実現させるためにIPSを使ってみます。

VyattaのIPSはLinuxでも頻繁に使われているSnortを使っています。

Vyatta自体は非常に軽量で高速に動作しますがSnort(IPS)を利用する場合はパケットを転送するだけのルータではなく、パケットの中身を見てシグネチャと照らし合わせ、Vyattaで設定したポリシーと照らし合わすなどのプロセスがあるためメモリを多めに積んだマシンが必要になります。
また今回は紹介していないですがNATを利用する場合も同様でパケットを書き換え再度checksumする必要があるためCPUパワーが必要になります。

Snortのおさらい
Snortはオープンソースの侵入検知システム(IDS)と言われるもので、ネットワークに流れるパケットをキャプチャーし不正なパケットを検出します。

通常IDSは不正なパケットを検出し警告を出すにとどまりますが、IPSは検出し遮断します。

VyattaはSnortでこれを実現します。

不正アクセスする手法やシステムの脆弱性は常につきまとうので、Snortは定期的にルールセット(シグネチャ)を更新しています。

Snortにユーザ登録

Snortのシグネチャを定期的に更新するためにSnortにユーザ登録しoink-codeを取得します。

http://www.snort.org/

Snortの設定

早速、VyattaでIPSの設定をしてみましょう。

まず、Snortのシグネチャを取得します。

$update ips rules oinkcode ****

Snortのサーバが少し遅いので時間がかかるかもしれません。

updateを先しないとError: Missing Snort Rulesと出たりするので必ず先にUpdateしてください。

ログを見ると更新されたのかわかります。

$show ips update-log

自動アップデートとLANの設定

Snortは定期的にシグネチャを更新する必要があるので自動アップデートの設定を行い定期的にシグネチャを更新したいと思います。

$configure
#set content-inspection ips auto-update oink-code ****
#set content-inspection ips auto-update update-hour 2

この設定でAM2時に自動的に更新されます。

次にLANのネットワークを予め指定することでSnortによる誤検知を防ぐ事ができます。

$configure
#set content-inspection ips modify-rules internal-network 192.168.1.0/24

IPSの設定

VyattaのIPSではパケットをチェックする経路を選択できます。

  1. 全てのパケットをチェック
  2. 特定のインタフェースのパケットをチェック
  3. 特定のゾーン間のパケットをチェック

IPSは負荷が高いのでできるだけパケットチェック対象を絞るべきですが今回は1の全チェックで検証したいと思います。

$configure
#set content-inspection inspect-all enable

次にチェックするプロトコルを指定します。これでも同様に全チェックだと負荷が高くなります。ICMPやF/Wで既にdropしているプロトコルなどは省くべきです。

$configure
#set content-inspection traffic-filter preset all

ここでshowして設定を確認してみましょう。

$configure
#show content-inspection
+inspect-all {
+    enable
+}
+ips {
+    auto-update {
+        oink-code ***
+        update-hour 2
+    }
+    modify-rules {
+        internal-network 192.168.1.0/24
+    }
+}
+traffic-filter {
+    preset all
+}

最後にVyattaでデフォルトルールで設定されている警告レベルの設定を行います。

デフォルトルールには4つのプライオリティが準備されています。
priority-1が最も危険度が高いイベントになりpriority-3が通常の通信でも発生するようなイベントになります。
Otherはルールにマッチしなかった場合に適応されます。

  1. priority-1
  2. priority-2
  3. priority-3
  4. Other

例えば各priorityには次のようなルールがセットされています。

priority-1 trojan-activity トロイなどによるバックドアを検知します
priority-2 successful-dos DoSを検知します
priority-3 icmp-event Pingを検知します

その他にも多くあるのでドキュメントを参照してください。
show ips rulesでも確認できます。

$ show ips rules

Vyattaではこれらのpriority別に検知時の動作を指定します。

  1. alert:通信を許可しログにAlertとして記録します
  2. drop:通信を遮断しログにAlertとして記録します
  3. pass:通信を許可しそれ以外の動作をしません
  4. sdrop:通信を遮断しログには記録しません(silent drop)

今回は実験的に全てのpriorityをdropとして指定したいと思います。

$configure
#set content-inspection ips actions priority-1 drop
#set content-inspection ips actions priority-2 drop
#set content-inspection ips actions priority-3 drop
#set content-inspection ips actions other pass

そして一旦、ローカルネットワークの設定を削除してみます。

$configure
#delete content-inspection ips modify-rules internal-network 192.168.1.0/24
#commit

削除した事で全てのネットワークがIPSの対象になりました。

別のマシンからこのVyattaにPingを打ちます。

$ping 192.168.1.2
PING 192.168.1.1 (192.168.250.1) 56(84) bytes of data.

--- 192.168.250.1 ping statistics ---
16 packets transmitted, 0 received, 100% packet loss, time 15086ms

全てPingが失敗したのが確認できたと思います。

この原因を調べてみます。

$show ips log
---------------------------------------------------------------------------
2011-07-22 16:51:15.540325 {ICMP} 192.168.1.2 -> 192.168.1.3
(misc-activity) Misc activity (priority 3)
[1:382:7] ICMP PING Windows
---------------------------------------------------------------------------
2011-07-22 16:51:15.540325 {ICMP} 192.168.1.2 -> 192.168.1.3
(misc-activity) Misc activity (priority 3)
[1:384:5] ICMP PING
---------------------------------------------------------------------------

priority-3のルールによって遮断されていることがわかりました。

Pingを通すためにルールを変更したいと思います。

Pingを防いでいるルールはicmp-info.rulesですので、このルールだけを除外します。

$configure
#set content-inspection ips modify-rules exclude-category icmp-info.rules
#commit

再度Pingを実行するとPingが通ると思います。

最後に変更したローカルネットワークの設定を元に戻しておいてください。

$configure
#set content-inspection ips modify-rules internal-network 192.168.1.0/24

priority-1以外はAlertで大丈夫だと思いますが利用するネットワーク形態によって調節してみてください。

IPS導入時はこまめにログを見てフォールスポジティブとフォールスネガティブが無いかチェックし適宜ポリシーを変更する必要があります。

Written by koujirou

July 22nd, 2011 at 6:07 pm

Posted in セキュリティ

オープンソースで構築する仮想ファイアーウォール

without comments

Hatena Bookmark for this entryHatena Bookmark - オープンソースで構築する仮想ファイアーウォール

仮想ファイアーウォールというとイメージしにくいと思いますがVyattaを少し使ってみたので紹介したいと思います。

長くなるので3つぐらいに分けたいと思います。

Vyatta : ビアッタ

Vyattaでできること

  • Routing
  • NAT
  • VPN
  • ※F/W
  • ※IPS
  • Loadbalance
  • VRRP
  • CUI/GUI(Webベース)

今回紹介するのは※が付いている項目です。

 

Vyattaとはそもそもなに?

VyattaはDebianベースで作られておりiptablesやsnortなどを組み合わせた“物”です。

Juniperなどのアプライアンス製のF/Wに付いている機能が網羅されている感じです。

ルーティングプロトコルも充実しているので高性能なルータとしても十分機能させることができます。

またVyattaには有料サポートも準備されおりサポートが必要な場合はそちらを使うのもいいと思います。

無料版もVPNクライアントやアンチウイルス機能が無い程度ですので十分に使えます。

イメージの配布もクラウド環境用なども準備されているのですぐに試すことができます。

http://www.vyatta.org/

 

インストール

メモリ256M、HDD 5Gもあれば十分です。

今回は検証が目的なので利用環境に応じてリソースは変更してください。

インストール自体は非常に簡単なので省略します。

Live Installのままだとリブート後全て消えてしまうのでinstall-imageだけは行ってください。

$install-image

イメージをInstallした後は必ずリブートしてください。色々おかしくなります。

初期設定が終わるまでGUIは使えないのでCLIで進めます。

ユーザ名、パスワード共にvyattaでログインできます。

Linuxライクなプロンプトが表示されていると思いますが、通常のLinuxコマンドもそのまま使えます。

lsコマンドなどを実行するとファイル/ディレクトリリストが表示されると思います。

 

基本操作

Ciscoなどの製品を使ったことがある人ならすぐになじめると思います。

Vyattaの操作はLinuxコマンドで行うのではなくVyatta専用のコマンドを利用します。

show : showに続く項目の情報を表示する
set : setに続く項目を設定する
save : 設定を起動ファイルに書き込む(設定は再起動まで反映されない)
commit : 設定を反映させる(設定後必ず行う)

$ : operationモード
operationモードでは設定の変更は行えません。

F/Wやインタフェースなどの情報を確認したい場合に利用します。

 

# : configureモード
operationモード時にconfigureコマンドを実行することでcofigureモードに移行できます。

configureモードでは全ての設定の変更が行えます。

 

IPの設定

早速IPを割り振ってみましょう。

configureモードになったら次のコマンドを実行します。

$configure
#set interface ethernet eth0 address 192.168.1.2/24
#set system gateway-address 192.168.1.1
#commit

これでeth0に192.168.1.2が割り当てられました。

SSHを起動

SSHが使えないと色々不便なのでSSHを起動します。

$configure
#set service ssh
#commit

ここまでくるとGUIを利用できます。

#set service https
#commit

先ほど設定したIPアドレスにアクセスするとGUIモードで設定を変更できます。

NTP/DNS設定

$configure
#set system time-zone Asia/Tokyo
#set system ntp server ntp.nict.jp
#set system name-server 8.8.8.8
#commit

ユーザ追加

plaintext-passwordとなっていますが、入力はプレーンテキストなのでそのままで大丈夫です。
設定後暗号化されます。

levelは適宜変更してください。

$configure
#set system login user kojiro
#set system login user kojiro level admin
#set system login user kojiro authentication plaintext-password hogehoge
#commit

F/W設定
初期設定ができたところで、本題のF/Wの設定を行いたいと思います。

F/Wを設定する前に予めIPアドレスのグループを作っておくと後々の運用が楽になります。

VMGuet01というグループを作りIPアドレス172.16.0.10を参加させました。

$configure
#set firewall group address-group VMGuet01
#set firewall group address-group VMGuet01 address 172.16.0.10
#commit

VyattaのF/Wは親ノード⇒親ノード内のルール番号(1~1024)⇒許可/拒否⇒マッチ条件 のような流れで設定します。

HTTPという親ノードを作成します

$configure
#set firewall name HTTP

ルール番号を指定する。1~1024までならどれも大丈夫ですが1から評価されてゆきマッチした時点でそれ移行を評価しないので100や200など少し間を開けて登録するのがセオリーです。
また、どれにもマッチしなかった場合はF/W全般に言えることですが暗黙の拒否があり全て拒否されます。

今回は内側(LAN)から外側(WAN)に向けた設定をしてみます。

ルールは100から使ってきます。

$configure
#set firewall name HTTP rule 100

HTTPノードに対するルール100のアクションを指定します

$configure
#set firewall name HTTP rule 100 action accept

HTTPノードに対するルール100のマッチ条件を指定します

$configure
#set firewall name HTTP rule 100 source group address-group VMGuet01
#set firewall name HTTP rule 100 destination port 80,443

この設定は送信元がVMGuet01で宛先のポートが80番(HTTP)、443(HTTPS)を許可するという意味になります。

sourceをPortやGlobalIPなどにすることで外側から内側へのアクセス制御も行えます。

commit時にエラーがでる場合などは設定が抜けている事が殆どなのでshowコマンドで設定を確認しながらやっていくといいと思います。

次はIPSを設定してみます。

Written by koujirou

July 21st, 2011 at 10:00 am

Posted in セキュリティ

GoogleのWebアプリケーション脆弱性スキャナ使い方

without comments

Hatena Bookmark for this entryHatena Bookmark - GoogleのWebアプリケーション脆弱性スキャナ使い方

はてなから引っ越ししました。はてなさん今までお世話になりました。

GoogleがWebアプリケーション脆弱性スキャナskipfishを公開しました。

以前にもGoogleが開発した脆弱性診断ツールratproxyを紹介しました。

ratporxyとskipfishの大きな違いは、ratproxyは受動的な脆弱性診断ツールであったのに対してskipfishは能動的な脆弱性診断ツールです。

skipfishの特徴

  • SQLインジェクションの検出
  • コマンドインジェクションの検出
  • 秒間2000リクエスト以上実行できるパフォーマンスの高さ
  • Basic認証、cookieなども渡せる
  • 非常にファイルが軽い(1.3M)
  • HTMLで結果を出力

 

使い方
skipfishをダウンロードしてください。

展開後

make
./skipfish -o /var/www/html/skipfish -W /dir/dictionaries/complete.wl http://test.jp/

-o 結果ファイル出力先(空ディレクトリじゃないとエラーになります)
-W テストに使う辞書
-g 最大接続数 (指定推奨)

complete.wlで2時間ぐらいかかりました。

使ってみた感じ

今まで利用した脆弱性診断ツールの中では間違いなく最高速度ですが、辞書が少ない点、辞書式では難しい既存の脆弱性を発見するための仕組みがないことから簡易的な使い方や開発中のアプリケーションのような診断にしか使えないと思います。

現在はまだβ版なので今後の追加機能に期待。

Written by koujirou

July 19th, 2011 at 6:03 pm

Posted in セキュリティ