dev.toについての記事を書いた
ここ最近ずっとdev.toのことばかり考えてる。 個人的にパフォーマンスチューニングがプログラミングの中でも断トツで楽しい。
ISUCON7 競技者として、コーチとして、出場してきました
このブログでもいくつか記事を書いている通り半年間、沖縄のノンプログラマーな学生3人にISUCONを通してプログラミングを学び、それをもとに就職活動しよう、みたいなプロジェクトをやってきました。今回はその半年間の集大成としてのISUCONに参加してきた、というやつです。
競技者として
まずは競技者として、手短に。ISUCON7に「okinawa.rb」というチーム名で参加してきました。結果としては、スコア的に敗退、最終のbenchでもfailしてしまい惨敗でした。
名前の通り okinawa.rbに普段参加しているメンバー(@tompng, @siman-man)で出場しました。構成としてはぼくが、インフラ周りを触って、ぺんさんとしーまんさんにアプリケーションコードを見てもらう感じでやりました。今回のアプリについては他の方もたくさん記事を書かれているので省略しますが、アプリケーションコードの具合ではかなりいい線言ってるんじゃないかと思ってます。ぺんさんとしーまんさんのRubyへの知識や引き出しの多さ、手の速さは本当にすごくて、僕が手を出そうと思ったらすでに着手してる、すでに完成してるという具合でアプリケーションコードほとんどおまかせしていました。題材の特性上nginxが今回の一番のボトルネックだったところを自分が解決できなかったのでここさえどうにかなればいい線言ってたのではと思うとくやしい思いです。だけど普段から触ってないので知識不足が根本的な原因だと考えると単純に力不足だったなぁという印象。競技が終わったあとのdiscordやtwitterでの感想戦は本当に勉強になりました。
沖縄でもぺんさんやしーまんさんのようなハイパーなエンジニアがそばにいるというのは励みになるし、来年も機会があれば出場できたらなぁと思います。インフラ周りの知識をもっともっと勉強したいなぁと思う大会でした。
ISUCONを支えて頂いている全ての関係者の方に感謝します。ありがとうございました。
コーチとして
最初にも書きましたが、半年間じゅり、まさよし、福地、だいすけにISUCON予選を突破するためにwebプログラミングを教えてきました。それぞれ「仕事ください」、「まさ」として出場して、結果としては敗退という形になりました。
この半年間の方針として教えてきたことは
- webのベースとなる基礎知識をちゃんと付ける
- 数値を計測して、それをみて改善を行う
- nginxやmysqlの最低限の設定を覚える
- 静的ファイルはnginxに担当させる
- DBのインデックスを貼る
- N+1を解決する
とwebアプリケーションのチューニングにおける基礎中の基礎をしっかりやる。それをちゃんと時間内にやることができれば学生枠での予選突破はできるんじゃないかという前提でやってきました。しかし今回のアプリケーションはISUCON7 予選問題の公開と解説にもあるように、
倍率が高くなった現代のISUCONにおいては、多くの参加者にとって予選こそがISUCONになるということを念頭に、ISUCONの醍醐味で予選でまだやってないのはなんだろうと考えたときに思いついたのが複数台構成でした。
と複数台構成になっていて、かつ裏の設定ではCDNを通してアプリケーションにアクセスが来ているという前提のアプリケーションになっててこれは例年でいうと本戦相当のかなり複雑なアプリケーションになっていました。CDNが前段にあるというシチュエーションを経験したことがなく、かつアプリケーション側のボトルネックはAjaxで来るリクエストだったと言うものもありRuby側でのprofilingも困難な状況、などなど今でやってきた基礎知識では想定されていない問題が出てしまい手も足もでないという形になってしまいました。
これは僕の読みとして
- 複数台構成は予選では来ない
- 予選はわりとベーシックな構成で基礎をちゃんとやっていれば予選突破できそう
- nginxやmysqlでのトリッキーな出題はあまり来ないのでは
とかが外れた形になって申し訳ないという感じです。僕のnginxの知識の少なさや大規模サービスでCDNを使った経験が無いことが、nginxについて深く教えれなかった事は責任を感じてたりします。。
とは言え、往年のweb開発者でも今回の問題を解決できず爆死しているのを見るあたり、半年間の知識でこんなの解決できるかよって感じなのでしょうがないとしか言いいようがないかも、というのもあります。
当日やってるのを見て
僕は土曜日に参戦したので、日曜日はまさチームの後ろ姿を見ながら仕事してました。競技中はヒントを与えることはできないので後ろから見守りる形にでしたが、、あぁそこ違う、とか、お、よく気がついたなとか思ったりしてました。半年前はプログラミングをほぼ未経験だったことを考えると、ISUCONのコードをチューニングしている姿を見るとよく半年でここまで来たなぁ、という思いがあって感慨深いなぁと思ったりしました。いま、3人のブログの4月ぐらいの投稿から見直すとだいぶ無知だった状態から少しずつ着実に成長している姿が見て取れて結構おもしいろいです。
今回の全体を通しての活動
結果は敗退となってしまったけど、この半年間で彼らにwebアプリケーションとは、プログラミングとは、エンジニアとはとか、エンジニア界隈の人々がどんな人達なのか、エンジニアの生き方とは、みたいなところを少し垣間見せる事は出来たんじゃないかなぁと思います。
まさよしは、今回の活動を通して、ハッカーズチャンプルーでLT登壇したり、CODEBASEで彼が感じたエンジニアという生き方を語ったり。就職活動としてはISUCON予選出場前にみんなのウェディングさんに内定もらったみたいです。Rubyist界隈としてginza.rb開催していたりRubyKaigiスポンサーをされていたりで、いい会社に内定もらえてよかったなぁと思います。
じゅりは、ISUCON夏期講習に参加して、そこで講師をされていた方がいる面白い会社のインターンに行ったりしたみたいです。彼的に大尊敬できる師匠がいる環境下でこそ輝ける感があるので、ぜひその会社に入ってほしいなぁとか思ったりしてます。(願望
福地は、予てから考えてたエストニア留学に踏み出すみたい?です。もともと就職活動前提で動いてないので今回の経験が今後どう生きるかはこれから次第だけど、自分がやりたいようにやるといいと思うよーという感じ。学生のうちから焦らなくても20代長いので好きにやるといいよと言うのが個人的な感想。
就職したいけど就職活動したくない、エンジニアとして働きたいとなんとなく思っているという3人と関わって、ISUCONを通して色々見せれたかなぁと思って個人的には満足してます。就職すると決めていた2人に関してはちゃんと正しい会社、正しい人たちに繋げることが出来たと思っててエンジニアとしてはちゃんと正しいトラックに載せれたかなと思ってる。地方の学生がエンジニアとしていい感じに就職する難しさを感じてるのでそれを今回はうまくやれたかなと思っててよかった。
とりあえずISUCONは一旦終わりなので、3人のやる気があれば次はRailsかLaravelとか教えていったり、アプリケーション書くバイトかなんか振ったりして実際の仕事につなげて行けたりすると楽しいかなと思ったりしてる。基礎をしっかりつけたのでここからWAFさわるとかなり学びがありそう。
学習の題材としてのISUCON
今回ISUCONに出場すると決めたのはわりと思いつきだったけど、webアプリケーションを理解するという意味でISUCONはしっかり基礎をつけないと戦えないというのもあり、OS, Webサーバー, Appサーバー, DB, アプリケーションをちゃんと着実に学ぶ機会があるので題材としてかなりいい感じだった。3人1チームでやるというのも良くて半年間、わりと長い期間3人で教えつつ支えつつでモチベーションを保つのに良かった。あと学習としてゴール、目的が明確なのは動機としてわかりやすくて良くて、スコアが数値として出るので他の人と比較ができるという点でもいい感じだった。
ISUCON最高
来年にむけて
また来年もISUCON出たいという学生が沖縄にいたら教えていきたいなぁと思ったりしてる。人数も3人から9人くらい?3チームくらい教えれるとおもしろいかなぁと思ったりする。けど時間的余裕を作る必要があるので、講師を複数にしたり、スポンサーとかいたりすると仕組みとしていいなぁと思う。
なので、出場したい学生募集してます。講師やりたいという方、またスポンサーやってもいいよという方、企業の方、いたら連絡ください。
ISUCON模試を開催して運営&参加してきた
沖縄の宜野湾市にあるプロトソリューションさんが運営するCODEBASEでISUCONの模擬試験を開催してきました。 ここ最近ぼくがISUCON, ISUCON行ってたら一緒にイベントやろうと言って頂いたので開催する形になりました。
今回、題材をいつも使わせてもらっているpixiv private-isuを今回も使おうかなーと思ってたのですが、周りで数回模試をやってたりすると参加者の半分ぐらいがすでに一度やったことある経験者が多かったのでせっかくの機会にまた同じものをやってもなーと昨日思いながらとtwitterのタイムライン見てたら、ふとISHOCON1 〜個人参加のISUCON練習コンテスト〜というのが開催されていることを知り、その題材となってるishocon1のリポジトリが公開されていたので、あれこれいけるんじゃねと思い急遽こちらを使うことにしました。
参考実装はRuby, Python, Goで用意されててEC2のAMIが公開されていたり、マニュアルがちゃんと書かれていたりで構築のハードルが低くて運営としてすごい助かりました。ISHOCONを作成して公開していただいてる @showwin さんに感謝です。
※AMIが公開されてるの利用者側としてはとっても重要なので用意してもらえると利用者としてはとてもやりやすく普及し易いと思いますのでやってみてもらえるといいのではと思いました。
運営としてやったこと
インスタンス構築
AWS EC2のインスタンスはCODEBASEさん側で用意してもらえる事になっていたので、参加チーム分作成していただきました。今回は8台のインスタンスを構築しました。ISHOCONでは競技用のアプリとbenchmarkerが1台の構成なのでチームに1台インスタンスという構成になります。
公開鍵の設定
参加者の方には事前にGithubへアカウント登録してもらい、各自公開鍵の設定をお願いしていました。今回はGithubの公開鍵を利用して、各サーバーに割り当てられた参加者と管理者の公開鍵を設定しました。
$ curl https://github.com/{saboyutaka,tompng,siman-man}.keys >> /home/ishocon/.ssh/authorized_keys
動作確認
各インスタンスに入り、マニュアルにかかれている手順でアプリを起動し、ベンチマーカーが動くことを確認しました。事前に @showwin さんに利用確認をした際に、一部バグが存在しているので修正してくださいということを伺ったので、その部分を全インスタンスに反映させました。
ポータル
ポータルは pixiv private-isu で利用するために公開されてるポータルを流用しました。
ポータルの構築自体はポータルの説明どおりに構築しました。ISHOCONのbenchmarkとポータルが必要とするJSONの形式が異なるためどうしようかなぁと思ったけど結局雑なスクリプトを使うことで対応しました。前日に急遽思い立って変更したのであまり時間がなかったのでまぁいいかなと。 ポータルではscoreとtimestampだけが利用されていたので、その形式でJSONを投げることにしました。
#!/bin/sh TEAM=$1 SCORE=$2 JSON="{ \"score\": ${SCORE}, \"timestamp\":{ \".sv\":\"timestamp\" } }" curl -X POST -d "${JSON}" "https://xxxxx.firebaseio.com/teams/${TEAM}.json"
これを全員にダウンロードしてもらい
./score.sh team名 12345
のように実行してもらう形にしました。点数は自己申告です(笑)
そのほか
これで環境構築はだいたいできたので、あとは開始の挨拶とレギュレーションの説明なんかを軽くしました。参加者の皆さんがISUCONについてご存じの方が多かったので負担がほとんどなかったので良かった。
参加者としてやったこと
運営準備がわりとスムーズに行えたので、競技開始時間から20分後くらいには競技に参加することができた。今回は okinawa.rbのメンバー(@tompng, @shiman-man)とチームで参加しました。2人がアプリケーションがっつりかける感じだったのでぼくはインフラ周り担当しますねーという感じでやった。
今回もおなじみのツール群を使いました。
時系列あまりちゃんと覚えてないので以下やったこと。
- webapp配下をgit repository化、githubにpush
- mysqldumpで競技用インスタンスのDBをdump
- ローカルでgithubからclone、dumpからDBを再現構築
- Rubyのバージョンアップグレード 2.2.3 -> 2.4.2
- bundle update
- nginx.conf, my.cnfをgit repository配下に移動
- おれおれMakefile
- alpのインストール
- myprofilerのインストール
- htop, tig, tree, pecoあたりをインストール
- nginxの設定
- 静的ファイルをnginxで配信(これは今回効果なかったっぽい)
- その他細かいやつ、秘伝のタレを利用
- mysqlの設定
- innodb_buffer_pool_size, query_cache あたりを中心に秘伝のタレを利用
- gooseを使ったmigration環境の構築
- 各テーブルのindexを貼る
- imagemagickを使って画像のresize
- sessionをmemcachedで管理
- nginx update 1.8.x -> 1.12.0
- mysql update 5.5 -> 5.6
- mysqlのデータベースをinnodb_file_per_tableするために一度DROPして再構築
- nginx, unicorn, mysqlをunix domain socket での通信に変更
- app.rbのいくつかのチューニング
- 定期的にhtop, alp, myprofilerの状況報告
- portalへのPOST
- benchmark回す担当
- ポストイット整理
実際のコード github.com
開始前にこれはやりたいなぁと思っていたものは一通り消化できたので満足。今回のアプリは画像をリクエストしてくるときにheaderを送ってきてくれてない?ぽくてnginx側でexpiresつけてたけどその後も普通にリクエスト投げてくるので304返せなかった。画像は400px幅しか使われていなかったのでリサイズしてみたところbenchmark通ったのでこれで行くことにした。N+1も削りつつ、ほとんどのDB問い合わせを@tompngさんがゴリゴリキャッシュしてくれてったおかげで爆速に。
結果優勝することができました!🎉🎉🎉
あまりアプリケーションコードそこまで読まなくておまかせしてたのでスコア取れたのは大部分 @tompngさんと@shiman-manさんのおかげ🙏🙏
学生チームのMK5(@d_ishitaka, @CodeHex, @maeken2010)と接戦してたけど、勝てて大人の尊厳をまもれてよかった。学生でここまでできるのやばい。
まとめ
今回もめちゃくちゃ楽しくやらせていただきました。運営、会場提供、イベント企画をしていただいたCODEBASEさん、題材のISHOCONを作成・公開していただいている@showwinさん、また参加していただいた皆さんありがとうございましたー!!
予選がんばりましょー!!💪💪💪