Skip to content

Instantly share code, notes, and snippets.

@zawataki
Last active September 9, 2019 14:12
Show Gist options
  • Save zawataki/80ad3848f006c57470391526890eac8c to your computer and use it in GitHub Desktop.
Save zawataki/80ad3848f006c57470391526890eac8c to your computer and use it in GitHub Desktop.
ISUCON9 オンライン予選で敗退した

概要

2019/09/08に実施されたISUCON9のオンライン予選へ初めて参加した。
チームは自分一人。
競技で実施したことやハマったことなどを記録する。

前準備

過去問の振り返りブログを1つ読んだぐらい。
詳しく対策が書かれていたけど、それをあまり自分のものにする時間が取れず、結局活かせなかった。。。

11:30 開始

予選は10時開始だったが、朝は予定があったのでこの時間から着手した。
事前に運営から指示があって作ってあったインスタンス(※)を使うのかと思い、
そこへブラウザからアクセスするもWebアプリが表示されず。。。
悩みながら、マニュアルをしっかり読んだら、改めてインスタンスを作る必要があることに気づいた。
これで15分ぐらい悩んでた気がする。

 ※参考:ISUCON9 オンライン予選用 Alibaba Cloud でのイメージファイルの展開方法 : ISUCON公式Blog

11:45 マニュアルに目を通しつつアプリケーションの仕様確認

アプリのクオリティが高くて感動した。

12:00 サーバ探索

サーバにsshでログインし、ディレクトリを探索。
マニュアルに書いてあったログインユーザはrootだったが、rootのホームディレクトリにはアプリのソースコードらしきものが見当たらない。
なので、/homeディレクトリを確認すると、isuconという、いかにもなユーザのディレクトリを見つけた。
そのディレクトリを漁って、ソースコード諸々が入ったディレクトリをローカルPCにコピーした。
このとき、対象ディレクトリに含まれていた20000件の画像ファイルもコピーされそうになったので、
ソースコードとドキュメントが入ったディレクトリだけ個別でコピーした。

後から思ったのは、Visual Studio CodeのRemote Developmentプラグインで直接サーバ上のファイルを修正したり、Markdown形式のドキュメントを読むようにすればよかった。

12:20 デフォルトのスコアを確認

まずは、何もいじっていないデフォルト状態でのスコアを確認した。
結果は2120点。

12:25 サーバにインストールされているGoをバージョンアップ

Goはあまり触ったことなかったけど、ちょうど良い機会なのでGo実装を選んだ。

とりあえず、修正→ビルド→サービスへ反映、という一通りのサイクルを実践するために、
適当にAPIを1つ選んで適当にレスポンスを書き換えた。
GoのソースコードがあるディレクトリにMakefileがあったのでmakeを実行すると、 cannot find packageというエラーが出た。

以前Goを触ったときに、GOPATHを設定する必要があったことを思い出し、下記コマンドでGOPATHを設定。

export GOPATH=/home/isucon/go/

 ※/home/isucon/go/ディレクトリは、サーバ探索しているときにたまたま見つけた

再度、makeすると、また似たようなエラーで失敗。
エラーログを見る限りでは、GOPATHは設定できているっぽい。
ググったら、Go 1.12から取り込まれたGo Modulesという機能が使われている事がわかった。

 参考:Go Modules - Qiita

そこでgo versionを実行すると、1.10であることが判明。 そのため、Downloads - The Go Programming Languageから最新版のLinux用ファイルのURLをコピペし、以下の通り、サーバへインストールした。

# Download
wget https://dl.google.com/go/go1.13.linux-amd64.tar.gz

# Extract the downloaded file
tar zxvf go1.13.linux-amd64.tar.gz

# Move the extracted go directory
mv go /usr/local/

# Check that go binary exists
ll /usr/local/go/bin/

# Set PATH variable so that I can execute the go binary anywhere
export PATH=/usr/local/go/bin/:$PATH

# Check the go binary path
type -a go

# Check Go version
go version

これでGoが1.13になったので、改めてmakeすると無事に成功。
その後、systemctl restart isucari.golang.serviceを実行し、修正したAPIのレスポンスが意図したものに変わったことを確認できた。

マニュアルか何かで、サーバ再起動後に追試(スコア再測定)を行うことがあるということなので、/etc/bash.bashrcに以下の記述を追加した。

export PATH=/usr/local/go/bin/:$PATH
export GOPATH=/home/isucon/go/

これらの作業の途中で予定があったので下記のようなスケジュールでこなしていた。
 12:25 作業@自宅  13:30 外出準備  14:00 作業@電車移動中  14:15 別の予定

15:30 DBのインデックス作成

とりあえず、MySQLのスロークエリログを見ようと思ったけど、デフォルトでOFFだったし、あまり解析する時間も無さそうだったので、
アプリで実行するSQLクエリのwhere句で使われているカラムすべてにインデックスを張りまくる、という力技を実施した。

なお、この作業は前述した予定を済ませた後、次の予定まで1時間ほどあったので喫茶店でやってた。 16:25からは別の予定を済ませていた。

17:40 無駄なSQLクエリの実行を削減

とある関数内にて、一度categoriesテーブルを叩いた直後に、
取得したレコードの親カテゴリ名を取得するために再び同じテーブルを叩いている処理があった。 このテーブルはアプリ起動中に登録/更新/削除されないマスタテーブルなので、
親カテゴリのIDと名前をmapとしてデータ保持するようにした。
ただ、思い返すと、テーブル丸ごと保持するようにしたほうが良かったなーと反省。

以上の対策をして、17:50に3210点を獲得できたので、
試しにCampaignを0から1に変えてベンチマークを走らせると、エラーで失敗した。
最後に実行したベンチマークのスコアが最終得点になるので、
慌てて元に戻して、ベンチマークを走らせたところで、Portalサイトが落ちて、ベンチマークが失敗。 その後、Portalが落ちたことによって競技時間が10分延長されたので、 改めてベンチマークを走らせると何故か3,010点に減ってしまったところで競技終了。

18:10 コンテスト終了

最終得点は3010点。スコアがあるチームは430チームいて、そのうち265位。
超楽しかったから、来年はちゃんと予習も当日も時間を割いて、ガッツリ参加したい。
早速、沢山の人が振り返りブログを書いてるから、それを見て勉強しておこう。

なお、Twitterには投稿したが、
今回のオンライン予選のスコア一覧をスプレッドシートにまとめた。 https://docs.google.com/spreadsheets/d/1PUMn9hgJ45GptUjPiBJY3ZrdsgHYgsRqpVNWQoDJnss/edit?usp=sharing 誰でも見れるようにしてあるので、自分のチームの順位が気になる人はどうぞ。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment