ぷらすのブログ

初参加のISUCON9 予選で敗北した

#ISUCON#Go#MySQL#Nginx

こんにちは@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に一番時間が使われていたので修正することにしました。

12時57分時点のpprof

13:20 getNewCategoryItemsgetTransaction の 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 でしたがものすごく楽しかったです。他のチームがスコア伸ばしてるのを見ると負けられないぞという気持ちになりますし、色々と勉強になりました。

来年は本戦行きたいです!💪💪

← CyberAgentのAbemaTVでインターンしてきた話ドメインロジックと永続化処理を分離する設計改善を行って得られた知見 →
Topへ戻る