ISUCON12予選練習の備忘録
環境構築
貧乏社会人なのでWSLで環境を構築した
感謝👏
事前情報収集
traPの常連さんのリポジトリと、サークルブログが非常に参考になる
リポジトリ: https://github.com/oribe1115/isucon12-qualify
ブログ: https://trap.jp/post/1640/
いざ実食
systemdで起動するサーバをgoに変更し、とりあえずbenchを回してみる
~省略~
[ADMIN] 06:33:45.439935 負荷走行を終了しました
[ADMIN] 06:33:46.440691 ScenarioScoreMap: map[string]int64{
"AdminBilling": 6,
"AdminBillingValidate": 65,
"OrganizerNewTenant": 82,
"OrganizerPeacefulTenant": 0,
"OrganizerPopularTenant": 72,
"Player": 193,
"PlayerValidate": 176,
"TenantBillingValidate": 189,
}
[ADMIN] 06:33:46.440786 WorkerCount: map[string]int{
"AdminBillingScenarioWorker": 1,
"AdminBillingValidateWorker": 1,
"NewTenantScenarioWorker": 1,
"PlayerScenarioWorker": 26,
"PlayerValidateScenarioWorker": 1,
"PopularTenantScenarioWorker": 1,
"TenantBillingValidateWorker": 1,
}
06:33:46.440812 Error 0 (Critical:0)
06:33:46.440828 PASSED: true
06:33:46.440831 SCORE: 783 (+783 0(0%))
[ADMIN] 06:33:46.440950 score.ScoreTable{
"GET /api/admin/tenants/billing": 9,
"GET /api/organizer/billing": 5,
"GET /api/organizer/players/list": 10,
"GET /api/player/competition/:competition_id/ranking": 135,
"GET /api/player/competitions": 38,
"GET /api/player/player/:player_name": 138,
"POST /api/admin/tenants/add": 2,
"POST /api/organizer/competition/:competition_id/finish": 9,
"POST /api/organizer/competition/:competition_id/score": 12,
"POST /api/organizer/competitions/add": 14,
"POST /api/organizer/player/:player_name/disqualified": 3,
"POST /api/organizer/players/add": 3,
}
[ADMIN] 06:33:46.441015 ScenarioCount: map[bench.ScenarioTag]string{
"AdminBilling": "count: 1 (error: 0)",
"AdminBillingValidate": "count: 2 (error: 0)",
"OrganizerNewTenant": "count: 1 (error: 0)",
"OrganizerPeacefulTenant": "count: 0 (error: 0)",
"OrganizerPopularTenant": "count: 1 (error: 0)",
"Player": "count: 26 (error: 0)",
"PlayerValidate": "count: 4 (error: 0)",
"TenantBillingValidate": "count: 1 (error: 0)",
}
何度か試した後の記録だがソースは触ってない
本番ではスコアしか見えないので、その想定で触っていく
推測するな、計測せよ
とりえあず遅いリクエストを計測するためnginxの設定を済ませ、alpをインスコし、計測をした
alpのconfigは本番では当然自分で記載する必要があるが、お手軽に始めるため常連さんの設定をパクらせていただく
sudo rm /var/log/nginx/access.log && sudo service nginx restart
でアクセスログ削除 & nginx再起動した後、ベンチを回し、alpで集計する
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
| COUNT | 5XX | METHOD | URI | MIN | MAX | SUM | AVG | P99 |
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
| 281 | 0 | GET | /api/player/competition/[0-9a-f]+/ranking | 0.030 | 30.000 | 1024.270 | 3.645 | 30.000 |
| 22 | 0 | POST | /api/organizer/competition/[0-9a-f]+/score$ | 0.930 | 30.000 | 201.890 | 9.177 | 30.000 |
| 7 | 0 | POST | /api/organizer/players/add$ | 4.150 | 30.010 | 98.310 | 14.044 | 30.010 |
| 11 | 0 | GET | /api/admin/tenants/billing | 4.500 | 19.310 | 93.770 | 8.525 | 19.310 |
| 204 | 0 | GET | /api/player/player/[0-9a-f]+$ | 0.010 | 0.190 | 5.050 | 0.025 | 0.140 |
| 14 | 0 | POST | /api/organizer/competitions/add$ | 0.050 | 0.830 | 2.720 | 0.194 | 0.830 |
| 1 | 0 | POST | /initialize$ | 2.340 | 2.340 | 2.340 | 2.340 | 2.340 |
| 12 | 0 | POST | /api/admin/tenants/add$ | 0.010 | 0.490 | 1.260 | 0.105 | 0.490 |
| 5 | 0 | GET | /api/organizer/billing$ | 0.000 | 0.700 | 1.010 | 0.202 | 0.700 |
| 8 | 0 | POST | /api/organizer/competition/[0-9a-f]+/finish$ | 0.020 | 0.080 | 0.300 | 0.037 | 0.080 |
| 5 | 0 | POST | /api/organizer/player/[0-9a-f]+/disqualified$ | 0.030 | 0.040 | 0.150 | 0.030 | 0.040 |
| 28 | 0 | GET | /api/player/competitions$ | 0.010 | 0.020 | 0.140 | 0.005 | 0.020 |
| 8 | 0 | GET | /api/organizer/players$ | 0.000 | 0.010 | 0.020 | 0.003 | 0.010 |
| 1 | 0 | GET | /css/app.83b4c321.css | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /js/app.3a4ec98c.js | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /index.html | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /api/organizer/competitions$ | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
とりあえずalpでの集計は出来たっぽい、明らかに遅いエンドポイントがあるのでそこから改善していく
とりあえず GET /api/player/competition/[0-9a-f]+/ranking
が重たいことが分かるのでそちらを改善していくことにする
ソースを読むと典型的なN+1なので直す。playerもplayer_scoreも幸い同じsqlite3上にあるのでJOINが使えるので1発で取ってくるSQLを書いた
ついでにMySQLに対してslow query logを出力させるように設定
ベンチ後のalp出力
cat /var/log/nginx/access.log | alp json --config config/alp.yml
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
| COUNT | 5XX | METHOD | URI | MIN | MAX | SUM | AVG | P99 |
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
| 251 | 0 | GET | /api/player/competition/[0-9a-f]+/ranking | 0.020 | 26.680 | 1404.200 | 5.594 | 26.670 |
| 28 | 0 | POST | /api/organizer/competition/[0-9a-f]+/score$ | 2.840 | 26.650 | 233.970 | 8.356 | 26.650 |
| 185 | 0 | GET | /api/player/player/[0-9a-f]+$ | 0.050 | 20.760 | 154.830 | 0.837 | 20.500 |
| 7 | 0 | POST | /api/organizer/players/add$ | 7.340 | 21.270 | 87.590 | 12.513 | 21.270 |
| 21 | 0 | GET | /api/admin/tenants/billing | 1.460 | 20.990 | 78.710 | 3.748 | 20.990 |
| 1 | 0 | POST | /initialize$ | 3.280 | 3.280 | 3.280 | 3.280 | 3.280 |
| 20 | 0 | POST | /api/organizer/competitions/add$ | 0.020 | 0.280 | 1.960 | 0.098 | 0.280 |
| 12 | 0 | POST | /api/admin/tenants/add$ | 0.010 | 0.190 | 1.090 | 0.091 | 0.190 |
| 7 | 0 | GET | /api/organizer/billing$ | 0.010 | 0.250 | 0.490 | 0.070 | 0.250 |
| 14 | 0 | POST | /api/organizer/competition/[0-9a-f]+/finish$ | 0.020 | 0.050 | 0.380 | 0.027 | 0.050 |
| 45 | 0 | GET | /api/player/competitions$ | 0.010 | 0.060 | 0.350 | 0.008 | 0.060 |
| 6 | 0 | POST | /api/organizer/player/[0-9a-f]+/disqualified$ | 0.020 | 0.040 | 0.150 | 0.025 | 0.040 |
| 13 | 0 | GET | /api/organizer/players$ | 0.010 | 0.030 | 0.060 | 0.005 | 0.030 |
| 1 | 0 | GET | /js/app.3a4ec98c.js | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /index.html | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /css/app.83b4c321.css | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /api/organizer/competitions$ | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
+-------+-----+--------+-----------------------------------------------+-------+--------+----------+--------+--------+
何かあんまり変わってない、別にボトルネックがありそう
SQLite側に以下のようにINDEXを貼ってみる
既存のテナントDBに対してINDEX作る作業は30秒以内で終わるっぽく、init.shに書いても間に合うっぽい
Go側でテナントDB作るときにINDEXも同時に作るようにした
CREATE INDEX competition_idx ON competition(tenant_id);
CREATE INDEX player_idx ON player(tenant_id);
CREATE INDEX player_score_idx ON player_score(tenant_id, player_id, competition_id);
その後のalp
cat /var/log/nginx/access.log | alp json --config config/alp.yml
+-------+-----+--------+-----------------------------------------------+--------+--------+----------+--------+--------+
| COUNT | 5XX | METHOD | URI | MIN | MAX | SUM | AVG | P99 |
+-------+-----+--------+-----------------------------------------------+--------+--------+----------+--------+--------+
| 314 | 0 | GET | /api/player/competition/[0-9a-f]+/ranking | 0.020 | 28.640 | 1448.010 | 4.611 | 28.640 |
| 30 | 0 | POST | /api/organizer/competition/[0-9a-f]+/score$ | 1.990 | 28.630 | 240.100 | 8.003 | 28.630 |
| 160 | 0 | GET | /api/player/player/[0-9a-f]+$ | 0.010 | 16.730 | 117.740 | 0.736 | 16.700 |
| 7 | 0 | POST | /api/organizer/players/add$ | 7.210 | 24.250 | 99.630 | 14.233 | 24.250 |
| 20 | 0 | GET | /api/admin/tenants/billing | 1.220 | 16.300 | 74.740 | 3.737 | 16.300 |
| 1 | 0 | POST | /initialize$ | 13.190 | 13.190 | 13.190 | 13.190 | 13.190 |
| 20 | 0 | POST | /api/organizer/competitions/add$ | 0.060 | 0.270 | 2.100 | 0.105 | 0.270 |
| 12 | 0 | POST | /api/admin/tenants/add$ | 0.020 | 0.290 | 1.750 | 0.146 | 0.290 |
| 52 | 0 | GET | /api/player/competitions$ | 0.010 | 0.080 | 0.610 | 0.012 | 0.080 |
| 14 | 0 | POST | /api/organizer/competition/[0-9a-f]+/finish$ | 0.020 | 0.040 | 0.370 | 0.026 | 0.040 |
| 7 | 0 | GET | /api/organizer/billing$ | 0.000 | 0.140 | 0.210 | 0.030 | 0.140 |
| 7 | 0 | POST | /api/organizer/player/[0-9a-f]+/disqualified$ | 0.010 | 0.050 | 0.190 | 0.027 | 0.050 |
| 13 | 0 | GET | /api/organizer/players$ | 0.010 | 0.030 | 0.090 | 0.007 | 0.030 |
| 1 | 0 | GET | /js/app.3a4ec98c.js | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /index.html | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /css/app.83b4c321.css | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
| 1 | 0 | GET | /api/organizer/competitions$ | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
+-------+-----+--------+-----------------------------------------------+--------+--------+----------+--------+--------+
やっぱり変わらない
計測しないとこうなるという教訓かも