Open11
ISUCON練習メモ
手元のM1 Macでprivate-isuの実行
Multipassのインストール
これは手動で。
サーバー構築
git clone https://github.com/matsuu/cloud-init-isucon.git
cd cloud-init-isucon/private-isu
multipass launch --name private-isu --cpus 2 --disk 16G --mem 4G --cloud-init standalone.cfg 20.04
sshでログイン
multipass shell private-isu
手元で普通にsshしたい場合
sudo install -m 600 -o $USER -g $(id -g) /var/root/Library/Application\ Support/multipassd/ssh-keys/id_rsa ~/.ssh/multipass.id_rsa
.ssh/config
Host isucon
Hostname <インスタンスのIP(後述)>
User ubuntu
IdentityFile ~/.ssh/multipass.id_rsa
IPは multipass list
でわかる(もしくはログインした状態で hostname -I
)。
$ multipass list main
Name State IPv4 Image
private-isu Running 192.168.64.12 Ubuntu 20.04 LTS
環境構築のログの確認
sudo tail -f /var/log/cloud-init-output.log
ベンチマーカの実行
cd /home/isucon/private_isu.git/benchmarker
./bin/benchmarker -u ./userdata -t http://$(hostname -I | perl -alE "say @F[0]")/
isucon userでsshできるようにする
whoami ubuntu
sudo cp -r .ssh /home/isucon/
sudo chown -R isucon.isucon /home/isucon/.ssh
sudo chmod 700 /home/isucon/.ssh
sudo chmod 600 /home/isucon/.ssh/authorized_keys
exit
ssh isucon@isucon
isucon 12でbenchの実行
cd bench
./bench -target-addr 127.0.0.1:443
初期スコア(M1 Pro 8コア)
SCORE: 3180
そのまま2回目
SCORE: 2346
え!?
multipasshが3つCPU100%なのが気になる…。
→その後Mac再起動して試したら4000台後半で安定。
nginxのaccess logをjsonにする
sudo vi /etc/nginx/nginx.conf
...
log_format json escape=json '{"time":"$time_iso8601",'
'"host":"$remote_addr",'
'"port":$remote_port,'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":"$status",'
'"body_bytes":$body_bytes_sent,'
'"referer":"$http_referer",'
'"ua":"$http_user_agent",'
'"request_time":"$request_time",'
'"response_time":"$upstream_response_time"}';
access_log /var/log/nginx/access.log json;
...
sudo systemctl reload nginx
sudo tail -f /var/log/nginx/access.log
alpの導入
# Install Go
sudo apt install -y golang-go
# Install alp
git clone https://github.com/tkuchiki/alp.git
cd alp/cli/alp
go build -o alp
sudo mv alp /usr/local/bin/alp
alp
alpの実行
# ログの退避
LOG_DATE=$(date +%Y%m%d%H%M)
echo $LOG_DATE
sudo mv /var/log/nginx/access.log /tmp/access_$LOG_DATE.log
sudo chown root:root /tmp/access_$LOG_DATE.log
sudo chmod 644 /tmp/access_$LOG_DATE.log
sudo systemctl reload nginx
# 集計
sudo alp json --sort sum -r -m "/api/player/competition/[\w-]+/ranking,/api/player/player/[\w-]+,/api/organizer/competition/[\w-]+,/api/organizer/player/[\w-]+/disqualified,/image/\d+" --percentiles="50,90,95,99" -o count,1xx,2xx,3xx,4xx,5xx,method,uri,min,max,sum,avg,p50,p90,p95,p99,stddev < /tmp/access_$LOG_DATE.log > /tmp/alp_$LOG_DATE.log
cat /tmp/alp_$LOG_DATE.log
# 結果
+-------+-----+-----+-----+-----+-----+--------+-------------------------------------------+-------+--------+----------+-------+-------+-------+--------+--------+--------+
| COUNT | 1XX | 2XX | 3XX | 4XX | 5XX | METHOD | URI | MIN | MAX | SUM | AVG | P50 | P90 | P95 | P99 | STDDEV |
+-------+-----+-----+-----+-----+-----+--------+-------------------------------------------+-------+--------+----------+-------+-------+-------+--------+--------+--------+
| 689 | 0 | 644 | 0 | 45 | 0 | GET | /api/player/competition/[\w-]+/ranking | 0.008 | 16.556 | 1138.462 | 1.652 | 0.020 | 8.040 | 9.648 | 16.516 | 3.571 |
| 433 | 0 | 394 | 0 | 39 | 0 | GET | /api/player/player/[\w-]+ | 0.004 | 16.472 | 704.476 | 1.627 | 0.068 | 6.948 | 9.792 | 15.804 | 3.419 |
| 86 | 0 | 77 | 0 | 9 | 0 | POST | /api/organizer/competition/[\w-]+ | 0.004 | 16.556 | 159.523 | 1.855 | 0.460 | 5.688 | 8.105 | 16.556 | 2.930 |
| 16 | 0 | 14 | 0 | 2 | 0 | GET | /api/admin/tenants/billing | 0.052 | 17.668 | 104.673 | 6.542 | 5.968 | 9.484 | 17.668 | 17.668 | 3.575 |
| 7 | 0 | 7 | 0 | 0 | 0 | POST | /api/organizer/players/add | 2.024 | 9.292 | 31.120 | 4.446 | 3.656 | 9.292 | 9.292 | 9.292 | 2.575 |
| 1 | 0 | 1 | 0 | 0 | 0 | POST | /initialize | 9.336 | 9.336 | 9.336 | 9.336 | 9.336 | 9.336 | 9.336 | 9.336 | 0.000 |
| 19 | 0 | 19 | 0 | 0 | 0 | GET | /api/organizer/billing | 0.004 | 4.529 | 8.533 | 0.449 | 0.012 | 3.052 | 4.529 | 4.529 | 1.181 |
| 37 | 0 | 36 | 0 | 1 | 0 | POST | /api/organizer/competitions/add | 0.004 | 0.260 | 1.496 | 0.040 | 0.028 | 0.076 | 0.172 | 0.260 | 0.046 |
| 97 | 0 | 87 | 0 | 10 | 0 | GET | /api/player/competitions | 0.000 | 0.048 | 0.984 | 0.010 | 0.004 | 0.024 | 0.036 | 0.048 | 0.012 |
| 11 | 0 | 6 | 0 | 5 | 0 | POST | /api/admin/tenants/add | 0.008 | 0.096 | 0.432 | 0.039 | 0.020 | 0.088 | 0.096 | 0.096 | 0.038 |
| 13 | 0 | 12 | 0 | 1 | 0 | POST | /api/organizer/player/[\w-]+/disqualified | 0.004 | 0.020 | 0.128 | 0.010 | 0.008 | 0.012 | 0.020 | 0.020 | 0.004 |
| 23 | 0 | 23 | 0 | 0 | 0 | GET | /api/organizer/players | 0.004 | 0.016 | 0.124 | 0.005 | 0.004 | 0.012 | 0.012 | 0.016 | 0.004 |
| 1 | 0 | 1 | 0 | 0 | 0 | GET | /css/app.83b4c321.css | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | 1 | 0 | 0 | 0 | GET | /js/app.3a4ec98c.js | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | 1 | 0 | 0 | 0 | GET | /index.html | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | 1 | 0 | 0 | 0 | GET | /api/organizer/competitions | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
+-------+-----+-----+-----+-----+-----+--------+-------------------------------------------+-------+--------+----------+-------+-------+-------+--------+--------+--------+
alpのdiffを実行する
function alpdiff () {
PATTERN="/api/player/competition/[\w-]+/ranking,/api/player/player/[\w-]+,/api/organizer/competition/[\w-]+,/api/organizer/player/[\w-]+/disqualified,/image/\d+"
echo diff $1 $2
cat $1 | sudo alp json --sort sum -r -m $PATTERN --percentiles="50,90,95,99" --dump dumpfile1.yaml
cat $2 | sudo alp json --sort sum -r -m $PATTERN --percentiles="50,90,95,99" --dump dumpfile2.yaml
alp diff -r --percentiles="50,90,95,99" --show-footers -o count,1xx,2xx,3xx,4xx,5xx,method,uri,min,max,sum,avg,p50,p90,p95,p99,stddev dumpfile1.yaml dumpfile2.yaml
}
alpdiff /tmp/access_2022081215{22,59}.log
GoでRemoteでデバッグする
ssh isucon
でログインできる状態で vscodeのremote sshで接続する。
その状態で以下のファイルを生成。"program"
と"cwd"
は適宜合わせる。
.vscode/launch.json
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/webapp/go/cmd/isuports",
"cwd": "${workspaceFolder}/webapp/go",
}
]
}
systemdですでにgoのサーバーが起動しているので、stopしている状態で、vscodeで「F5」を押すとデバッグ可能な状態で起動する。あとはブレークポイントをvscode上で設定してbenchを回すとその箇所をデバッグできる。
sudo systemctl stop isuports.service
VSCode内で複数のGoプロジェクトを扱う場合 or go.modがVSCodeのワークディレクトリのカレントにない場合
settings.json
"go.toolsEnvVars": {
"GO111MODULE": "on"
},
"gopls": {
"experimentalWorkspaceModule": true
},
pt-query-digestの導入
sudo apt install -y percona-toolkit
kazeburo/query-digesterの導入
git clone https://github.com/kazeburo/query-digester
sudo mv query-digester/query-digester /usr/local/bin/
sudo chmod a+x /usr/local/bin/query-digester
集計
--
以降にmysqlへの接続情報を書く。
sudo query-digester -duration 80 -- -uroot -proot
[実験]slowqlの導入
今のところ主役にならなそうではあるが、気になったので使ってみる。
.bashrc
+ export PATH=$HOME/go/bin:$PATH
go install github.com/devops-works/slowql/cmd/slowql-replayer@latest
go install github.com/devops-works/slowql/cmd/slowql-digest@latest
digestの実行
約10倍高速だが、個人的にqt-query-digestの方が見やすい。
$ slowql-digest -top 20 -sort-by query_time -k mysql -f /tmp/slow_query_20220714235859.log
...
Query #14
Calls : 5268
Hash : 2ed3d496c9377606d9ed8b5c423ca9ee
Fingerprint : replace into id_generator (stub) values ('a');
Schema :
Min/Max/Mean time : 946µs/45.691ms/5.495ms
p50/p95 : 4.458ms/12.291ms
Concurrency : 83.5191%
Standard deviation : 3.858ms
Cum Query Time : 28.948143s
Cum Lock Time : 11.241749s
Cum Bytes sent : 0
Cum Rows Examined/Sent : 0/0
Cum Killed : 0
Query #15
Calls : 785
Hash : 5ae8aba57361bd167198c8bf075b8b5c
Fingerprint : select player_id, min(created_at) as min_created_at from visit_history where tenant_id = ? and competition_id = ? group by player_id;
Schema :
Min/Max/Mean time : 135µs/312.108ms/59.347ms
p50/p95 : 46.483ms/142.011ms
Concurrency : 134.4117%
Standard deviation : 44.86ms
Cum Query Time : 46.58779s
Cum Lock Time : 1.644ms
Cum Bytes sent : 0
Cum Rows Examined/Sent : 17160293/77470
Cum Killed : 0
replayer実行
slow queryに含まれるクエリを再実行してくれる。
が、クエリの内容によってはロックされて最後まで実行されなかった。
slowql-replayer -u root -p -h localhost -k mysql -f /tmp/slow_query_20220715000523.log -db isuports -no-dry-run
SQL error: Error 1213: Deadlock found when trying to get lock; try restarting transaction
SQL error: Error 1213: Deadlock found when trying to get lock; try restarting transaction
SQL error: Error 1213: Deadlock found when trying to get lock; try restarting transaction
ISUCON12予選問題の場合は、init.shを実行後であれば問題なく流れるのが期待値?
selectやinsertだけなどfilterして実行ができると良いのかもしれない。
sshrcの導入
自分の場合は .gitconfig
を設定することが多いので、一旦それだけ自動化した。
sshrcのインストール(ホストのみで実行)
wget https://raw.githubusercontent.com/cdown/sshrc/master/sshrc &&
chmod +x sshrc &&
sudo mv sshrc /usr/local/bin
.gitconfig用の設定
mkdir -p ~/.sshrc.d
cp .gitconfig ~/.sshrc.d
.sshrc
if [ $(hostname | grep isucon | wc -l) == 1 ]; then
echo 'sshrc: set config'
cp -r $SSHHOME/.sshrc.d/.gitconfig $HOME/.gitconfig
fi
sshrcの実行
ssh isucon12q
でログインできるのであれば
sshrc isucon12q
とすることで、 .gitconfig
の設置が完了する。