これは2022/7/9にtraP内で開催した講習会の資料を外部公開に際して一部変更をしたものです
ISUCON初心者向け講習会を開催しました | 東京工業大学デジタル創作同好会traP
※優勝したり上位に入るためのテクニックは扱いません
「やったことがないことはやらない」は勝つためには重要
しかし、ISUCON初参加/web初心者は 「やったことがない」にぶつかるのは当たり前
大会の時間中に「やったことはないけれど、これで改善できるかもしれない」まで至れるのはよいこと
はじめてのことを試してみて、それで学びを得られたら十分参加の意義がある
どちらでもOK
チームで相談して選ぼう
同じ部屋に他チームもいるのはダメなので要注意
メリット
各自の自宅から通話をつなぎながら
各チームでDiscordやSlackを立てる必要がある
メリット
口頭での情報共有以外に、テキストで共有できる場所があるとよい
チームによって様々なので「正解」はない
ここではよくある(?)パターンを紹介するので、チーム内で方針を決めておくとよいです
玄人向け
常連チームでもそうそういない
どちらもISUCONの過去問練習、事前準備をがっつりやりこんでいる人
常連チームではそこそこいる
メンバー全員が各自で計測、分析、改善を行っていくスタイル
作業箇所が競合しないようにの管理、厳しい時の相談、タスクの受け渡しはちゃんとやっている
チームメンバー全員のレベルが高い&お互いの能力・思考がわかりあっている前提
初参加ではこれがおすすめ
「役割分担」といっても大まかなゆるっとしたもの
本番中は基本的に、Linuxコマンドを叩いて環境を操作しなければならない
よく使うコマンドがまとまった小冊子
「こういう操作をしたいけれどなんのコマンドを使えばいいかわからない」というときは、この本をペラペラ眺めてみると良い
ハッカーとしてサーバー上で操作をして進めていくゲーム
一部なんちゃってなコマンドもあるけれど、基本的な操作はLinuxコマンドと大体同じ
「コマンドを打つとめっちゃ文字が流れてくる」ことに慣れるのにおすすめ
実際にLinuxコマンドを使いながら問題を解いていく
全てのコマンドを覚える必要はないけれど、「こういうことができるコマンドがある」と知っておけるのは大事
ソースコードの管理・共有用のリポジトリは事前に作っておこう
必ずprivateリポジトリとして作成すること
競技中にpublicリポジトリに問題のソースコードをアップしてしまうと、失格になる可能性があります
以下の行為を特に禁止する。
- 予選の競技終了時間までに、競技の内容に関するあらゆる事項 (問題内容・計測ツールの計測方法など)を公開・共有すること(内容を推察できる発言も含む)
個人のprivateリポジトリを作って他メンバーをCollaboratorとして招待する形でOK
無料ユーザーの個人privateリポジトリは招待できる人数上限があるが、ISUCONチームメンバーの3人は問題なく招待できる
ベンチマークを回す前にやることとか
結構いろんな操作が必要なので、都度手打ちの実行をするのは厳しい
「ISUCON Makefile」で調べるといろんな人が公開しているのが出てくる
ハンズオンで使うMakefileも主要な操作をまとめてあります
「やることに困ったらここを見る」ができるように
特に「競技が始まったらまずやること」はまとめておこう
チートシートもいろんな人が公開しているので参考にしてみるとよい
ISUCON11予選(PISCON1回目の問題)を使います
oribe1115/traP-isucon-newbie-handson2022
このリポジトリをテンプレートにしてリポジトリを作成しておいてください
今回はpublic/privateどちらでもOK
テンプレートからリポジトリを作成する - GitHub Docs
上記のテンプレートリポジトリは今回のハンズオンに特化した内容になってます
今後使用してもらってもOKですが、他の問題ではそのまま使えないことに注意してください
含まれている問題
oribeがデモをするリポジトリ: https://github.com/oribe1115/traP-isucon-newbie-handson2022-demo
インスタンスが立ったら何はともあれベンチマークを回す
SSHで入るよりも前にやる勢いでよい
目的
以下、コマンドは基本的にサーバー上のホームディレクトリ(/home/isucon
)で実行してください
curl https://raw.githubusercontent.com/oribe1115/traP-isucon-newbie-handson2022/main/Makefile -o Makefile
make setup
適宜yes
やEnterを押して進める
ssh-keygen
で生成する鍵のパスフレーズは空でよいので、Enterを押して進める
privateリポジトリとのやりとりを円滑に行うためにデプロイキーを使用する
作成したリポジトリのSettings > Deploy Keysで登録する
登録する公開鍵はサーバー上での以下の出力結果
cat .ssh/id_ed25519.pub
git init
git remote add origin {作成したリポジトリのSSH用URL}
git pull origin main
error: The following untracked working tree files would be overwritten by merge:
Makefile
Please move or remove them before you merge.
Aborting
上記のエラーが出た場合は以下のコマンドでMakefileを削除してからpullをやり直してみてください
rm Makefile
今回は設定済みなのでスキップ
必要のないファイル、大容量なファイル(DBの初期データなど)をリポジトリに含めてしまわないよう、適切に設定する必要がある
git branch -m main
make set-as-s1
make get-conf
git add .
git commit -m "init"
git push origin main
競技のライブ配信で、競技開始時刻よりも前に流れ終わるように流れるので焦らずに見ておくとよい
ボトルネックや改善の仕方そのものの情報は出てこないが、アプリについてのドメイン知識の把握に有用
出題動画が用意されるようになったのはここ最近になってからです
予選の出題動画が用意されたのはISUCON11が初です
評判良かったし、多分今後も継続して用意されると思われます
ルールや環境の説明について書かれている
特に改善方針の決定に重要な箇所
問題のアプリ自体の説明が書かれている
アプリ独自の用語や機能を確認する
動いているアプリケーションが何かを確認する
sudo systemctl list-units --type=service
s1/etc/systemd/system/isucondition.go.service
を見てみる
webapp/sql/0_Schema.sql
こんな感じのデータを持ってるんだな〜とざっくり把握できればいい
isu.image
がLONGBLOB型で画像データがそのまま入ってそうでやばそうだけど、本当にボトルネックなのかはまだわからないので触らない
webapp/go/main.go
明らかに分量がやばいので頭から読もうとしない
ざっと「こんな関数があるんだな〜」って把握すれば十分
N+1っぽい多重for文があってもボトルネックかはまだわからないので触らない
main関数見てAPIの構成を把握しておくのはおすすめ
alpの設定にも必要な情報なので
postInitialize
もざっと見ておくと良い
プロセスごとのcpu使用率、メモリ使用率をリアルタイムで確認できる
top
サーバーのリソースの使用具合をリアルタイムで確認できる
(開発終了してるらしいので別のに乗り換えた方がいいのかもしれない)
dstat
systemdで動いているサービスのログを確認できる
make bench
を実行すると、最後にjournalctlが立ち上がった状態になる
tkuchiki/alp: Access Log Profiler
アクセスログを解析するツール
オプション指定で同種のリクエスト(e.g. URI内のIDだけ違う)を束ねることができるので便利
どのAPIにどれくらいリクエストが来ていて、それがどのくらい重いのかを調べるのに使う
make alp
s1/etc/nginx/nginx.conf
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
+ log_format ltsv "time:$time_local"
+ "\thost:$remote_addr"
+ "\tforwardedfor:$http_x_forwarded_for"
+ "\treq:$request"
+ "\tstatus:$status"
+ "\tmethod:$request_method"
+ "\turi:$request_uri"
+ "\tsize:$body_bytes_sent"
+ "\treferer:$http_referer"
+ "\tua:$http_user_agent"
+ "\treqtime:$request_time"
+ "\tcache:$upstream_http_x_cache"
+ "\truntime:$upstream_http_x_runtime"
+ "\tapptime:$upstream_response_time"
+ "\tvhost:$host";
- access_log /var/log/nginx/access.log main;
+ access_log /var/log/nginx/access.log ltsv;
コピペ元: https://github.com/tkuchiki/alp#nginx
alpでの出力用の設定はtool-config/alp/config.yml
pprof package - net/http/pprof - Go Packages
Go言語用のプロファイリング可視化ツール
アプリケーション内でどこにどのくらい時間がかかっているのかを確認するのに使う
ベンチマーク中にmake pprof-record
で計測
make pprof-check
でWebUIによる閲覧
WebUIでの閲覧時にはポートフォワードが必要
# ローカルで実行
ssh -L 8090:localhost:8090 isucon@{グローバルIP}
webapp/go/main.go
import文に追加
import (
_ "net/http/pprof"
...
)
main関数に追加
func main() {
go func() {
log.Fatal(http.ListenAndServe(":6060", nil))
}()
...
}
スロークエリーログの解析に使う
スロークエリーログ: DBで実行されたクエリのうち実行に時間がかかったもののログ
make slow-query
s1/etc/ysql/mariadb.conf.d/50-server.cnf
- #slow_query_log_file = /var/log/mysql/mariadb-slow.log
+ slow_query_log_file = /var/log/mysql/mariadb-slow.log
- #long_query_time = 10
+ long_query_time = 0
[mariadb]
+ slow_query_log
実演
ベンチマークを回す前には必ずmake bench
を実行する
リモートリポジトリの設定まではツールの導入と同じ
pullをすると以下のエラーが出てしまうので
error: The following untracked working tree files would be overwritten by merge:
Makefile
webapp/.gitignore
webapp/NoImage.jpg
webapp/ec256-public.pem
...
これで解決(力技)
git fetch origin main
git reset --hard FETCH_HEAD
git branch -m main
make set-as-s2
make get-conf
git add .
git commit -m "s2 init"
git push origin main
2台目で操作
make access-db
でデータベースに入れる
# データベース接続ユーザーの確認
mysql> SELECT host,user,password FROM mysql.user;
mysql> CREATE USER 'isucon'@'%' IDENTIFIED BY 'isucon';
mysql> GRANT ALL ON *.* TO 'isucon'@'%' WITH GRANT OPTION;
mysql> SELECT host,user,password FROM mysql.user;
mysql> CREATE USER '{ユーザー名}'@'{許可するホスト}' IDENTIFIED BY '{パスワード}';
mysql> GRANT ALL ON *.* TO '{ユーザー名}'@'{許可する}' WITH GRANT OPTION;
ISUCONなのでワイルドカード(%
)を使って任意のホストからのアクセスを許可する設定にしてしまってOK
DBのport(MariaDBのデフォルトportは3306)を外部に対して開けていなければ攻撃される心配はないです
s2/etc/mysql/mariadb.conf.d/50-server.cnf
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
- bind-address = 127.0.0.1
+ bind-address = 0.0.0.0
s1/home/isucon/env.sh
- MYSQL_HOST="127.0.0.1"
+ MYSQL_HOST="{2台目のプライベートIPアドレス}"
MYSQL_PORT=3306
MYSQL_USER=isucon
MYSQL_DBNAME=isucondition
MYSQL_PASS=isucon
POST_ISUCONDITION_TARGET_BASE_URL="https://isucondition-1.t.isucon.dev"
SERVER_ID=s1
ベンチマークを回す前に両方のリポジトリを最新にする&make bnech
を実行するのを忘れずに
2022/7/22: ハンズオンで使用するMakefileでログローテーションがうまく行えていなかった問題を修正しました