mesimasi Logo

ISUCON11本戦で学生1位になった

ISUCON11本戦で学生1位になった_thumbnail

「雑談係」として さんぽしさん(@sanpo_shiho) とささん(@tosa_now) とISUCON11本戦に出場して「学生1位(全体9位)」を取れました!!

ちなみに予選の記事は こちら です.

本戦のリポジトリは こちら です.

前提

構成

  • 1台目(App:PDF関係のやつ)
  • 2台目(DB)
  • 3台目(App:PDF以外のやつ)

役割

まし:DB -> App さんぽしさん: インフラ周り -> App とささん: App

やったこと

他のチームメンバーがやったことはブログに書いてくれると思うので,僕目線で書いていきます.

10:00 ~ 10:30くらいまで

git管理・gotopの導入・マニュアルを読む

まずは 3台全てで ~/webapp以下をgit管理しました.また,topを更に見やすくしたツールであるgotopを導入しました. この間にalpやpt-query-digest,pprofなどをさんぽしさん,とささんが用意してくれました.

10:30~11:00くらい

admin prepare対策をする

slow-queryログを見るとadmin prepareがかなり多かったので,

mysqlConfig.InterpolateParams = true

を追加しました.また,ついでに

db.SetMaxOpenConns(30)
db.SetMaxIdleConns(15)

も雑に追加しました.期待してなかったんですがこれによりスコアが1万点近く上がったようです. ちなみに, admin prepare対策を知らなかったのですが他の人の予選記事を読んで知りました.ありがとうございます!

INDEXを貼れないか考える

slow-queryログを見ながらINDEXを貼る箇所を探していましたが今回は外部キーが多く,貼っても効果なさそうでした.

getGradesのIFNULL(SUM(…))をgenerated columnでできるんじゃないか?と勘違いする

IFNULL(SUM(…))を使っているクエリが上位に2件くらいありました.あまりコードを読んでいなかったので「成績にNULLがあるからIFNULLしてるんだ!」と勘違いして,nullじゃない成績をgenerated columnで持とうとしました.しかし,「SUMの結果がNULLになる場合があるのでIFNULLしている」ものだったので無理だと気づきました.大事な初期時間を無駄にしてしまいましたね….

11:00~ 12:45くらいまで

ページネーションの改善

Coursesにページネーションがあり,パフォーマンスが悪いことで有名なLIMIT OFFSETを用いて実装されていました.これは以前にCyber Agenetさんのパフォーマンスチューニングコンテストに出た際に遭遇しており,ブログに残していました. 自分の書いた説明を見ながら取り組んだのですが,結構ケアレスミスを多く出して時間がかかってしまいました. この改善を入れてもあまりスコアが伸びませんでした.しかし,alpを見るとリクエスト数がかなり増えていたので「負荷は下がったがリクエストが増えたせいでスコアが伸びていない」と判断しました.

ちなみに実装しながらご飯を食べました.

11:30くらい

なんか気づいたら5万点近くになっていて,最初に8万円をとるという特別賞をもらえるのでは?とざわついていました.さんぽしさんがパッとAppとDBを分けてくれ,6万点近くまで上がったのですが8万点は遠そうだったので落ち着いて作業に戻りました….

13:00 ~ 15:00 くらいまで

announcementにもページネーションがあり,とささんがある程度実装してくれてたやつを引き継いで実装しました.こちらもなぜかバグらせて思ったよりも時間がかかってしまった….

15:00 ~ 15:20くらい

submissionの修正

なぜかsubmissionが原因でベンチが落ちるようになってしまっていたので,修正しました.原因としてはclassesがnilな場合分けをしていないことでした.

15:20 ~ 15:50 くらい

課題のpdf書き出しの改善

課題がアップロードされたら読み込んでpdfに書き出す処理がio.ReadAllとos.WriteFileを用いて実装されていました.これを以下のようにio.Copyを用いて 実装し直しました.

func WriteFileByBufio(dst string, file multipart.File, perm fs.FileMode) error {
	fp, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	defer fp.Close()
	writer := bufio.NewWriter(fp)
	_, err = io.Copy(writer, file)
	if err != nil {
		return err
	}
	return nil
}

io周りのパフォーマンス差についてはあまり知らなかったのですが,なんとなくbufferしてたりCopyしたほうが早いやろwってことで実装してしまいました.結果としては最悪ケースの所要時間が半分くらいになりましたがスコアにはあまり響きませんでした.

16:00 ~ 18:00 くらい

getGradesがボトルネックすぎる

この段階でDBのCPUが100%に張り付きまくっているのですが,getGradesのクエリがめちゃくちゃslow-queryログに出ていたんですが,解決が難しかったです.3人がかりであーだこーだと言っていて,さんぽしさんととささんが改善を加えてくれたのにあまり負荷が下がらず,悩みに悩んでいました….

UserCodesのキャッシュ

User.Codeは変更されないことに気づいたのでキャッシュしました.スコアに変化はなし…

登録コースの一括取得

GetRegisteredCoursesの中でN+1クエリが飛んでいたので一括取得するようにしました.これもスコアに変化はなし….

18:00 ~ 競技終了まで

残り時間がなくなってきて,改善を入れてもスコアが上がるどころか下がっていました.さんぽしさんが「ベストスコアに戻そう」と言ってくれたのでベストスコアのcommitがどこだったか必死に探し始めました.commitとスコアを結びつけておけばよかったと思いましたが後の祭りです…

なんとかベストスコアのcommitを見つけ,絶対改善につながる修正(ログ消しやバグ修正など)だけ取り込んで終了しました.本当は再起動試験をするつもりだったんですが時間がなくてできませんでした.Failしなくて本当に良かったですw

最後に

とにかくgetGradesを改善できず,DBのCPUが100%に張り付いていて点数が伸びなかったのがくやしいですね.ただ,昨年同じチームでISUCONに参加した際は予選で落ちてしまったのに,今年は本戦で学生1位を取れたのが本当に嬉しかったです.一緒に参加してくれたさんぽしさん,とささんはもちろん,運営の皆さん・今まで様々な知見をブログなどで共有してくださった皆さんなど,本当にありがとうございました🙏

ココ2年でパフォーマンスチューニング楽しい!になってしまったので,これからもISUCONはもちろんパフォーマンスチューニングの大会が開催されていくよう期待してます!!!

タグ

Loading...

利用規約

copyright ©めしまし All Rights Reserved.