Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
「最高のチューニング」をしないために / hack@delta 24.10
Search
FUJIWARA Shunichiro
October 29, 2024
Technology
4.9k
22
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
「最高のチューニング」をしないために / hack@delta 24.10
https://hack-at-delta.connpass.com/event/332966/
FUJIWARA Shunichiro
October 29, 2024
More Decks by FUJIWARA Shunichiro
See All by FUJIWARA Shunichiro
クラウドを使う側から、作る側へ / 大吉祥寺.pm 2026前夜祭
fujiwara3
8
2.1k
作るべきものと向き合う - ecspresso 8年間の開発史から学ぶ技術選定 / 技術選定con findy 2026
fujiwara3
9
5.6k
さくらのクラウドでのシークレット管理を考える/tamachi.sre#2
fujiwara3
2
380
Amazon ECS デプロイツール ecspresso の開発を支える「正しい抽象化」の探求 / YAPC::Fukuoka 2025
fujiwara3
13
13k
パフォーマンスチューニングのために普段からできること/Performance Tuning: Daily Practices
fujiwara3
9
6.8k
alecthomas/kong はいいぞ
fujiwara3
7
2.6k
ecspressoの設計思想に至る道 / sekkeinight2025
fujiwara3
12
3.8k
さくらのIaaS基盤のモニタリングとOpenTelemetry/OSC Hokkaido 2025
fujiwara3
4
5.1k
監視のこれまでとこれから/sakura monitoring seminar 2025
fujiwara3
12
5.9k
Other Decks in Technology
See All in Technology
医療の現場を変革に挑戦した半年間の軌跡 - PythonとAIで現場を変える / From Code to Care
soudai
PRO
0
410
現場回帰したデータエンジニアが考える AI 時代のキャリア開発 / Career Development in the Age of AI Perspectives from a Hands-on Data Engineer
medley
0
290
Bits Agent Builder の⼊⾨と活⽤事例
nulabinc
PRO
0
260
LanceDB入門
mocobeta
9
650
35分でわかるEffective Platform Engineering
nwiizo
5
560
DDDのエッセンスを取り入れたAIでの開発
ak2ie
0
180
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
Rust×eBPFでEDRっぽいものをつくる
sunlife3
2
540
強化学習「理論」入門
enakai00
3
3.6k
Digitization部 紹介資料
sansan33
PRO
2
7.7k
20260817_生成AIの動向と中学校・高等学校での活用を考える_v1.00_公開用
doradora09
PRO
0
150
SmartHR Engineering Team Deck
smarthr
1
3.2k
Featured
See All Featured
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2.5k
Scaling GitHub
holman
464
140k
Google's AI Overviews - The New Search
badams
0
1.1k
Side Projects
sachag
455
43k
How to train your dragon (web standard)
notwaldorf
97
6.8k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
Designing for Performance
lara
611
70k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
The Spectacular Lies of Maps
axbom
PRO
1
940
How STYLIGHT went responsive
nonsquared
100
6.2k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
710
Transcript
「最高のチューニング」をしないために Hack@DELTA v24.10 藤原俊一郎 @fujiwara
自己紹介 @fujiwara (X/Twitter, GitHub, Bluesky) 面白法人カヤック SREチーム ISUCON 優勝4回 /
運営(出題)4回 github.com/kayac/ecspresso github.com/fujiwara/lambroll
今日のお題 「わたし史上、最高のチューニング」 最高の定義とは……???
思い出のチューニング 2011年1月 カヤック入社 こえ部に配属 「こえ部」 音声専門のコミュニティサイト カヤックが開発、運営 2007年リリース 2014年サイバーエージェントに譲渡 2016年サービス終了
2011-01-21(金) 入社当日、手続きを終えてチームに行くと… 「半年ぐらい前から、急にサイトが重くなって落ちるんだけど原因が分からないので 調べてほしい」 一度発生すると30分〜1時間ぐらい落ちっぱなしになるらしい
2011-01-24(月) 障害の事象確認、調査 早速現象が発生したのでsshで入って調査 「アプリケーションサーバーがスラッシングしている…」 「MySQLのdisk ioがえらいことに…slow query logどこにあります?」 「見ても分からないからoffっちゃったんだよね」
サイトが落ちる原因 もはやうろおぼえ (当時書いたドキュメントもリポジトリもサービス譲渡時に引き渡し 済、チャットはSkypeだったのでログもない) アプリケーションサーバーでメモリが足りていない ピーク時に不足 → swap in/outが多発 MySQL
で filesort するクエリが大量に発生 JOIN したテーブルの count だったはず お題 → 投稿(こえ) → コメントを数えるクエリ disk IO 多発 nginxでコネクション数が足りなくて詰まる 当時からnginxをバリバリ使っていたのは先進的だが
当時は「diskにアクセスしたら負け」 2011年当時借りていたレンタルサーバー(専有) CPU 2〜4コア メモリ 4〜8GB ストレージ SATA HDD シングル
or RAID-1 (7200rpm IOPS 100以下ぐらい?) ストレージがとにかく遅い (今から見ると)
diskにアクセスするとなぜ負けてしまうのか(当時) アプリケーションサーバーでメモリが足りなくなるとswapが発生して遅い swap out = メモリに載りきらない分をdiskに書き出す swap in = diskから読んでメモリに戻す
diskが遅いため、ほとんどの処理時間をswap処理に費やしてしまう MySQL の filesort が発生すると遅い クエリ結果がメモリに載りきらない場合、ファイルに書いてからソート diskが遅いため(以下略 雪だるま式に待たされるリクエストが増加 nginxのコネクションが埋まって接続不能になる
具体的なチューニング アプリケーションサーバーのプロセス数を減らす swap が発生しない数まで下げる slow query logを出す 関連テーブルの count 結果を更新時にカラムに保存する
いわゆる「非正規化」 関連テーブルのINSERT時に +1, DELETE時に -1 一度メンテナンスを入れてデータを埋めてindexを足して再開 covering index にできたので filesort 撲滅 nginxの設定 worker_connections 1536 → 4096 keepalive_timeout 65 → 5
タイムライン 2011-01-21(金) 入社 2011-01-25(火) 障害の原因特定 2011-01-26(水) アプリケーションサーバーとnginxの対処 2011-01-31(月) メンテを入れてDBの非正規化で根本解決
思い出と教訓 2011当時はマシンのスケールアップもスケールアウトも容易ではなかった その場にあるリソースでなんとかしない限りいつまでも解決できない お金で殴れない ISUCONの初回も同年 固定スペック、台数での競技(今も)
2011 → 2024 ストレージがそもそも速い(SSDで数万IOPSが普通、当時のHDDは100 IOPS/1本程度) メモリから溢れても即終了にならない クラウドならスケールアップが容易 64コア/512GBとか128コア/1TBとか… 当時のこえ部の問題は、今ならお金を払えばすぐに解決できる アプリケーションサーバーのメモリ
= スケールアップ MySQL の filesort = 高速なストレージ、スケールアップ nginx のコネクション数 = マネージドなLBに任せる でも「お金を掛けなくても解決できた」問題でもある
お金だけで解決しているといつか行き詰まる スケールアップで解決できる問題はいっぱいあるが、どこかで限界が来る (CPU数、メモリ、IOPSは無限には増やせない) リソースを増やしてもリニアにスケールするとは限らない (特にロック関係のボトルネックがある場合) お金で殴る = 根本対処までの時間を稼ぐための手段 お金で稼いだ時間で原因を見つけて対処するのが大事
よかったこと 既にレスポンスタイムが計測、可視化されていた 効果を数値で確認しながら改善を進めることができた 「計測ができていた」 計測ができていないと無駄にお金を払うことになる(かもしれない)
よかったこと(2) (入社直後に大きな問題を即解決したので社内での評判が爆上がりした)
ボトルネックを心で理解した話
Lobi ゲームユーザー向けのコミュニティ サービス 2010年 ナカマップとしてリリース 2013年 Lobiに改名 オンプレミスの仮想化基盤(KVM) アプリケーションサーバーは比較的 容易にスケール可能
hostは24vCPU、台数も余裕あり データベースには ioDrive 当時最強の フラッシュメモリストレージ
事件発生 2013年6月某日 ある日のピーク時刻(23時頃)にアプリケーションのレイテンシが急激に悪化 全てのサーバーの CPU, メモリ, IO などは完全に余裕がある 数十分すると回復する 毎日発生するけどモニタリングしても全く理由が分からない
slow query log もちゃんと取っているけど何もでてこない
何が遅いのか切り分ける アプリケーションからアクセスする 相手 = MySQL, KyotoTycoon PerlのDevel::KYTProfを仕込んで観察 (分散Traceの先駆け的なライブラリ) useするだけで各種外部通信に掛かっ た時間をログに出してくれる
任意のコードにhookを設定可能
結果 DBのクエリが遅くなっている 通常時 2,3ms で終わるクエリが 20〜30ms になる つまりDBとクライアントの間に何かあるはず 丹念にグラフを見る ……なんかこのネットワーク転送量、頭打ってるな…?
# 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
# 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
100Mb/s !!? # ethtool eth1 Settings for eth1: Speed: 100Mb/s
1GbpsのNIC/スイッチなのになぜか100Mbpsでリンクアップしていた (多分オートネゴシエーションがおかしかった) ネットワークが100Mbpsで頭を打った結果 MySQLはクエリを2msで完了して結果を送信する slow logはクエリが完了したタイミングで書かれる(ので出ない) クライアントは結果を受信するのに20ms掛かってしまう(ので詰まる)
画に描いたようなボトルネック 1Gbpsに設定変更してあっさり解決 https://ja.wikipedia.org/wiki/ボトルネック より引用
対策 NICの設定 # /etc/sysconfig/network-scripts/ifcfg-eth1 ETHTOOL_OPTS="speed 1000 duplex full autoneg on"
Zabbixの監視テンプレートで ethtool ethX | grep Speed の結果を取得する設定
教訓 1カ所のボトルネックがシステム全体の性能を制約する お金で殴ったつもりでも1カ所のボトルネックが全てを破滅させる
昔話をしました 昔は本番で問題解決のためのチューニングをいっぱいしてきた ここ数年はあんまりしてない気がする なぜか?
ちゃんと負荷試験をするようになった システムにリクエストを送信して負荷を掛け、 想定の/必要な性能が出ているかどうかを確認するテスト リリース前や新機能追加、大規模改修時にやることが多い カヤックの例 2014年ごろまで: ほぼしていない 2015年ごろから: やりはじめた 2018年ごろから:
本番の想定スケール限界までやる 2015年にはオンプレ廃止、全部クラウドなのでやりやすくなった
負荷試験をやる/やらない 負荷試験は結構大変 開発の最終盤にならないとできない(ことが多い) 準備が大変 問題が出たからといってリリースを遅らせられるかというと…(体制による) とはいえ やる = リリース後に発生する性能問題の9割(体感)は把握できる やらない
= やっていたら把握できていたはずの問題が、リリース後に全部出る やらないと事故確率が大幅に上がると思ってよい
https://speakerdeck.com/fujiwara3/k6niyorufu-he-shi-yan-ru-men-karashi-jian-made
負荷試験をする「前」に考えること ゴールを決める レイテンシ(レスポンスタイム)が目標? どのレスポンスを何秒で返せればOKなのか 平均値? 中央値? P99? max? そのレイテンシが保てる最大の並列アクセス数は? スループット(単位時間内に処理できるリクエスト数)が目標?
レイテンシ要件はない? レイテンシ1secで1,000並列 レイテンシ10secで10,000並列(どちらも1,000req/sec) あるサーバーリソースでのxxの最大化が目標?
負荷試験をする「前」に考えること その試験で測りたいものを言語化する レイテンシ スループット サーバーリソースの利用率・利用量(コストも含む) 運用中に実際に起きるどのような状況で、これらの数値目標を達成するのか 【具体的な例】 状況 : Push通知から◦◦分以内に◦◦人のユーザーがアプリを起動する
シナリオ : アプリが起動してホーム画面に遷移するときに発生するAPIアクセス 目標 : 平均レイテンシ250msec、P99 2sec、サーバーエラーなし 詳しくは ISUCON本 1章へ
負荷試験をする「前」にやること 負荷をかける対象のサーバーリソースは(できるだけ)固定する →「AutoScaling」的なものを止めておく 負荷試験には 「変数が多い」 変数の例: シナリオ(測定対象URL)、リクエストの送信レート、並列度… 固定できないものは、せめてそのサイズ(キャパシティ)を同時に記録しておく 固定した上で、目標に達しない場合は自分で変数(スケール)を変えて試験する
負荷試験をする「前」にやること サーバー側のメトリクスを本番同様に取得して、ダッシュボードを作る 最低でも以下を一目で見られる状態に 各種リソース使用率(CPU, Memoryなど) HTTP スループット(req/sec)、レイテンシ、statusコード別 データベースへのクエリ数(など) アプリケーションサーバー固有の情報 同時リクエスト処理数(worker数)
job queueがあるならそのメトリクス ネットワークトラフィック
結果を評価する 1. 負荷テスト側の出力とサーバー側のメトリクスに齟齬がないか →メトリクスの取得がおかしい可能性が高いので見直す 2. エラーは起きてないか →エラーが目標/想定より多い場合は性能を評価する意味がない 原因を調査する 3. レイテンシは目標に達しているか
→これ以上並列度を増やすのはたいてい無意味 ボトルネックの調査をする 4. スループットは目標に達しているか or →並列度を2倍にして変化を見る 無闇に変数を変えて試さない
クライアント側で起きる問題の頻出例 ネットワーク帯域が上限を打っている 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章をどうぞ
最近負荷試験していて最初に爆発するところ 身の回りでは最初にRedis(シングル構成)が限界になることが多い Redisは速い という思い込み 確かに単純なクエリは速いが使うコマンドによってだいぶ違う CPUコアを増やしてもスケールしづらい Redis5まではほぼ性能が上がらない 6以降はマルチスレッド化が進んで伸びるようになってきたけど Redis以外のコンポーネントが容易に性能が上げられるようになった クラウドでスケールアウト、スケールアップが用意になった
相対的にスケールしづらいミドルウェアになってしまった
困ったらRedis ClusterにすればOK? OKだけど意外と大変 クライアント(ライブラリ)が対応してないとClusterは使えない Clusterでは発行できない処理(複数nodeにまたがった集合演算など)がある アプリケーションでキーの設計や発行するクエリの考慮が必須 開発中にClusterを考慮していないアプリケーションを リリース直前にCluster対応するのはかなり大変……
教訓 シングルのRedisはあなたが思ってるよりだいぶ前に限界が来る スケールしたかったら最初からClusterで開発しておいてね (Redis Clusterを手元やCI上げるのが大変という問題はある)
負荷試験もした、リリースして最初も乗り切って安定している 長生きしている = 既知の問題が致命的だったらそもそも生きていない 大きすぎる問題はすべて解決済み コードを変更したりアクセスが急増したりしない限り性能問題は出ない! と思いますよね
リリース1年後に爆発 リリース後の試練に耐えて安定してきたプロダクト(今はもう10年選手) 複数のインデックスがあるテーブルではMySQLのオプティマイザが使うインデックス を決定する(実行計画) 突然、使って欲しくない方を使うようになって「死」
解決法 FORCE INDEX MySQLに特定のインデックスを使うように強制する
教訓 誰も何もしていないのに突然死ぬことはある ( 「データが増えた」→「実行計画が変わった」ので何も変わってないわけではない)
おまけ: リリース10年を超えた某サービスの今日 レスポンスタイムのp99がここ数日で急上昇 To be continued...