ISUCON7 挑戦記。
今日はISUCON7の本戦でした。 頑張りましたがなかなか力及ばず、全体11位 学生内3位という結果に。
来年、このブログを見て、がんばるぞいな気力を出すため、これから1年頑張って修行するため、今回の記録をブログに纏めておこうと思います。
全体11位 学生3位でした また一年修業します pic.twitter.com/xwj0fmG8KE
— namazu (@namazu510) 2017年11月25日
ISUCONでることにした。
なんかISUCONの記事を研究室メンバーが見ていて、その数日後に私が行こうよー、って言い出したら cut-ter 氏がいいよー? って返ってきたので、行こうぜーって流れに。
もう一人のメンバーが決まらなくて色々声をかけていたら、3年生のスーパーエンジニアyuuki君がいいよーって行ってくれたのでチーム結成!! 本当に行くことになりました。
チーム名は研究室のマスコットキャラクターの名前から付けました。
一応練習した
ISUCONは知ってはいたけれど、有効なテクニック等は全くもって分からない状態だったので、皆で休日に予選問題を解いたりして練習しました。 Vagrant + Ansibleで自動構成可能な物が配布されているのでそれを使ってみんなでやりました。
最初の内は
- Goが強いらしいからGoでGoしようぜ!! だけど俺はGo知らん(´・ω・`)
- Ansibleとかいうのようわからんくて、プロビジョニングでエラーでるんだけど?
- プロビジョニングできたのにベンチマーク上手く動かねぇ
- あーMySQL壊しちゃった-!
- あーGo分からん。 なにこれ。
とか散々でした。 私が構成は基本的に用意していたので、Ansibleを治したりしている内にAnsibleがある程度分かるようになりました。 今では、某所のサービスも構成はすべてAnsibleで管理しています。 このISUCONの練習からAnsible使えるようになるきっかけを得られました。
私とcut-ter氏はGoできないマンだったので、Goのお勉強をある程度しました。 その結果なんとか動くコードは書けるようになりました。 GoにISUCONを機に触れることができて、実際にある程度書くことが出来るようになったこともISUCONに出て良かったなーって事になります。
予選
ちまちま問題を解きつつ、予選の日が来ました。 予選の問題を見て始めに思ったこと。
え なにこれ コード行数多くね? てかなんで複数台構成なの くそわろwww
まぁ気を取り直して問題を見ました。
予選に関して言うと、私たちのチームは力業でスコアを上げることに全力を注ぎました。
2台のWebサーバから追加されたプロフィール画像をDBサーバに保存し、表示はDBサーバから取って、きてそれを表示するという処理になっていました。
とりあえず静的ファイル配信をしてNginxのお世話になれば良い感じだろうと考え、DBサーバのとあるディレクトリをNFSエクスポートして、Webサーバ側でマウント。 保存処理はNFSのマウントポイントにファイルを書き出し、配信はそこをNginxで出すというのを提案しました。
この方法考えついたとき、俺頭おかしいと思いました。 でもまぁいいんじゃねぇの?ってとりあえず私がちゃちゃっとやりました。
そしたらスコアは上がったけど、Webサーバの外側NICが100Mbps*2(制限いっぱい)まで使い切っていました。 じゃあ3台で配信すればいいじゃんの結果3台 100Mbps * 3 で配信しました(笑)。
後になって思いましたが、 アホでした。
この力業配信で学生枠基準の突破水準は超えました。 社会人基準はやっぱちゃんと302しないとダメだったぽ。 あとはNginxのパラメタを弄ったりNFSのキャッシュを掛けたり色々していました。 ベンチマークをやるたびにスコアが倍近く変動し、Nginxのパラメタチューニング全く参考になりませんでした。。。
私がNginxのパラメータと無限に挌闘している中、他の二人はN+1をつぶしたり、キャッシュをしたり色々してくれていました。
最後NFSを使っていたせいか、再起動に失敗してPCが上がってこなくなりました。 運営さんに強制再起動を掛けて頂いて、最後5分で全力でシェル叩いて復旧した。
NFSは起動順序を制御できないISUCONでは禁じ手ですね。 深く心にしみました。
cut-ter氏と予選が終わってラーメンを食べに行っていたら、予選突破していたことを知りました。 やったね。
どうやればよかったか、予選好評で見てへー!!ってなりました。 知らんがなそんなん。 一つ賢くなりました。 こうやって学ぶ機会を提供してくれるのがISUCONのいいところですね。 実践的な新しい知見に気づかせてくれる。
本戦
起床チャレンジ
寝坊するところだった
— namazu (@namazu510) 2017年11月24日
危なかった。 7時にアラート鳴っててカーテン開けたんですけどそのまま二度寝。 8時30分に起きました。 ダッシュで新宿Go! なんとか間に合いました。
午前中
ゲームって来てふぁーってなりました。 websocketもちゃんと挑戦したことはなく、解析ツール等が手元にありませんでした。 リクエストTimeやメソッド毎の負荷のかかり方等をkataribeさんのお世話になり続けていたので、どうするか状態になりました。
ただ、オンラインゲームを支える技術(webdbさんの)を読んだことがあったので、今回の方針は見た瞬間すぐに分かりました。
- ゲーム状態のオンメモリ化
- パラレルワールド化(部屋ごとにサーバとかを完全に分けて処理)
素早く方針は固まり、お昼ご飯を食べ終わった頃には、各自で作業を始めていました。
今になって思う、ここまでの反省点として
第一に、kataribeが使えないと分かった時点で、websocketのリクエスト毎の時間をしっかり解析するコード等を午前中に仕込んだりするべきでした。 最初にメソッドの時間をちょろっと計っただけで始めてしまい、最後の方は、実際にどれくらいの部屋が、どのサーバで処理されてて、どのwebsocketのハンドラが時間かかってて、並列度はいくつかーとか全然分からない闇の中でした。 この状態で午後の4時間くらいをずっと過ごしてしまったのが痛手。 これをやっていれば、getStatusの時間 BIGINTとかにも気づけたはず。。。
第二として、これは事前準備の段階でやっていなかったのでどうしようもないですが、Goで動いてるバイナリのプロファイラを何か見つけておいて使えるようにしておくべきでした。 それぞれのメソッド、どの部分にどれだけCPU喰ってるとか、メモリアロケートとか把握全くしていなかったのでBIGINTに気づけなかった。
午後
午後1で、私が今回の失敗の要因No1をやらかしました。
オンメモリ化にあたって永続化と実装工数が少なくてすむ事を考えRedisを選択。 そこまではいい。 そのGo言語Clientとして、とりあえず見つけた
を放り込みました。私よく知らず入れたのですが、実は練習で使っていなかったClientライブラリらしいです(私がRedisを使うことは無かった)。 適当に私がこれでええやろって入れて突っ走りました。
結果として、私の所は簡単な処理で良かったので問題なくできたのですが、AddISUとbuyのオンメモリ化の作業がライブラリが簡素すぎるせいで相当難航し、バグ取り終わらず最後までマージできない&無限に時間を消費という結果を生み出しました。
コアな部分のライブラリはみんなの合意をもっとしっかり取るべきでした。
その後DBの無駄な問い合わせ等に関してはひたすらキャッシュを行い、DBへのリクエストを削りました。
getStatusのDBクエリに関してはつぶしたものの、BIGINTは頭から飛んでたのもあって、全く対応をしていない状態でした。
最終的には
- ある程度オンメモリ化
- オンメモリ化でAddISUとかBuyとか失敗してそのへんはクエリしてた
- 部屋ごとに分散はGood
という状態でした。 スコアは16003
オンメモリ化の工数をバカみたいに増やしたのが完成したものに響いてる。
なまずんは基本的に本番に弱い。ここ4年くらい、いや生まれてからずっと本番で上手くいった試しが無いような気がする。 つらいさん。
感想
私は来年は社会人なので、チームとかどうなるかなーって。 ただ沢山の刺激を受けて、何が足りないかとか、記述出来ないほどに感じたのでまた1年修行します。
大学でISUCONみたいなのやったら楽しそうです。 企画したいなーって。 12,3チームくらい集まらないかな? 無理かー?
さいご
ISUCON、得るものも多く、楽しかったです。 一緒に頑張ってくれたチームメンバ&運営様ありがとうございました!!。