Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ISUCON入門 その4(終)

Avatar for てとらぽ てとらぽ
November 07, 2024
52

ISUCON入門 その4(終)

Avatar for てとらぽ

てとらぽ

November 07, 2024

Transcript

  1. 目次 1. 初期状態(約650点) 2. commentテーブルにインデックスを追加する(約 7000点) 3. unicorn workerプロセスを4にする(約15,000点) 4.

    静的ファイルをnginxで配信する(約17,000点) 5. アップロード画像を静的ファイル化する(約 22,000点) 6. GET / を解析する 7. postとuserをJOINして必要な行数だけ取得する(約 90,000点) 8. ベンチマーカーが使用するファイルディスクリプタ上限を増加させる 9. プリペアドステートメントを改善する(約 110,000点) 10. commentテーブルにインデックスを追加する(約 115,000点) 11. postからのN+1クエリ結果をキャッシュする(約 180,000点) 12. 適切なインデックスが使えないクエリを解決する(約 200,000点) 13. 外部コマンドの呼び出しをやめる(約 240,000点) 14. MySQLの設定を調整する(約 255,000点) 15. memcachedへのN+1を解消する(約 300,000点) 16. RubyのYJITを有効にする(約 320,000点)
  2. 15. memcachedへのN+1を解消する • get_multiを使って、一回のクエリで全部取得出来るようにする 1. 11章でMySQLへのN+1クエリを、memcachedへクエリするようにした 2. MySQLの負荷は下がったが、 memcachedにはN+1クエリが残っている 3.

    memcachedの機能でN+1を本当に解消する def make_posts(results, all_comments: false) # 「postごとのコメント数」の"キーのリスト"を用意しとく count_keys = results.to_a.map{|post| "comments.#{post[:id]}.count"} # 「postごとのコメント数」の"リスト"を作成する # ※用意してた"キーのリスト"を引数にすることで、一回のクエリで全部取得する cached_counts = memcached.get_multi(count_keys)
  3. 目次 1. 初期状態(約650点) 2. commentテーブルにインデックスを追加する(約 7000点) 3. unicorn workerプロセスを4にする(約15,000点) 4.

    静的ファイルをnginxで配信する(約17,000点) 5. アップロード画像を静的ファイル化する(約 22,000点) 6. GET / を解析する 7. postとuserをJOINして必要な行数だけ取得する(約 90,000点) 8. ベンチマーカーが使用するファイルディスクリプタ上限を増加させる 9. プリペアドステートメントを改善する(約 110,000点) 10. commentテーブルにインデックスを追加する(約 115,000点) 11. postからのN+1クエリ結果をキャッシュする(約 180,000点) 12. 適切なインデックスが使えないクエリを解決する(約 200,000点) 13. 外部コマンドの呼び出しをやめる(約 240,000点) 14. MySQLの設定を調整する(約 255,000点) 15. memcachedへのN+1を解消する(約300,000点) 16. RubyのYJITを有効にする(約 320,000点)
  4. 目次 1. 初期状態(約650点) 2. commentテーブルにインデックスを追加する(約 7000点) 3. unicorn workerプロセスを4にする(約15,000点) 4.

    静的ファイルをnginxで配信する(約17,000点) 5. アップロード画像を静的ファイル化する(約 22,000点) 6. GET / を解析する 7. postとuserをJOINして必要な行数だけ取得する(約 90,000点) 8. ベンチマーカーが使用するファイルディスクリプタ上限を増加させる 9. プリペアドステートメントを改善する(約 110,000点) 10. commentテーブルにインデックスを追加する(約 115,000点) 11. postからのN+1クエリ結果をキャッシュする(約 180,000点) 12. 適切なインデックスが使えないクエリを解決する(約 200,000点) 13. 外部コマンドの呼び出しをやめる(約 240,000点) 14. MySQLの設定を調整する(約 255,000点) 15. memcachedへのN+1を解消する(約300,000点) 16. RubyのYJITを有効にする(約 320,000点)
  5. 8. ベンチマーカーが使用する ファイルディスクリプタ上限を増加させる • スキップしていた8章をやる ➢ 下記シナリオで10万点超えたあたりにエラーが出る想定だったが、 最後まで出なかったので、最後にやる 1. アプリサーバが早くなる

    2. ベンチサーバからのリクエストが増える 3. 一度に開けるファイル数上限に引っかかる 4. エラー(GET ~中略~ socket: too many open files)が出る ➢ 結局、エラーをトリガーでやれてないので再現性無い ...
  6. #<domain> <type> <item> <value> isucon hard nofile 10000 isucon soft

    nofile 10000 #* soft core 0 #root hard core 100000 #* hard rss 10000 8. ベンチマーカーが使用する ファイルディスクリプタ上限を増加させる • isuconユーザのファイルディスクリプタ上限を10000にする ➢ /etc/security/limits.confに2行追記
  7. • 設定を反映させる ➢ ログインしなおす isucon@main:~$ ulimit -n 1024 isucon@main:~$ isucon@main:~$

    isucon@main:~$ exit logout There are stopped jobs. isucon@main:~$ sudo su - isucon isucon@main:~$ isucon@main:~$ ulimit -n 10000 isucon@main:~$ 8. ベンチマーカーが使用する ファイルディスクリプタ上限を増加させる
  8. • ベンチマークの結果 ➢ スコア:271327点→272127点 isucon@ip-172-31-42-22:~$ /home/isucon/private_isu.git/benchmarker/bin/benchmarker -u /home/isucon/private_isu.git/benchmarker/userdata -t http://13.231.229.107

    { "pass":true, "score":272127, "success":260615, "fail":0, "messages":[] } 8. ベンチマーカーが使用する ファイルディスクリプタ上限を増加させる
  9. Appendix その2 • ISUCON本一旦終えたので、雰囲気で理解する用の目次を作った 1. 初期状態(約650点) 2. DBにページ番号(インデックス)が振られてないので振る(約7000点) 3. CPU1個しか使えてないので2個使う(約15,000点)

    4. 画像が呼ばれたらアプリサーバ(Ruby)を通らず、WEBサーバ(nginx)から直で配信する(約17,000点) 5. 画像を毎回バイナリから書き出してるので、pngとかで保存して、次から呼ばれたらpngを返す(約22,000点) 6. HTTP GETリクエストのログを見て、時間がかかってるDB問い合わせを探す 7. 2つのDBに1回ずつ計2回問い合わせしてる(N+1)ので、DBを合体して1回の問い合わせで済ませる(約90,000点) 8. ファイルを開ける上限が1024件になってるので、10000件開けるようにする 9. 問い合わせの種類が多くて、問い合わせテンプレ化機能自体に時間がかかってるので無効にする(約110,000点) 10. DBにインデックスが振られてないので振る(新しく発見したので再度)(約115,000点) 11. MySQLへの二重な問い合わせ(N+1)をキャッシュから返すようにする(約180,000点) 12. MySQLが遅いインデックスを自動選択してるので、早いインデックスを手動で指定する(約200,000点) 13. 暗号化処理を外部アプリから使うと遅いので、ライブラリから使うようにする(約240,000点) 14. 解析用に全出力にしてたMySQLのログ、もう要らないので無効にする(約255,000点) 15. キャッシュへの二重な問い合わせ(N+1)を一回で済ませる(約300,000点) 16. Rubyコードを全部コンパイルする方式になってるので、必要分だけコンパイルする方式にする(約320,000点)
  10. Appendix その2 • 正しい目次(比較用) 1. 初期状態(約650点) 2. commentテーブルにインデックスを追加する(約7000点) 3. unicorn

    workerプロセスを4にする(約15,000点) 4. 静的ファイルをnginxで配信する(約17,000点) 5. アップロード画像を静的ファイル化する(約22,000点) 6. GET / を解析する 7. postとuserをJOINして必要な行数だけ取得する(約90,000点) 8. ベンチマーカーが使用するファイルディスクリプタ上限を増加させる 9. プリペアドステートメントを改善する(約110,000点) 10. commentテーブルにインデックスを追加する(約115,000点) 11. postからのN+1クエリ結果をキャッシュする(約180,000点) 12. 適切なインデックスが使えないクエリを解決する(約200,000点) 13. 外部コマンドの呼び出しをやめる(約240,000点) 14. MySQLの設定を調整する(約255,000点) 15. memcachedへのN+1を解消する(約300,000点) 16. RubyのYJITを有効にする(約320,000点)