isucon練習記 private-isu 2度目
今回はnode実装で再挑戦
環境構築
ISUCONからクーポンが貰えたのでさくらのクラウドで作成
netplan周り何も分かってないけど書いてる通りで良かったんだろうか
code:いつもの
$ sudo mkdir -p /home/isucon/.ssh &&\
sudo cp ~/.ssh/authorized_keys /home/isucon/.ssh &&\
sudo chown -R isucon:isucon /home/isucon/.ssh
管理画面からホスト名が設定できたのでsudo hostnamectl set-hostname isu1は不要
GitHubが鍵が拾えるの地味に便利
とりあえずベンチ回す
code:json
{"pass":true,"score":0,"success":160,"fail":46,"messages":["リクエストがタイムアウトしました (GET /)","リクエストがタイムアウトしま
した (GET /favicon.ico)","リクエストがタイムアウトしました (GET /image/10000.png)","リクエストがタイムアウトしました (GET /image/8608.jpg)","リクエストがタイムアウトしました (GET /image/9200.jpg)","リクエストがタイムアウトしました (GET /js/main.js)","リクエストが タイムアウトしました (GET /js/timeago.min.js)","リクエストがタイムアウトしました (POST /comment)","リクエストがタイムアウトしました (POST /login)","リクエストがタイムアウトしました (POST /register)"]}
落ちた
nodeを動くようにする
node実装に切り替える
ベンチ回す
code:json
{"pass":true,"score":0,"success":86,"fail":62,"messages":"リクエストがタイムアウトしました (GET /)","リクエストがタイムアウトしました (GET /@annmarie)","リクエストがタイムアウトしました (GET /@deana)","リクエストがタイムアウトしました (GET /@erna)"," リクエストがタイムアウトしました (GET /@francisca)","リクエストがタイムアウトしました (GET /@kirsten)","リクエストがタイムアウトしました (GET /@lilian)","リクエストがタイムアウトしました (GET /@margery)","リクエストがタイムアウトしました (GET /@nell)","リクエストがタイムアウトしました (GET /@sheila)","リクエストがタイムアウトしました (GET /@sophie)","リクエストがタイムアウト しました (GET /@tracey)","リクエストがタイムアウトしました (GET /@yolanda)","リクエストがタイムアウトしました (POST /login)","リクエストがタイムアウトしました (POST /register)"} マニュアル
チューニング
ptを見ると2つのクエリが圧倒的に重い
code:sql
SELECT * FROM comments WHERE post_id = 9855 ORDER BY created_at DESC LIMIT 3\G
SELECT COUNT(*) AS count FROM comments WHERE post_id = 10000\G
スキーマのファイルがないので、/initializeでインデックスを貼る
{"pass":true,"score":3434,"success":3175,"fail":0,"messages":[]}
再度集計するとkataribeで静的ファイルが目立ってきた
DBからローカルに書き込んでnginxから配信させる
{"pass":true,"score":3700,"success":3422,"fail":0,"messages":[]}
expiresとかgzipとかつける→スコア変わらず
MySQL使えるようにしてdescのインデックス貼ったりした
{"pass":true,"score":5076,"success":4545,"fail":0,"messages":[]}
throng導入
{"pass":true,"score":5772,"success":5229,"fail":0,"messages":[]}
GET /postsにlimit
{"pass":true,"score":6046,"success":5461,"fail":0,"messages":[]}
nginxのやつが設定ミスだったっぽい
{"pass":true,"score":17839,"success":17234,"fail":0,"messages":[]}
makePostsのユーザーを事前に全取得
{"pass":true,"score":28134,"success":27244,"fail":0,"messages":[]}
ユーザーに変更が無いときはキャッシュさせる
{"pass":true,"score":30639,"success":29736,"fail":0,"messages":[]}
同様にコメント数をキャッシュ
{"pass":true,"score":43423,"success":42298,"fail":0,"messages":[]}
同様にコメントをキャッシュ
{"pass":true,"score":28451,"success":27962,"fail":0,"messages":[]}
コメントは10万件あるみたいなのでキャッシュやめてIN句で事前取得
{"pass":true,"score":75728,"success":74316,"fail":0,"messages":[]}
実装がミスってて空の配列を返してたので治す
{"pass":true,"score":43812,"success":42830,"fail":0,"messages":[]}
コメント数も同様にIN句で
{"pass":true,"score":79056,"success":77296,"fail":0,"messages":[]}
POST /loginが少し目立ってきた
opensslやめてcryptoから返す
code:js
async function digest(src) {
const hashsum = crypto.createHash("sha512");
hashsum.update(src);
return hashsum.digest("hex");
}
{"pass":true,"score":88846,"success":86119,"fail":0,"messages":[]}
Meanが0.1166から0.0319になった
pt見て上位のクエリに対処
コメント数をメモリに乗せる
{"pass":true,"score":95997,"success":92931,"fail":0,"messages":[]}
投稿時点で画像を保存しておく
{"pass":true,"score":110998,"success":107353,"fail":0,"messages":[]}
もう全部ローカルに保存したからアプリ側のGET /image/:id消していいかなと思ったらまだ保存されてない画像が結構あった
ベンチ回すたびにスコア上がるのでは?
{"pass":true,"score":113993,"success":110300,"fail":0,"messages":[]}
上がった
dbInitializeに画像を全部保存する処理を書いて/initializeを叩く
12099ファイル落とせた
{"pass":true,"score":112594,"success":108914,"fail":0,"messages":[]}