こんにちは@p1assです。
9 月 8 日に同じくCAMPHOR-の運営である tomoyat1 さんと ISUCON9 の予選に出場してきました。
結果は惨敗でしたが、来年に向けて今年やったことを備忘録として残しておきます。
事前準備
ガッツリしたことは何もしていないです。先日に 1 時間ほど、初動をどうするかの話し合いをしました。また、軽く pprof やスロークエリログ、nginx のアクセス解析の方法を調べました。
過去問で予行練習をしたかったのですが、時間がなくそのまま本番に突入しました。
当日
10:00 ルールを読む
tomoyat1 さんがサーバのインスタンス立ち上げを行っている間に予選マニュアルを読んでました。
「ユーザにあわせた商品の一覧を返すことで、購入の機会を増やすことができます。」という文章に疑問を持ちつつも、ひとまず全部を読みました。
10:17 webapp を git 管理する
インスタンスが立ったので、ソースコードを git 管理するようにしました。
この時点でローカルで開発ができるようになりました。去年は Go Module に対応していなくて大変だったらしいのですが、今年は幸いなことにgo.mod
があったので、特に戸惑うことなく環境を整えることができました。
10:?? Nginx の access log を吐くようにする & alp で解析できるようにする
初回ベンチマークを回す前に Nginx のアクセスログと MySQL のスロークエリログの設定(こっちは tomoyat1 さんが担当)をしました。
他にも app サーバと DB サーバの分割と netdata の準備を tomoyat1 さんがやってくれました。
11:00 初回ベンチ
2,310: イスコイン
netdata を見ると DB の負荷が 100%に張り付いていたので、SQL クエリを軽くしていこうという話になりました。
11:41 LIMIT 1 をつける
1 件しか取得しない SELECT 文に LIMIT 1 をつけました。
2,410 イスコイン: ちょっと増えた
12:37 getNewItems
の N+1 を潰す
alp で見ると頻繁に /new_items
や /new_items/*.json
が叩かれていたので、このハンドラーを読んでみると N+1 だったので、JOIN を駆使して修正しました。
2,310 イスコイン: ちょっと減った
12:53 pprof を導入
細かいプロファイルを取りたくなったので導入しました。
getNewCategoryItems
に一番時間が使われていたので修正することにしました。
13:20 getNewCategoryItems
と getTransaction
の N+1 を直す
自分がgetNewCategoryItems
を tomoyat1 さんがgetTransaction
を直しました。
2,710 イスコイン: 300 増えた
13:32 BcryptCost
を 1 にする
postLogin
の bcrypto の処理が重たかったので BcryptCost を 1 にしました。
後から気づいたのですが bcrypt のコストの最小値は 4 なので 1 にしても無意味です(ライブラリ側でデフォルトの 10 にされるため)。
14:26 getCategoryByID の SQL を 1 回で住むようにする
pprof で割合が大きかったgetCategoryByID
が SQL クエリを 2 回発行していたので一回で済むようにしました。
2,710 イスコイン: まさかのあまり変化せず
昼休憩
昼休憩です。近くのコンビニに買い出しに行きました。
items の GET を高速化しても商品の購入がスムーズにいかないと点数上がらないよねという話をしつつ午後の方針を決めました。
15:10 postBuy
で叩く外部 API を goroutine で叩くようにする
POST /buy
が地味に遅かったので外部 API を goroutine で同時に叩くようにしました。本当はトランザクション周りも良くしたかったのですが、あまり良いアイデアが思いつかずそのままにしました。
3,010 イスコイン: 3000 点台に載った
15:52 postComplete
のトランザクションを一部外す
本当にトランザクションを外していいのか分からなかったのですが、「駄目だったらベンチ落ちるやろ!w」ということで外しました。ついでに外部 API を goroutine で叩くようにしました。
3,310 イスコイン: 少し伸びた
16:04 BcryptCost
を 4 にする
BcryptCost
の最小値が 4 と気づいたので変更しました。
あまりスコアに変化はありませんでした。
17:20 新着一覧ページをパーソナライズする
「ユーザにあわせた商品の一覧を返すことで、購入の機会を増やすことができます。」という文章があったので、各ユーザが最後に購入したカテゴリと同じカテゴリを表示するようにしました。
3,420 イスコイン: 少し伸びた
17:22 campaign
を 1 にする & Nginx の設定を変更 by tomoyat1
これまでにcampaign
を 1 にするのを試していたのですが、500 系が多く返ってきて変更を躊躇っていました。
このタイミングで tomoyat1 さんが Nginx の too many connections が原因なことを突き止めて設定を変更しました。
4,310 イスコイン: めっちゃ伸びた!
17:47 インデックスを init.sh から貼るようにする
今まで DB のインデックスを直接貼っていたのですが、initialize で DROP しているので意味がないことに気づき、ベンチのスタート時にセットするようにしました。
5,610 イスコイン: 結構伸びた
18:00 ~ ポータルが落ちて延長戦 & ベンチを回す
色々とログを吐く設定をやめたりしてベンチを回したが点数が半分になりました。ワロタ
2,810 イスコイン: 😇
スコアの遷移
fail は沢山ありますが、基本は右肩上がりにすることが出来ました。 最後だけが悲しいです。
感想
初の ISUCON でしたがものすごく楽しかったです。他のチームがスコア伸ばしてるのを見ると負けられないぞという気持ちになりますし、色々と勉強になりました。
来年は本戦行きたいです!💪💪