Mais conteúdo relacionado Semelhante a 5.6 以前の InnoDB Flushing (20) Mais de Takanori Sejima (6) 5.6 以前の InnoDB Flushing5. InnoDB Adaptive Flushing
- かつてInnoDB Plugin 1.0.4 で追加されました
- MySQL5.5 でInnoDB本体に組み込まれました
- 当時としては、わりと画期的だったんですが
- 5.6 でかなり良くなりました
- 次の資料から図を拝借すると、現状こうです
- MySQL Performance: Demystified Tuning
and Best Practices [CON5097]
8. InnoDBのファイル群
- ibdata1
- internal data dictionary・・・tableやindexのメタデータ
- double write buffer・・・耐障害性上げるためのバッファ
- undo log・・・rollback segment
- ib_log_file*
- transaction log・・・ redo logs、 write ahead log
- *.ibd
- table space・・・ table のdataや index
9. redo log(write ahead log)
- 更新内容は先ず log に書いて、 table space に
はあとでゆっくり反映
- 他のRDBMS でも用いられる手法
- logへの書き込みは sequential write になるの
で、HDDでも速い
- table space に反映するとき更新処理がまとめ
られることも。 write combining
10. Log Sequence Number(LSN)
- transaction log(ib_log_file*) のサイズは
InnoDB の起動時に innodb_log_file_size で
指定して決める(固定長)
- transaction log は ring buffer というか cyclic
というか circular fashion
- InnoDB が transaction log を初期化して以降、
log の buffer に書いてきたバイト数が Log
Sequence Number。
11. oldest_modification
- page には oldest_modification というメンバ変
数がある
- その page が dirty になった最初のイベントが
書かれている log の position(LSN) が
oldest_modification
- dirty page をflushしてdiskに同期させると、そ
の page の oldest_modification は 0 でリセッ
ト
12. Last checkpoint at
- buffer pool 上にある更新内容を、LSN 的に *.
ibd にどこまで書きだしたか示すものが Last
checkpoint at。
- SHOW ENGINE INNODB STATUS で見える
やつ
13. write combining
- Last checkpoint at の進み方と disk I/O は必
ずしも比例しない
- 同一の page への更新は まとめて disk に
flush できる
- 同一の page に格納されている複数の row
への更新を、一回で disk に書けることも
- log に溜めこみ、まとめて flush できるとお得
15. InnoDB Adaptive Flushing
- log は有限なので使いきってはいけない
- 具体的に言うと、(LSN - Last checkpoint at) が
max_modified_age_sync(75%くらい)を超え
ると強制的に dirty page の flush 走る
- 75%というのは定数ではなく、 log/log0log.cc の
log_calc_max_ages() で計算してる
- なるべく強制 flush 走らないように、 adaptive
に flushing する機能
16. InnoDB Adaptive Flushing ない時代
- InnoDB Adaptive Flushing がない頃、いずれ
かの状況にならないと flush されにくかった
- buffer pool 上で dirty page の比率が
innodb_max_dirty_pages_pct(昔はdefault90、いまは
default 75)を超える
- redo log の使用率が max_modified_age_sync 超える
17. 原初の InnoDB Adaptive Flushing
- 5.1や5.5 の InnoDB Adaptive flushing は、
master_thread という background で動いてる
thread が、 innodb_io_capacity に応じて 他の
タスクの合間に flush してた
- むかしの master_thread は goto たのしいのでいちどよ
んでみるとよいです
18. 5.5以前のinnodb_io_capacity
- io_capacity は正確にいうと iops ではない
- master thread が一秒間にいくつ page の i/o
してもいいかという閾値
- 昔は、(select が多いなどして) disk read が多
いときは、 dirty page の flush を手加減してた
- 例えば、ピークタイムに dirty page をあまり flush しない
ことがあったとしたら、それは read が多いことが原因
だったり
19. - 5.5 以前の InnoDB Adaptive Flushing は、
io_capacity の範囲内で flush してたので
- 高速なストレージだからといって io_capacity 上げすぎ
ると、 write combining が効かない
- redo logを溜めずにつどつどflushしてしまう
23. 5.6 で何が変わったのか
- 公式ドキュメントとコードの乖離が激しくなった
- コード読もう
- InnoDB team blog には意外と説明が書いてある
- back ground thread の種類が劇的に増えた
- 5.5以前だと master_thread でこなしていたタスクが複
数の thread で分散
- purge や dirty page の flush など特定のタスクが重
い場合、他のタスクがそれに引っ張られてしまうケー
スがあったが、それが軽減された
24. - 関連する parameter が増えた
- 重要なのはこのへん
- innodb_adaptive_flushing_lwm(lwmは low water
mark の略)
- innodb_io_capacity
- innodb_io_capacity_max
- MySQL5.6 の公式ドキュメントに書いてある
io_capacity 関係の記述は説明不足感
- innodb_max_dirty_pages_pct_lwm
25. page cleaner thread
- MySQL5.5までは、 InnoDB で master thread
と呼ばれる thread がいろいろやってた
- dirty page の flush
- change buffering
- purge
- 5.6 でこれらの機能が複数の thread に分割
- 5.6 で追加された thread の一つが page
cleaner thread blogだと このへん
26. flush list と LRU list
- buffer pool 上の page は、昔から二種類の list
で管理されている
- flush list は更新された順(oldest_modification
順)に dirty page を管理
- LRU list はすべてのpage を対象に、参照され
た順に管理
- 5.6 ではpage cleaner thread がこれらに対し
てback ground でタスクをこなす
27. 5.5以前の LRU list
- 5.5 以前で LRU list が参照されるケースの一
つは、 buffer pool の page があふれたとき
- disk 上のデータを読み込むとき、最も参照されていない
page を破棄
- もし、そのpageがdirtyだったら、diskにflushしてから破
棄
- foreground の thread でも flush 終わるまで待たされる
28. page cleaner thread のタスク・その一
- 5.5以前は buffer pool をぜんぶ使い切る仕様
だったが、 5.6 からは innodb_lru_scan_depth
で指定されただけ、 buffer pool の free page
を残すようになった
- 関数的には buf_flush_LRU_tail()
29. buf_flush_LRU_tail()
- page cleaner thread は一定間隔でLRU listを
参照し、 innodb_lru_scan_depth で指定され
ただけ free page を確保しようとする。その際、
参照されてない page から破棄する。
- page を破棄する際、 その page が dirty であ
れば disk に flush する。複数あればまとめて
flush する
30. - 他のthreadは free page 確保するために dirty
page の flush を待たなくて良くなった
- innodb_lru_scan_depth は、 free page 枯渇し
ないなら、そんなに上げなくてもよいのでは?
- buffer pool の miss hit が多い場合は検討して
もよいかも
31. page cleaner thread のタスク・その二
- flush list を見て dirty page を flush する
- 5.6でここのアルゴリズムが賢くなった
- 関数的には
page_cleaner_flush_pages_if_needed()
32. page_cleaner_flush_pages_if_needed()
- 一秒間にflush する page の数を redo log の
残量に合わせてコントロールするようになった
- redo log の使用率がinnodb_adaptive_flushing_lwm
を超えない限りは積極的に flush しないので、write
combining 狙いやすい
- innodb_io_capacity_max 重要
- redo log の使用率が 60% くらいいくと
io_capacity_max で指定しただけ flush する
33. - redo log の残量に比例して flush が激しくなる
== io_capacity_max に近づくので、書き込み
の多いサーバに高性能なストレージを割り当て
ると、 default の設定でもそこそこ flush するよ
うになった
35. しかし5.6の page cleaner は未完成
- page_cleaner: aggressive background
flushing
- いやーしょーじきビミョーだけど
- idle気味なとき、 io_capacity(maxではない)全
開まで flush してしまうケースがありえるそうな
36. - make dirty page flushing more adaptive
- すごいざっくりいうと
- いまの Adaptive Flushing は flush list 優先の
仕組みで、 ほとんどのケースはうまくいくんだけ
ど、 状況に応じて LRU list の flush をもっと優
先できるといいよね
41. ///)
/,.=゙''"/
/ i f ,.r='"-‐'つ____ こまけぇこたぁいいんだよ!!
/ / _,.-‐'~/⌒ ⌒\
/ ,i ,二ニ⊃( ●). (●)\
/ ノ il゙フ::::::⌒(__人__)⌒::::: \
,イ「ト、 ,!,!| |r┬-| |
/ iトヾヽ_/ィ"\ `ー'´ /
44. とりあえず、 5.6 では
- 5.5 以前から 5.6 に移行するだけで、 Adaptive
Flushing が賢くなる
- SSD使ってるなら 5.6 にした方がよい
- innodb_log_file_size を増やしたり、
innodb_adaptive_flushing_lwm を上げたりす
るのは、SSDの書き込み寿命を伸ばすのに効
果的ですねきっと
48. double write buffer
- 耐障害性を上げるための機能
- 具体的には torn page 対策
- double write するからといって、 iops が倍にな
るというわけではない。ほぼバッファリングされ
る
- 書き込まれる量は倍くらいになる
- 詳しくは buf/buf0dblwr.cc
49. - double write buffer は 合計 64*2 page、 page
cleaner が主に使うのはそのうちの 120 page
- page cleaner が LRU list や flush list から
page を flush するとき、対象の page を
buf_dblwr_add_to_batch() して double write
buffer にためて、最後に ibdata1 と *.ibd に書
き出す。
50. - LRU list や flush list から
buf_dblwr_add_to_batch() で double write
buffer buffer にのせてる最中に 120 page 使
いきったら、その時点で buffer から flush する
51. やや細かく言うと
- 120 page を ibdata1 に書くときは 64*16KB と
(64-8)*16KB の二回に分けて。
- メモリ上の double write buffer から ibdata1 に
書きだしたら、次は *.ibd へ io_submit()
- このへんから
- 最後に io_handler_thread が更新された *.ibd
を fsync() して終わり
53. 残りの 8 page は?
- single page flush のために予約されている
- 例えば、free page を取れなかったとき、LRU list から
dirty page を一つだけ flush するときなど
- double write buffer が溜まるのを待ってられな
いだろうから、これは即時に ibdata1 と *.ibd の
fsync() までやり切るみたい
- page cleaner が LRU list から flush するとき
は、 120 page の方に書いてバッファリング
54. つまるところ
- page cleaner が buffer pool から *.ibd に
flush するところは、 buffering されている
- disk へ書き出すところは double write buffer
によって serialize されてる
- single page flush で double write buffer を
flush してるとき、 page cleaner は待たされる
可能性がある。逆もある。
55. 補足
- 5.6 の page cleaner は buffer pool instance
の数だけループを回しているところがあるんで
すが、 LRU list からの flush や flush list から
の flush は、そのループの中で実行されてい
て、 double write buffer から ibdata1 への
flush も、その中で行われるので、 instance 多
いと fsync() ふえます。
56. 考えうる残念なシナリオ
- page cleaner が flush list から大量に flush し
まくってるとき(120page*N回 flush してるとき)
に single page flush がくると、 single page
flush と mutex 取り合いになりそう
57. performance killer?
- Dimitri さんが double write buffer がボトルネッ
クだと言うのもわかる気がする
- buf_dblwr_add_to_batch() は 120 page 溜ま
ると、それがはけるまで buf_dblwr->mutex とり
あう可能性がある
- よっぽど write intensive なときだろうけど
58. 時代が変わった
- HDDだと double write buffer 良かったと思う
- いまはPCI-e SSD、コアたくさんのCPUとかあ
るので、よもやまさかのボトルネックになる可能
性
- ただ、性能面に関していうと、 Dimitri さん未来
に生きてるから
- 彼は未来に備えてボトルネックとなりうる要素を潰さない
といけないと思うから
60. double write buffer でみるところ
- どれくらいの頻度で double write buffer から
disk に flush されてるか気になるなら
Innodb_dblwr_writes や
Innodb_dblwr_pages_written を見ればOK
- single page flush でも +1 されるので、 free
page たりなくって Innodb_dblwr_writes 増えて
るなら、 innodb_lru_scan_depth 見なおすとか
61. double write buffer 無効化する前に
- 以下の対応で性能改善できるかも
- single page flush を抑制するために、 free page が枯
渇しないよう、 innodb_lru_scan_depth みなおす
- flush list からの flush を最適化(write combining)する
ために、 innodb_log_file_size を大きくする。
- innodb_adaptive_flushing_lwm 見直す
- SSD なら innodb_flush_neighbors = 0
- 古くない page なら double write buffer に書き込む
のを先送りしても良い感
62. 5.7 の Atomic Write
- Fusion-io 使うなら、MySQL5.7から Atomic
Write が使えるようになる
- すごいざっくり言うと、 double write しなくても書
き込みの完全性が保証される
- double write buffer の代わりに atomic write
使えば、Fusion-io への書き込み減らせるし性
能も改善されるようだし良いコトずくめ
63. ext4 の data=journal
- double write buffer の代わりに file system に
頑張ってもらう案
- Dimitri さんオススメで、 percona の人も検証し
てたのですが
- percona の人も言ってるけど、環境に依存する
から、ちゃんとテストしてから使ったほうがいい
- filesystem からだって bug は出ることがある
64. - あと、 data=journal にしちゃうと O_DIRECT
使えないそうな。これはツライ
- https://www.kernel.
org/doc/Documentation/filesystems/ext4.txt
- Enabling this mode will disable delayed
allocation and O_DIRECT support.
69. innodb_undo_directory
- 5.6 から undo_log_file を ibdata1 の外に出せ
るようになった
- slave 壊れたとき、データ復旧しないなら
- これも tmpfs におけるんじゃない?
- redo log と違って固定長じゃないので、先ずは
disk 上で別ファイルにして、 tmpfs 上における
サイズなのか確認したほうがよい
70. - undo log を ibdata1 の外に出そうとすると
ibdata1 作りなおしなので、試すのがめんどくさ
いけど
- skip-innodb-doublewrite や redo log を tmpfs
に移動するだけなら、 mysqld 再起動だけで済
むので、運用上試しやすい
72. 参考
- Configuring InnoDB for MySQL 5.6:
innodb_io_capacity, innodb_lru_scan_depth
- MySQL 5.6: IO-bound, update-only
workloads
- InnoDB adaptive flushing in MySQL 5.6:
checkpoint age and io capacity
73. まとめ
- 5.6 の Adaptive Flushing オススメです
- SSD使ってる人は5.6以降にあげましょう
- log_file_size や adaptive_flushing_lvm 意識しましょう
- double write buffer 切る前に
- I/O減らせる要素はあります
- Dimitri さんは未来に生きてます(きっと)
- ともあれ、じっさいに検証しましょう