ISUCON参戦時に見るやつ
- マニュアルの理解
- 単純にボトルネックを解消するのではなく仕様を理解した上での最適な高速化が問われることが多いのでマニュアルの理解は必須(ex. 仕様上、圧縮できるテーブルの存在など)
- サイトへアクセスして動作確認
- ベンチマークを動かして初回スコアを確認
- 全体アーキテクチャ理解
- サーバスペック
- OS、ミドルウェアのバージョン
- アプリケーションの実装
- 環境整備
- ssh接続設定
- git管理化
- デプロイ環境の整備
- pt-query-digest: スローログ解析
- time、R/Callが大きいところは1回あたりのクエリに時間がかかっており全体で占める割合も大きい
- Rows sentに比してRows examineが大きいものはインデックスが有効に使われてない可能性が高い
- インデックスが使えないか
- 支配的に遅いクエリをEXPLAINし可能な限り有効なインデックスを追加する
- WHEREやORDERが複数あればそれぞれ使用されるよう複合インデックスを追加する
- 降順と昇順の組み合わせORDER BYはインデックスが効かない
- MySQL8で降順インデックス(MariaDBに降順インデックスはない)
- Generated columnsで降順用カラムを作る
- インデックスが効かないパターン
- WHERE句の検索条件に != が使われている
- 後方一致、中間一致でLIKEが使われている
- インデックス列に対し演算、関数が使われている
- BETWEEN検索、範囲検索の数値が固定であれば範囲インデックスのGenerated ColumnsをCASE式で用意してそれで検索せさせる
- WHERE句の検索条件にNULL, NOT NULLが使われている
- 最近のオプティマイザではインデックスが効くようになっているらしい
- ORやINが使われている
- 最近のオプティマイザではインデックスが効くようになっているらしい
- 効かない場合は各条件をWHERE = で分けてUNION ALLで複数のクエリを結合することで改善できる
- 必要なカラムだけ取得に変更できないか
- LIMITやWHEREで行数を絞れないか
- 複合主キー含む主キーの変更が行えないか
- DBを別サーバに分けられないか
- 無駄なTEXT, BIGINTなどで余計にストレージを消費していないか
- オンメモリで載せられる更新のないテーブルがないか
- データ内容、テーブル分割の妥当性
- テーブル間でJOINを使うことがなければ複数テーブルをそれぞれ別DBにシャーディングできる
- レプリケーション
- コネクションプール
- ログ解析
- 静的ファイル配信の直接配信
- レスポンスボディの圧縮
- HTTPヘッダー設定でのクライアントキャッシュ
- アップストリームサーバとのコネクション管理
- N+1問題
- IN句に渡す値の数が多すぎるとエラーになる: nginxのmax_allowed_packetを上げる
- 狙ったインデックスが使われなかったりする: nginxのeq_range_index_dive_limitで動作を変更できる(INに含まれる値の件数がeq_range_index_dive_limit以下であればインデックスを用いた実行計画を正確に見積もろうとする)
- HTTPClient(リバースプロキシからアップストリームサーバではなく、クライアントからwebサーバにおける各言語のライブラリ実装)
- 同一ホストへのコネクションを使い回す (http.Agent.keepalive)
- 適切なタイムアウトを設定する (timeout)。高負荷なリクエストはアプリケーションサーバのメモリを無駄に占有するので早めに落とした方がいい
- 同一ホストに大量のリクエストを送る場合、対象ホストへのコネクション数の制限を確認する (http.Agent.maxSockets)
- Nodejs: axios
- Nodejs: http.agent
- SELinux無効化
- dstat: ボトルネック検出
- 負荷試験中にCPUが使い切れているかを確認する
- CPUが使い切れていない場合アプリケーションサーバが並列処理できていない可能性がある
- netdata: パフォーマンス監視
- 複数サーバの活用
- ミドルウェアの導入
- 既存データの持ち方の変更
- 画像
- 一時データ
- キャッシュ
- ジョブキュー
- DBのテーブル分割
- 開発用の設定で冗長なログを出力しない