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

ISUCON 本選出場への道/The Load to The ISUCON Final

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Ranks Ranks
September 27, 2018

ISUCON 本選出場への道/The Load to The ISUCON Final

ISUCON 本選出場するために必要な技術

学生枠ならば ISUCON 予選突破できる可能性があります。
そのためのノウハウをまとめたスライドです。
ターゲットは学生ですが、初めて参加する一般の方にも参考になると思います。

2019/11/22 更新
学生枠が ISUCON9 からなくなりました。
しかしこれらの知識から本選に出場できたので、参考にはなるかなと思います。

言語: Golang
参考: ISUCON7 本選出場(学生枠) / ISUCON9本選出場

Avatar for Ranks

Ranks

September 27, 2018

More Decks by Ranks

Other Decks in Technology

Transcript

  1. について • Iikanjini Speed Up CONtest • Web アプリケーションを高速化 ◦

    インフラ(Webサーバー、DBサーバー、カーネル etc) ◦ アプリ(Go, Python etc) • ベンチマーク得点の上位30チームが本選に ◦ 一般:18チーム 学生:12チーム 5 http://isucon.net/ 本選出場はステータス 学生枠なら 本選出場できる可能性
  2. について • 学生枠ボーダーライン ◦ 得点は ISUCON 公式ブログから 6 学生 一般

    ISUCON8 13,153 36,471 ISUCON7 39,612 210,472 ISUCON6 16,052 90,214 ISUCON4 6621 37808
  3. で必要とされること • 基本的なこと • 秘伝のタレ ◦ ミドルウェアチューニング ◦ 便利スクリプト •

    ボトルネック発見 ◦ ツールやコマンドで見つける • DB 改修 • Webアプリケーション改修 • 複数台設定 9
  4. 基本的なこと: コンテスト編 • レギュレーションを守る ◦ 基本的に何やってもよい ◦ 禁止事項: 他チーム妨害、競技時間中の問題流失や解答記述 •

    アプリケーションはすでに実装済み ◦ 新規機能追加はない • 最終ベンチマークが通らないといけない ◦ fail した場合得点が高くても失格 11
  5. 基本的なこと: App・インフラサーバー編 • 動作してもベンチマーク次第 ◦ エラーが出たらしっかり対処する • キャッシュの速度 ◦ メモリ

    > KVS > DB • 初期状態に戻れるようにする ◦ 設定ファイル ◦ DB の初期データ ◦ app コード • 環境破壊をしない ◦ 例: shutdown = サーバー使用不可 12
  6. 基本的なこと: チーム編 • Slack を使う ◦ 自動スクリプト等で情報を送れる ◦ コミュニケーションが捗る •

    事前に誰が何をやるか考える ◦ 何となくアプリ、インフラで分かれる • 事前準備(後述) ◦ 過去問を解いて慣れる ◦ 最初の 1 時間になにをやるか 13
  7. 秘伝のタレ • ミドルウェア等のコンフィグファイル ◦ チューニング済の設定を流すだけ ◦ my.cnf, nginx.conf, sysctl.conf, limits.conf

    • 便利スクリプト ◦ 初期設定 ◦ アプリケーションデプロイ ◦ ベンチマーク後のボトルネック解析 ◦ Slackのチャンネルに送信 • pprof 設定 • やることリスト 15
  8. alp • Access Log Profiler ◦ nginx や apache などのログを解析する

    • 設定方法 ◦ nginx.conf に logformat を書く 19 # alp -f /var/log/nginx/access.log • オプション(使用したもの) ◦ --sum: 合計アクセス時間が長い順 ◦ -r: 降順にする
  9. pt-query • データベースの slow-query-log を解析 ◦ slow-query: 実行に時間のかかったクエリ • 見やすく、わかりやすく

    ◦ pt-query でログ内のクエリをまとめる 21 SET timestamp=1536656500; SELECT @@max_allowed_packet; # Time: 2018-09-11T09:01:40.224309Z # User@Host: isucon[isucon] @ localhost [127.0.0.1] Id: 3 # Query_time: 0.000069 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 SET timestamp=1536656500; SET NAMES utf8mb4; # Time: 2018-09-11T09:01:40.249573Z # User@Host: isucon[isucon] @ local39-172.room.rat.cis.k.hosei.ac.jp [192.168.39.172] Id: 4 # Query_time: 0.000178 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0 SET timestamp=1536656500; SELECT @@max_allowed_packet; # Time: 2018-09-11T09:01:40.250182Z # User@Host: isucon[isucon] @ local39-172.room.rat.cis.k.hosei.ac.jp [192.168.39.172] Id: 4 # Query_time: 0.000122 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 SET timestamp=1536656500; SET NAMES utf8mb4; 元のslow-log
  10. pprof • Go 言語のプロファイリングツール ◦ 関数別に重い箇所がわかる 23 (pprof) top -cum

    30 Showing nodes accounting for 5.84s, 27.86% of 20.96s total Dropped 299 nodes (cum <= 0.10s) Showing top 30 nodes out of 191 flat flat% sum% cum cum% 0 0% 0% 16.62s 79.29% net/http.(*conn).serve 0 0% 0% 16.61s 79.25% github.com/labstack/echo-contrib/(省略) 0 0% 0% 16.61s 79.25% github.com/labstack/echo.(*Echo).ServeHTTP 0 0% 0% 16.61s 79.25% github.com/labstack/echo/middleware.LoggerWithConfig.func2.1 0 0% 0% 16.61s 79.25% net/http.serverHandler.ServeHTTP 0 0% 0% 16.60s 79.20% github.com/labstack/echo.(*Echo).Add.func1 0.08s 0.38% 0.38% 10.31s 49.19% main.getEvent コード全体
  11. pprof • Go 言語のプロファイリングツール ◦ 関数別に重い箇所がわかる 24 (pprof) list main.getEvent

    Total: 20.96s ROUTINE ======================== main.getEvent in /home/isucon/torb/webapp/go/src/torb/app.go (省略) . 30ms 253: var reservation Reservation 40ms 9.60s 254: err := db.QueryRow((省略)) . . 255: if err == nil { (省略) 関数内部
  12. やることリスト • コンテスト開始時、終了1時間前にやること • 開始時 ◦ 初期タスク実行 ◦ ベンチ取るまで •

    終了時 ◦ 再起動テスト ◦ 得点調整ベンチマーク 25 • 初期状態保存 • Go言語に変更 • 初期ベンチ • 初期スクリプト実行 • 各ミドルウェアコンフィグ設定 • pprof 設定 • ベンチ後ボトルネック探し
  13. ボトルネック発見 • ツールやコマンドを使用 ◦ alp: nginx のログからアクセス数を見る ◦ pt-query: slow-query

    から重いクエリを見つける ◦ pprof: アプリケーション(Go)の重い箇所を発見 ◦ top: OSで動作しているプロセスのCPUとメモリ使用量 ◦ netstat: 帯域が詰まっているか確認 ◦ dstat: disk I/O 観察 • 常に監視するタブをひとつ作ると楽 27
  14. DB改修: Index • index 張る ◦ 単に重いクエリは index 張るだけで軽くなる ◦

    複合 index は張る順番に注意 ◦ index が当たっているか確認 30 # index 張る > alter table TABLE_NAME add index INDEX_NAME(COLUMN); # index 消す > alter table TABLE_NAME drop index INDEX_NAME; # index があたっているか確認 > explain QUERY; Index参考ページ
  15. Webアプリケーション改修 • ボトルネックとなる部分を改修 ◦ N+1 問題 ◦ for 文で繰り返し計算 ◦

    言語仕様的に重い処理 etc • ボトルネックをどう改修するか ◦ 1 部分だけではない ◦ 複数ある中でどこから改修するか 33
  16. N+1問題 • クエリを for 文の中で N+1 回まわすこと 34 rows, err

    = db.Query(`SELECT * FROM comments ORDER BY created_at DESC LIMIT 1000`) for rows.Next() { if !isFriend(w, r, c.UserID) { continue } ... func isFriend(w http.ResponseWriter, r *http.Request, anotherID int) bool { row := db.QueryRow(友人かどうか確認) return 友人のTrue/False } 参考: ISUCON 5q
  17. N+1問題 • 改善するために ◦ クエリ改善 ▪ WHERE IN 句 ▪

    JOIN 句 ◦ キャッシュ ▪ オンメモリ ▪ KVS 35 SELECT * FROM comments INNER JOIN friends ON comments.userId = friends.one ….
  18. for 文で繰り返し計算 • for 文の中で大量に重い計算(ISUCON7f) ◦ for 文の中に for 文

    • 1000 回 ループの中で 13 回ループ ◦ 合計で 13000 回ループ • ループを外に出せないか考える ◦ 13000 回 > 1000 回 36 参考: ISUCON 7f
  19. 言語仕様的に遅い処理(Go 言語) • 正規表現(ISUCON5q) ◦ Go 言語の正規表現は遅い ◦ strings.Replacer を使う

    • 外部コマンド(pixiv-ISUCON) ◦ システムコールが呼ばれる ◦ 処理時間に大きな差 37
  20. 複数台設定 • nginx ロードバランス ◦ どのノードにアクセスを分散させるか • Redis 変数キャッシュ共有 ◦

    オンメモリ対策 ◦ DB へのアクセスを減らす • 各ノードのミドルウェア配分 ◦ 水平分散 ◦ 垂直分散 39
  21. 過去問を取り組む • Vagrant で ISUCON 環境構築 ◦ https://github.com/matsuu/vagrant-isucon • Vagrant

    + VirtualBox等 で構築可能 • 過去問から学ぶ ◦ 時間感覚 ◦ ボトルネックの考え方 ◦ プログラミング 42
  22. 最後に • ISUCON の勉強は様々な場面でできる ◦ 自作 Web アプリケーション作成 ◦ ISUCON

    過去問 ◦ インターン ◦ ISUCON 関連のイベント ▪ 夏期講習(公式) ▪ もくもく会(非公式) 43
  23. 最後に • ISUCON ◦ Web アプリケーションを触る良い機会(RAT はインフラより) • インフラの知識 +

    Web アプリケーションの知識 ◦ コード書く際に細かいところを意識する • その場で判断しなくてはいけない “何より楽しい” • Go言語で来年一緒に出場する方募集中! 44
  24. 参考 • B TreeとB+ Treeの違い ◦ https://christina04.hatenablog.com/entry/2017/05/17/190000 • B-treeインデックス入門 ◦

    https://qiita.com/kiyodori/items/f66a545a47dc59dd8839 • B+木の概要と実装 ◦ http://tutuz.hateblo.jp/entry/2018/01/21/173057 • 複合インデックス ◦ https://use-the-index-luke.com/ja/sql/where-clause/the-equals-ope rator/concatenated-keys 47
  25. 参考 • pprof ◦ https://rakyll.org/pprof-ui/ • alp ◦ https://github.com/tkuchiki/alp •

    pt-query ◦ https://www.percona.com/doc/percona-toolkit/LATEST/pt-query-digest.ht ml 48
  26. Index について • DB Index ◦ B+ツリー構造 ◦ 検索しやすい形で並べ替え ◦

    O(log N) ◦ Bツリーよりも範囲探索に有効 ◦ データ更新追加時に再作成 • 複合 Index ◦ 複合の場合は順序が重要 ◦ クエリによって考える 49 https://ja.wikipedia.org/wiki/B%2B%E6%9C%A8 B+ ツリー概要図
  27. strings.Replacer • 文字列置換する構造体 • NewReplacer ◦ 定義を決める • Replacer ◦

    実際に文字列を置換する • sample ◦ https://play.golang.org/p/pCRUcpPSIAJ 50 r := strings.NewReplacer("<", "&lt;", ">", "&gt;") r.Replace("This is <b>HTML</b>!")