ハッカーズチャンプルーで模擬ISUCON
こんにちは。
一昨日、ハッカーズチャンプルーでのISUCON合宿が終了しました。
3日間で10時間くらいしか寝てないので多少お疲れ気味ですw
今回は3日目に行った模擬ISUCONの模様をダイジェストでお伝えしようと思います。
時間は本戦と同じの10:00~18:00の8時間。
参加チームは3つ。
・anpanman (ぼく・disk)
・fukumoto (マサ・ディックス)
・penpen(琉大情報工)
そして題材はこれ。
pixivの社内イスコン。
カタツイさん、ありがとうございます。
では見ていきましょう。
チーム戦になるので、サーバーにログインできるユーザーとしてdiskを追加する必要がありました。
具体的には、authorized_keysにdiskの公開鍵を追加しておくこと。
参照記事がこちら。
ここで手こずり1時間が経過www
この時点で他の2チームはすでにベンチマークを走らせています。
ちなみにチューニングなしでベンチ走らせた場合、Rubyでは3000点弱がスタート。
2.データベースのチューニング
DBの管理は「Sequel Pro」を使う。
ここではインデックスが貼られてなかったので、とりあえずcommentsテーブルにpost_idとuser_idというインデックスを貼っとく。
GUIでインデックス貼れるSequel Proめっちゃ便利。
さぼさんが提供してくれた参考サイト:
なぜ、SQLは重たくなるのか?──『SQLパフォーマンス詳解』の翻訳者が教える原因と対策 - エンジニアHub|若手Webエンジニアのキャリアを考える!
とりあえずここでベンチ走らせたら、3000点→10000点くらいに。
3.アプリケーションのチューニング
まずはUnicornのチューニング。
unicorn_config.rbを開き、worker_processesを4に設定。
これでunicornが連れてくる職人さんが4人に増えた。
次はapp.rb。
実はこのソースコードは何回も見ているので、どこがボトルネックになりそうかはわかっていた。それがこれ。
今回のキモであるmake_postsメソッド。
まずpostsというarrayを用意して、色々ごちゃごちゃかき回して最後にまたpostsに入れてる。
どんどんハッシュを大きくしているイメージかな。
そして最初にresultsという変数がeachで回っているので、そいつの宣言元に行ってみる。
あったあった。
DBからのデータの取り方がよくない。
この処理は「/」にアクセスしたときのもの。
そもそもpostsは1ページに20件表示することになっている。
POSTS_PER_PAGE = 20
あと、deleteされたユーザも考慮に入れてデータを取ってくるようにする。
また純粋なSQL文に書き換える。それがこれ。
get '/' do
me = get_session_user()
results = db.query('SELECT `posts`.`id`, `user_id`, `body`, `posts`.`created_at`, `mime`
FROM `posts`
JOIN `users` ON `posts`.`user_id` = `users`.`id`
WHERE `users`.`del_flg` = 0
ORDER BY `posts`.`created_at` DESC
LIMIT 20')
posts = make_posts(results)
erb :index, layout: :layout, locals: { posts: posts, me: me }
end
クエリのテストはSequel Proで。(もちろんちゃんと走りました)
ここでベンチ走らす。
10000点→23000点
うん、いい感じ。
4.ログファイルの監視設定
とりあえずnginx(女将さん)でもイジイジしとこうかと思ったが、DBにある画像データをpublicに逃がさなきゃ静的配信できないので、ひとまずは女将さんは後回し。
そこで最初に設定するはずのログファイルの監視設定を行う。
tailコマンドで監視できる。
・nginx
nginxのログは
/var/log/nginx/access.log
に吐き出される。
このログを、「alp」を使って整形する。
参考はこちら。
ISUCON 5でalpを使ってNginxのログを解析した話 - Masteries
alpとnginxを連携する作業が必要なのだが、最新版をインストールした場合、ltsvの設定は公式通りにやらないとうまく動かなかった。
動くとこんな感じ。
unicornはaccess.logとerror.logを監視する。
(今回ここはやってないので割愛。どこかで記事書きます。)
まずはgenaral_logをtailコマンドで監視できるように設定。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.2.3 一般クエリーログ
もう一つ。
「my profiler」というものを使ってスロークエリを監視する。
KLabさんのgithubに公開されているので、それを参考に。
またこちらも勝手にご紹介。
5.nginxのチューニング
やっときたきた女将さん。
今回ぼくがめっちゃイジイジしたかった女将さん。
ナイスバディにしてあげようと気合い入れて、さぁいざ!
まずはKLabさんの記事を参考にworker_processesを1に、keepaliveを32にしてみた。
ここでベンチ走らせると1000点くらい伸びた。
やっぱり静的配信実現してからじゃないと伸びなさそうと凹む。
ここまでで多分4時間くらいが経過。
6.ググる、焦る、終了
データベースに突っ込んである画像データを逃すことを優先し、diskにバトンタッチ。
しかし
なぜだかうまくできないwwwww
前日はちゃんとできてたのに.....。
途中アクシデントに見舞われ、githubは諦めることに。
diskの方もなかなか苦戦している模様。
とりあえずベンチ走らすが、スコアがほぼ0になる始末。
そんなこんなで、あーだこーだしているうちに18:00。
終了!
最終スコアがこちら。
さぼさんwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
残り時間半分くらいから参戦してこのスコア。
さすが、お師匠さんです。
ぼくら学生チームはというと、まぁ僅差ですねwww
どうやらこの差はベンチ走らす時間とタイミングの差らしい。
ネット環境によって多少の誤差は生じるとのこと。
7.模擬 ISUCONを終えて
正直、スコア的には満足いくものではなかった。
が、得るものはスコア以上に大きかった。
一つ目に、「ISUCONがどんな感じなのか」ということ。
意外にも8時間は短いような気がした。
ぼくの場合、めっちゃ飯食うし、うんこ何回もするのでどうにかしないと...。
二つ目、「ログファイルの設定の重要性」。
ぼくらはまだ経験が浅いので、直感でどこ触ればいいのかまだわからない。
そのガイドをしてくれるログファイルは、時間をかけてでも用意しておくべきだった。
目標は開始から1時間くらいで全て揃えられること。
三つ目、「やっぱりまだ全然力不足だね」。
「あれ、なんでここできないんだろう?」ということが多々あった。
正直難しいことはしてないんじゃないかと思ったりもしたが、やはりそこは基礎ができてない証拠。
また一から出直してきます。
また、今回ぼくの個人的な目標として、
「できるだけ多くのエラーにあたる」
があった。
まぁぼくの場合何してもエラー出るので、目標ってほどのものでもないが、ここの経験を得られたのはかなりよかった。
正直、動くもの作るより、エラー解決したりする方が好きなのかもしれない。
実りの多かった模擬ISUCON。
次回は15万点目指して、また一から精進します。