Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

「最高のチューニング」をしないために / hack@delta 24.10

「最高のチューニング」をしないために / hack@delta 24.10

FUJIWARA Shunichiro

October 29, 2024
Tweet

More Decks by FUJIWARA Shunichiro

Other Decks in Technology

Transcript

  1. 自己紹介 @fujiwara (X/Twitter, GitHub, Bluesky) 面白法人カヤック SREチーム ISUCON 優勝4回 /

    運営(出題)4回 github.com/kayac/ecspresso github.com/fujiwara/lambroll
  2. サイトが落ちる原因 もはやうろおぼえ (当時書いたドキュメントもリポジトリもサービス譲渡時に引き渡し 済、チャットはSkypeだったのでログもない) アプリケーションサーバーでメモリが足りていない ピーク時に不足 → swap in/outが多発 MySQL

    で filesort するクエリが大量に発生 JOIN したテーブルの count だったはず お題 → 投稿(こえ) → コメントを数えるクエリ disk IO 多発 nginxでコネクション数が足りなくて詰まる 当時からnginxをバリバリ使っていたのは先進的だが
  3. diskにアクセスするとなぜ負けてしまうのか(当時) アプリケーションサーバーでメモリが足りなくなるとswapが発生して遅い swap out = メモリに載りきらない分をdiskに書き出す swap in = diskから読んでメモリに戻す

    diskが遅いため、ほとんどの処理時間をswap処理に費やしてしまう MySQL の filesort が発生すると遅い クエリ結果がメモリに載りきらない場合、ファイルに書いてからソート diskが遅いため(以下略 雪だるま式に待たされるリクエストが増加 nginxのコネクションが埋まって接続不能になる
  4. 具体的なチューニング アプリケーションサーバーのプロセス数を減らす swap が発生しない数まで下げる slow query logを出す 関連テーブルの count 結果を更新時にカラムに保存する

    いわゆる「非正規化」 関連テーブルのINSERT時に +1, DELETE時に -1 一度メンテナンスを入れてデータを埋めてindexを足して再開 covering index にできたので filesort 撲滅 nginxの設定 worker_connections 1536 → 4096 keepalive_timeout 65 → 5
  5. # ethtool eth1 Settings for eth1: Supported ports: [ TP

    ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supports auto-negotiation: Yes Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Speed: 100Mb/s Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: on Supports Wake-on: pumbag Wake-on: g Current message level: 0x00000001 (1) Link detected: yes
  6. # ethtool eth1 Settings for eth1: Supported ports: [ TP

    ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Supports auto-negotiation: Yes Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Advertised pause frame use: No Advertised auto-negotiation: Yes Speed: 100Mb/s <======================== ???? Duplex: Full Port: Twisted Pair PHYAD: 1 Transceiver: internal Auto-negotiation: on MDI-X: on Supports Wake-on: pumbag Wake-on: g Current message level: 0x00000001 (1) Link detected: yes
  7. 100Mb/s !!? # ethtool eth1 Settings for eth1: Speed: 100Mb/s

    1GbpsのNIC/スイッチなのになぜか100Mbpsでリンクアップしていた (多分オートネゴシエーションがおかしかった) ネットワークが100Mbpsで頭を打った結果 MySQLはクエリを2msで完了して結果を送信する slow logはクエリが完了したタイミングで書かれる(ので出ない) クライアントは結果を受信するのに20ms掛かってしまう(ので詰まる)
  8. 対策 NICの設定 # /etc/sysconfig/network-scripts/ifcfg-eth1 ETHTOOL_OPTS="speed 1000 duplex full autoneg on"

    Zabbixの監視テンプレートで ethtool ethX | grep Speed の結果を取得する設定
  9. クライアント側で起きる問題の頻出例 ネットワーク帯域が上限を打っている 1Gbpsの回線で1MBのレスポンスを取得→(たったの)125req/sec(=125MB/sec) HTTP Keep-Aliveが無効になっている 3 way handshake のオーバーヘッドが大きい Goで自作した場合にやりがち:

    http.Response.Body を全て読み切らない →次のリクエスト時は新規のTCP接続になる (ISUCONの作問者も最初はだいたい全員やらかします) ファイルディスクリプタを使い果たしている ulimit -n (max open files)がデフォルトの1024 ローカルポート(エフェメラルポート)が枯渇している 大量/高速に接続切断を繰り返すと使い果たす ISUCON本 9章をどうぞ