isucon3本戦に参加してきました。 #isucon

isucon3本戦にNoderチームとして参加してきました。予選と同じく、 @hakobera さん、 @hokaccha さん、そしてというメンバー。

結果どうだったか


悔しいー!!

今回画像系サービスということで登録された後の画像チェックが有り、そのチェックの不整合を最後まで取りきれず、、、無念の失格。ただ、失格はしたものの、参考点として、36464点を記録。点数だけなら3位の結果でした。。。

画像系サービス

最初にサービスの説明をすると、Twitterのようなサービスで、text投稿じゃなくて画像投稿をベースにしたサービス。

スクリーンショット的にはこんな感じ。

f:id:yosuke_furukawa:20131111130102p:plain

詳しくはレギュレーションを参照。

予選と違い、5台の複数台サーバーで好きなサーバーに何を入れても良い、という状態。
初期状態はサーバー1台でサービスが稼働しており、データベース、画像変換、Webアプリサービスが実装されている。

まずは序盤でssh周りのセッティングを行い、各サーバーに簡易的にアクセスできるようにする、gitリポジトリを作成してもらう、などの足回りを先に実施。

事前のミーティングで最初の1時間位は計測して方向性を決める、という事になっていたので、前回入れられなかったprofiler周りのセットアップを @hakobera さん中心に設定。

newrelicでprofilingしつつ、mysqlのslow_queryを取るようにした。

この辺りまでかなりスムーズ。

初期のベンチスコアは、 1301点(ちなみにこれが最初で最後のsuccess。。。)

測定結果が出てきたので、ここからボトルネックを判定していく。

DB周りはlong_query_timeを50msecにしたものの、全く出力されず。DB側は既にほとんど問題ない感じ。newrelicの状態を見てもDBよりも圧倒的に画像生成側で負荷が発生している事が判明。

これを基に5台のサーバー構成を決めていく。

初期サーバー構成

ひとまずprofilerの状況を基に下記の設定を実施。 hakobera さんが cacoo を使ってみんなにシェアしてくれたりとツールを使いこなしてくれてて助かった。

  • DBサーバ 1台
  • nginx 1台
  • Webサーバ 2台
  • 画像変換用サーバ 1台

DBはボトルネックじゃないので、素直に1台構成。shardingとかもしなくていいので楽だった。
nginxで各サーバーに処理を振り分ける実装を実現。
Webサーバも一様に負荷が来てるので2台構成。
画像変換だけは別サーバにした方がいいだろうということで1台別途割り当てることに。

序盤はこの構成を実現するところまでやって、ベンチ取ってからお昼食べようということになった。

nginx周りをhakobera さんに任せて、 画像変換サーバを hokaccha さんに任せ、残りは自分でセッティングする事に。

hakobere さん側でnginxから各種サーバへの振り分けを実装。

hokaccha さん側で画像変換処理を高速にするために child_process.exec してるところを imagemagick-native というモジュールを使うことに。(※Node学園祭のLTで発表されてたので使ってみようという感じに。)

僕の方では、deploy周りをスムーズにしておこう、ということで、全台にgit pullするスクリプトを作成したり、DBサーバをWebサーバから見えるようにするためにiptablesの設定したり、mysqlの権限設定したりとこまごましたところを設定。

大体全員の対応が終わったのが12:50〜13:00位。

5台構成、全然動かず

まずリファレンス実装の所にミスが有り、別サーバからisuconユーザーでDBに接続しようとすると動作しなかった。

{
  "database": {
    "dbname": "isucon",
    "host": "XXX.XXX.XXX.XXX",
    "port": 3306,
    "username": "isucon", ← ここが username => user にする必要が有る。
    "password": ""
  },
  "data_dir": "./data"
}

node-mysql側でユーザーのキーの指定がミスしているとデフォルトのrootユーザーでアクセスしに行くため、rootユーザーの権限が付いているローカルサーバだと起動していたが、別サーバからisuconユーザで接続する時にエラーになってた。

この辺りで30分くらいロス。
まぁその辺りを取り終わっていざベンチ!!

1301 => 890 位にダウン。

なんだよ〜、いきなり気持ち折るなよーー。。
お昼食べるのも忘れて5台構成にしたのに最初全然だった。

まぁひとまず動作はしたので、一旦ここからランチを食べながらベンチツールのエラーやnewrelicを見ながら解析。

中盤

  • 画像のdiffでベンチがfailしている。
  • nginx側でnginx error – 413 Request Entity Too Largeみたいなエラーがたくさん出てた。

nginxのエラーはhakoberaさんに、画像サーバの問題は hokaccha さんにお任せし、僕はtimelineの取得がまだ遅かったのでSQL修正や実装を少しずつ修正。timelineは多少早くなった気がする。

この辺りの修正が終わり、多少ベンチが早くなってきたのがもう大体16時くらい。

この時点の最高点として

890 => 5000位にアップ ※failしてるけど。

終盤

最後の一時間がisuconだ!! という事でここから色々と見直しつつ、全員で落ち着きながら色々試そうという事に。hakoberaさんがプロファイラを見つつ、サーバー構成を変えてくれて、

終盤のサーバー構成

  • DBサーバ 1台
  • nginx兼Webサーバ 1台
  • Webサーバ 2台
  • 画像変換用サーバ 1台

という構成に。

その後hakoberaさんに全体を見てもらいつつ、この前実施できなかったworkload周りのチューニングをやってもらい、最終的には
failは取りきれないものの、点数は

5000 => 12000位にアップ

でもまだfail...

icon画像が2件だけfailする。。。この時点であと1時間も無かった気がする。
postした画像を全件残してdiff取るとか、実装を元に戻してベンチ取ったりと色々検討したものの、どれも残り時間で実現できる見通しが立たず。

できることを最後までやりきろうとやってたけど、10分を残してもうfailを取り切るのは無理だと判断
少なくともベストを尽くす意味で、再起動したらちゃんとベンチ動くこと、自分達の設定にミスが無いことを確認。

動作を確認して、タイムアップ。

結果は思った通り、Failして失格だけど、点数はそこそこ良かった。

36464点。(※failしてるけど。)

反省会

終わった後でfujiwaraさんに画像のエラー取りきれなかったことを伝えつつ、どの辺りに問題がありそうか確認。

どうやらiconのpostは48x48のデータでそれを32x32にするので、imagemagickのライブラリを変えた場合、画像変換方法が変わると画像の差分が結構出る可能性がある、との事。あとありそうな事としては、画像の透過がうまく効いてないとかも考えられるかも、との事でした。

その辺りはこっちも気をつけないといけないけど、やっぱりimage-diffのツールは用意されてるからそれを試すべきだったなーと。。。

この辺りから悔しさがにじみ出てます。

やりたかったけど出来なかったこと

  • 画像POSTで変換。GETの時は変換しないとか
  • timelineのコードで何度もmysqlにポーリングしてる所はevent emitterとか使ってもう少しイベント駆動なコードにするとか
  • tmpfsに画像の一時ファイルを配置するとか(やっても効果ないかも)
  • targetオプションで複数エンドポイントを指定する*1
  • image-diffツールをちゃんと使って変換がうまくいくかどうか確認するとか

WebDAV使うとか全然頭になくて、1位の方々との引き出しの差も見せつけられた感じだった。

まぁでも

node.jsを使ったチームが僕らしかいない中で、そこまで悪いスコアにはならず、そこそこnode.jsのポテンシャルは見せられたかなーと。
(もちろんfailしてるからなんにも言えないんですが。。。)*2

後はnewrelic相当便利だと思いました。あの手軽さで手に入れられるprofileとしてはかなりいいなーと。
もっと見方を勉強しておくべきだったかもしれませんが、事前に素振りでnodetimeやnode.jsのv8-profilerも見てたんですが、
他のprofilerより見やすかったので、指針は立てやすかったなーと。

御礼

運営の方々へ
isuconの設営から問題作成まで、非常に楽しい問題を作成していただき、運営をしてもらった LINE、kayac、DATA HOTEL の方々には大変感謝しております。ここまでの問題を作成するのは本当に大変だったと思いますし、勉強になりました。

@hokaccha さん、 @hakobera さんへ
楽しかったです!!お二人がいなかったらここまで来れていないですし、非常に勉強になりました。
また来年も出ましょう!!

*1:そもそもnginxでフロントさばく構成にしてたけど、それエンドポイント複数作っておいて、benchツールでtarget複数指定すれば同じことじゃねー?みたいな事は終わった後、1位の人たちの話聞いて思った。

*2:node.jsバンザイなだけじゃなくて、不利点もたくさんあって、imagemagick-nativeのインストールにハマったり、使っている人が少ないから故にリファレンス実装にも穴があったりとあるので、次回以降どうしようか、、、みたいな話は出ましたが。