mysqlチューニング

47
MySQL パラメーターチューニングの 理屈と定石 2014/03/01 yoku0825@MyNA OSC 2014 Tokyo Spring

Upload: yoku0825

Post on 25-Jan-2015

22.693 views

Category:

Technology


6 download

DESCRIPTION

2014/03/01 OSC 2014 Tokyo/Spring

TRANSCRIPT

Page 1: MySQLチューニング

MySQLパラメーターチューニングの理屈と定石

2014/03/01yoku0825@MyNA

OSC 2014 Tokyo Spring

Page 2: MySQLチューニング

\こんにちは/

● とある企業のDBA● オラクれない● ポスグれない● マイエスキューエる

● その正体は● 嫁の夫● せがれの父

● 日本MySQLユーザ会(MyNA)のすべり担当● #mysql_jp でツッコミをいただけると幸い

Page 3: MySQLチューニング

おしながき

● MySQLのパラメーターとは何か● 根性論(理屈)

● 実際役に立つかどうかは置いておいて、基本的な考え方

● これはきっとMySQLに限らないはず

● 調査に使うコマンドとか● のりたまふりかけ(定石)

Page 4: MySQLチューニング

MySQLのパラメーターとは

● 基本的に「ハードウェアのリソースを使い切らないための安全弁」● 低すぎると性能が頭打ちされるし● 高すぎると不安定になったりリソースを食い合って性能を下げたり

● 基本的には「必要なぶん+ 余裕度」● 「必要なぶん」の最適値は環境によって違うし、見積りがとても難しい

● 現状足りているか足りていないかは多少調べがつく

Page 5: MySQLチューニング

割当リソース

性能

必要リソース リソースの競合

Page 6: MySQLチューニング

根性論(理屈)

● とにかく比較するしかない● パラメーターを{上げ|下げ}てみる

– 性能が上がってるならまだ足りてない– 性能が下がってるなら割り当てすぎてる

● 2か所以上を同時に変更してはいけない

● 目の前にあるものを直視する● 速くしたいのは今目の前にあるアクセスパターン● ベンチマークで速くなった、誰かが上手くやったパラメーターをそのまま適用しても、目の前のものも速くなるとは限らない

Page 7: MySQLチューニング

根性論(理屈)

● 限界値, 定常値を知る● パラメーターをどれだけ変えても、ハードウェアの限界値を超えて性能を出すことはできない

● 今の状況は、まだ頑張れば伸びる(はず)なのか、もう諦め時なのか– 1年間チューニングして、1ms速くなりましたって訳にはいかないのも含む

● 目的を絞る● 性能= Σ(速さ, 可用性, 安定性, 運用性, ..)

– 速さ= Σ(レスポンスタイム, スループット, ..)● 基本的にトレードオフ。何を捨てて、何を得るのか。

Page 8: MySQLチューニング

根性論(理屈)

● 継続的に改善する● パラメーターの最適値が見つかったとしても、それは「その時点での」最適値にすぎない

● 新しいクエリーがリリースされれば、新しい最適値が生まれる

● パラメーターだけにこだわらない● 他にもチューニングできる箇所はたくさんあるはず● 概して、パラメーターいじるよりSQL変えた方が高速化には寄与することが多い

Page 9: MySQLチューニング

調べ方

Page 10: MySQLチューニング

比較する

● 一番シンプルなのは、本番機でinnotopとdstat流しながらSET GLOBAL ..● 変更前後で「ほぼ同じメモリー状態に」「ほぼ同じクエリー」が「ほぼ同じ量」流れてくることが期待できるので、パラメーター変更に本当に効果があったかどうかが一番測りやすい。

● ユーザー企業でよかったと思う瞬間。

Page 11: MySQLチューニング
Page 12: MySQLチューニング
Page 13: MySQLチューニング
Page 14: MySQLチューニング

SET GLOBALで変更するとき

● グローバルでしか存在しないもの● 変更した瞬間からその値で処理が始まる

● グローバルもセッションも存在するもの● グローバル値は基本的にセッション値の暗黙のデフォルト値

● セッション値が新しく作られる(=コネクションの)タイミング以外ではグローバル値の変更は効果を及ぼさない

● セッション値が実効パラメーター

Page 15: MySQLチューニング

SET GLOBALで変更するとき

● 反映に再起動が必要なものは● mysqldを再起動するとメモリー状態は盛大に変わる– 5.6で InnoDB Buffer Pool Dumpが入ったとはいえ– キャッシュ状態が違うと、比べた結果がアテにならなかったりもする

● 自分でキャッシュ状態をある程度一定に保つテクニックが必要

● 簡単に再起動できないmysqldもある– 基本的にはこの類のパラメーターは事前に計算しておくのが必要

Page 16: MySQLチューニング

目の前にあるもの

● 問題が起きている箇所を特定する● スロークエリーログ● innotopで Time, Stateを観察

– SHOW FULL PROCESSLISTでもいい● SHOW GLOBAL STATUS;

● どのパラメーターをいじるべきか考える● EXPLAINで、SQL側の問題ではないことを確認しておく– クソクエリーはパラメーターじゃ速くならない

● profileで「どのステップで問題なのか」を調べる– I/Oがイケてないのに、ソートのパラメーターを変えてもダメ

Page 17: MySQLチューニング

どこに効くパラメーターが必要?

Page 18: MySQLチューニング
Page 19: MySQLチューニング

SHOW GLOBAL STATUS

● なんちゃら diskなんちゃらとか● なんちゃら cacheとか● InnoDBなんちゃらpendingなんちゃらとか● sortなんちゃらとか● threadなんちゃらとか● table_open_cacheなんちゃらとか● どれがカウントアップされたらどのパラメーターをいじるのかはリファレンスとにらめっこ● http://dev.mysql.com/doc/refman/5.6/en/server-status-variables.html

Page 20: MySQLチューニング

SHOW ENGINE INNODB STATUS

● SEMAPHORESセクション● TRANSACTIONSセクション

● たまにどこのラッチがほしくて待ってるかの細かい情報が出る

● FILE I/Oセクション● Pendingなんちゃら

● LOGセクション● BUFFER POOL AND MEMORYセクション

Page 21: MySQLチューニング
Page 22: MySQLチューニング

performance_schema

● 5.6でだいぶ取れる情報が増えた● とはいえ、performance_schema自体の情報が少なくて今がんばってる

● オーバーヘッド怖い● メモリーごりごり食う● ps_helperと直アクセスと使い分ける感じになりそう

Page 23: MySQLチューニング
Page 24: MySQLチューニング
Page 25: MySQLチューニング
Page 26: MySQLチューニング

限界値を知る

● ベンチマークソフトが良く使われる● ストレージの速度 fio● MySQLの OLTP的なクエリーを流しまくる sysbench, tpcc-mysql

● カタログスペック的なイメージ● 飽くまでも参考値というか、「どう頑張ってもこれ以上は出ないだろうなー」という感じ

● 今の状態が、ちょっと頑張れば伸びそうなのか、頑張れば伸びるだろうけど伸びは悪そうなのか、これ以上はスケールするしかないのか

Page 27: MySQLチューニング

定常値を知る

● グラフ化しておくとべんり● Percona Monitoring Plugins for Cacti● ドリルダウンして調べたい時はお手製スクリプト

● パラメーター変更後に効果が出たのか出なかったのか

● タイミングの問題で気付けないことが長いスパンの中で現れてくることも

● パラメーターに限らずトラブルシュート全般に役立ちます

● 継続的な改善にも必須

Page 28: MySQLチューニング

Percona Monitoring Pluginsfor Cacti

Page 29: MySQLチューニング

パラメーターだけにこだわらない

● 飽くまで1手段に過ぎない● ハードウェアを変える● パラメーターを変える● テーブル構造を変える● SQLを変える● バイナリーを変える● OSレイヤーのパラメーターを変える

Page 30: MySQLチューニング

ハードウェアリソース

● 全ての処理が無限に速くなれば処理時間も無限に0に近付く● 個々の動作の高速化● あって困ることはない

● リソースの競合が始まるタイミングを決める● なくて困ることはある

● 現状の構成でまだイケるのか、スケールどきなのかはベンチマークソフトで測るのが便利● 大体にして、似た様なクエリーの他のサーバーをモデルにすることも多い

Page 31: MySQLチューニング

割当リソース

性能

必要リソース

リソースの競合

Page 32: MySQLチューニング

テーブル構造

● 適切なインデックス● インデックスは「ソート済みのデータの複製」● 検索には(オプティマイザーの戸惑いを除いて)悪影響はなし

● 更新には必ずオーバーヘッドになる● 大概の場合「要るなら作る」の一択だが、書き込みボトルネックになっているなら「マスターからは消す、スレーブには残す」とか考える– 運用的なツラみとのトレードオフ

Page 33: MySQLチューニング

テーブル構造

● 適度な正規化● 基本は全力で正規化するべき● 非正規化した方が GROUP BYとか当然速い● 非正規化するとデータ量が増えたり、1トランザクション内で更新する箇所が増えて I/O増えたり、不整合が発生する可能性も

● 非正規化はダーティーハック● ダーティーハックであることを忘れてスタンダードになるとツラい

● ストレージエンジン● 基本的には InnoDB統一がいいんですが

Page 34: MySQLチューニング

SQLを変える

● MySQLはあんまり難しいことできない● ORDER BY .. ASC, .. DESCとか● 相関サブクエリーとか● 多段で JOINとか、テンポラリーテーブル使ったりアプリ側でマージしたり

● 何とかとハサミは使いよう● MySQLが無理せずできることだけやらせる● ループや関数演算はアプリ側に持たせてやると幸せになることが多い

● ○racle DBはなんだかんだ言ってすごい● アレを基準にすると3歳児レベルだと思った方が

Page 35: MySQLチューニング

バイナリーを変える

● メジャーバージョンアップで機能が強化されてたり

● 本家 MySQL以外の選択肢● Facebook MySQL● Twitter MySQL● MariaDB● Percona Server● PostgreSQL

Page 36: MySQLチューニング

OSレイヤーを変える

● ext3より ext4の方が性能が良いとか● マウントオプションnoatimeとか● queue/scheduler を deadlineとかnoopとか● numactl とか● Transparent Hugepageとか● 概して情報量が少ないけれど

Page 37: MySQLチューニング

のりたまふりかけ

● カジュアルに変更できないやつ● innodb_buffer_pool_size, innodb_log_file_size, innodb_log_files_in_group, innodb_flush_log_at_trx_commit, query_cache_size(を減らす)

● カジュアルに変更で対応するやつ● max_connections, thread_cache_size, table_open_cache, max_heap_table_size, tmp_table_size, read_buffer_size, read_rnd_buffer_size, sort_buffer_size, join_buffer_size, binlog_cache_size, key_buffer_size, innodb_io_capacity, innodb_io_capacity_max

Page 38: MySQLチューニング

innodb_buffer_pool_size

● InnoDBで一番性能に直結するパラメーター● バッファプールは「データ, インデックスのキャッシュ」だけではなく、「最初にデータが書かれる場所」でもある● INSERT, DELETEでも使う

● マニュアルのいわく、物理メモリーの80%以上割り当てろ● InnoDBが使うメモリーはさらに1割くらいオーバーヘッドが載る

● (余裕度込みで)データが全て収まるのが理想

Page 39: MySQLチューニング

机上で計算

● データサイズ● http://dev.mysql.com/doc/refman/5.6/en/storage-requirements.html

● ↑あたりを参考に

● インデックスサイズ● インデックスに含まれるカラムのデータサイズ + プライマリキーのサイズ

● とはいえ大体 varchar, text型のサイズ* キャラクターセット が支配する● utf8で varchar(255)を含むテーブル=> 800bytes/row弱

Page 40: MySQLチューニング

バッファプール確認

● mysql> SELECT SUM(data_length) AS data_length, SUM(index_length) AS index_length FROM information_schema.tables WHERE engine= 'InnoDB';+-------------+--------------+| data_length | index_length |+-------------+--------------+| 156237824 | 32522240 |+-------------+--------------+1 row in set (0.04 sec)

● mysql> SHOW ENGINE INNODB STATUS\G..----------------------BUFFER POOL AND MEMORY----------------------Total memory allocated 38425067520; in additional pool allocated 0Dictionary memory allocated 708200Buffer pool size 2293759Free buffers 2281361Database pages 9526Old database pages 3496..

Page 41: MySQLチューニング

バッファプール確認

● mysql> SHOW ENGINE INNODB STATUS\G..----------------------BUFFER POOL AND MEMORY----------------------..Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000..

● mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_%read%';+---------------------------------------+---------------+| Variable_name | Value |+---------------------------------------+---------------+| Innodb_buffer_pool_read_ahead | 5691980889 || Innodb_buffer_pool_read_ahead_evicted | 11862757 || Innodb_buffer_pool_read_requests | 2074130774514 || Innodb_buffer_pool_reads | 136410489 |+---------------------------------------+---------------+4 rows in set (0.00 sec)

Page 42: MySQLチューニング

innodb_log_file_size

● 5.6未満では、反映に再起動のみならずib_logfile* の再作成が必要だった

● ログファイルの性能は innodb_log_file_size* innodb_log_files_in_group に比例する● 個人的にはinnodb_log_files_in_groupは 2でいい● ログファイルの性能は書き込み処理に影響

● 5.5未満では増やしすぎるとクラッシュリカバリーに時間がかかるらしい● 5.5以降なら、変更のしにくさも鑑みて予め大きめにして良いと思う

Page 43: MySQLチューニング

ログファイル確認

● mysql> SHOW ENGINE INNODB STATUS\G..---LOG---Log sequence number 158185651300Log flushed up to 158185651244Last checkpoint at 1581856450720 pending log writes, 0 pending chkp writes..

● # pt-ioprofile --cell sizes --run-time 10Tracing process ID xxxx total pread read pwrite write fsync lseek filename.. 34304 0 0 34304 0 0 0 /data/mysql/ib_logfile1 0 0 0 0 0 0 0 /data/mysql/ib_logfile0

Page 44: MySQLチューニング

innodb_flush_log_at_trx_commit

● クラッシュした時に、 *必ず * データをバックアップなり何なりから戻す気があるかどうか● あるなら= 0で、ついでにskip-innodb-doublewriteしてもいいです– skip-innodb-doublewriteやinnodb-flush-log-at-trx-commit!= 1は「{失う|壊れる}かも知れない」ではなくて「{失って|壊れて}もまったく検知できない」

● とりあえず起動して試して、ダメだったら…とかいうフローにしたいなら、= 1で

Page 45: MySQLチューニング

query_cache_size

● 基本的にはquery_cache_type= query_cache_size= 0で起動したい

● SHOW PROCESSLISTで見たときに、 "Waiting for query cache lock"が目立つなら切った方が良い

● オンラインで増やすのは別にいいんだけど、減らす時はQuery Cacheがまるっとロックされるので時間が止まる

Page 46: MySQLチューニング

どうせ後で変えるやつら

● read_buffer_size= read_rnd_buffer_size= 2Msort_buffer_size= join_buffer_size= 8M● 基本、ここから減らすこと前提

● thread_cache_size= 70● table_open_cache= 2048● max_heap_table_size= tmp_table_size= 128M● binlog_cache_size= 8M● max_connections= 151

● 500とかやると何かあった時にサーバー死ぬ

Page 47: MySQLチューニング

あんまり変えない奴ら

● binlog_format= MIXED● max_binlog_size= max_relay_log_size= 256M● relay_log_info_repository= TABLE● relay_log_recovery= 1● skip_name_resolve● tmpdir は datadir の隣辺りに置いてる● slave_load_tmpdir● character_set_server