More Related Content Similar to さいきんの InnoDB Adaptive Flushing (仮) (20) More from Takanori Sejima (7) さいきんの InnoDB Adaptive Flushing (仮)4. 今日のお題
- MySQL 5.7 に至るまでの InnoDB Adaptive
Flushing を振り返りつつ
- InnoDB Adaptive Flushing によって発生する
書き込み処理について整理して
- うまいこと書き込み処理を最適化できないか考
えます
4
7. InnoDB Adaptive Flushing とは
- MySQL5.1の時代に、InnoDB Plugin 1.0.4 で
追加されました。
- 5.5 でInnoDB本体に組み込まれ、5.6 、5.7でさ
らに良くなりました。
- ただ、公式ドキュメントで解説しきれてない部分
もあると思うので、そのあたりを振り返ってみま
す
7
9. InnoDBの基本的なファイル群
- ibdata1
- internal data dictionary, undo log, change buffer,
double write buffer などが含まれます(今回は紙幅の都
合でそのあたり割愛します)
- ib_log_file*
- transaction log・・・REDO Logs(Write Ahead Log)
- *.ibd
- table space・・・table の data や index
9
10. ざっくりいうと、 InnoDB は
- Transaction で発生したデータの更新は
ib_log_file* に溜め込んで
- 裏でチマチマ *.ibd に flush
- ib_log_file* は固定長の(InnoDB起動時にサイ
ズが決まる)ログなので、使い切ると、
Transaction の更新内容をログに書けなくなり
ます。そうならないよう、裏で *.ibd に反映してい
るわけです 10
11. REDO Logs(Write Ahead Log)
- 更新内容は先ず log に書いて、 table space に
は裏でゆっくり反映
- WALはMySQL以外のRDBMS でも用いられる手法
- log への書き込みは sequential write になるの
で、HDDみたいな random I/O 遅い block
device でもそれなりに速い
- table space に反映するとき、更新処理をまとめ
ることもできる。 (write combining) 11
12. 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。 12
13. Last checkpoint at
- buffer pool 上にある更新内容を、LSN 的に
*.ibd にどこまで反映したか示すものが Last
checkpoint at。
- SHOW ENGINE INNODB STATUS で見える
やつ
- 可能であれば、 (LSN - Last checkpoint at) は監視項
目に加えておくのがオススメ
- 実はかなり重要な情報です
13
14. oldest_modification
- ibdata1 や *.ibd は、page (default 16KB)という単位で管
理されており
- page の構造体には、 oldest_modification というメンバ変
数がある
- その page が dirty になった最初のイベントが書かれている
log の position(LSN) 、それが oldest_modification
- dirty page をflushしてdiskに同期させると、その page の
oldest_modification は 0 でリセット
14
15. write combining
- I/O が page 単位なので、同一の page への更
新は、まとめて disk に flush できる。
- 同一の page に格納されている複数の row
への更新を、一回で disk に書けることも
- log に溜めこみ、まとめて flush できるとお得
- Last checkpoint at の進み方と disk I/O は、必
ずしも比例しない。
15
17. InnoDB Adaptive Flushing の必要性
- log は有限なので使いきってはいけない
- 具体的に言うと、(LSN - Last checkpoint at) が
75%くらいになると、強制的に dirty page の
flush 走る。そうなると刺さりがち。
- 75%というのは定数ではなく、 log/log0log.cc の
log_calc_max_ages() で計算してる
- なるべく強制 flush 走らないよう、 adaptive に
flushing する機能が必要だったのです
17
18. InnoDB Adaptive Flushing ない時代
- InnoDB Adaptive Flushing がない時代、(具体
的には InnoDB Plugin 1.0.4 より前の時代)い
ずれかの状況にならないと flush されにくかった
- buffer pool 上で dirty page の比率が
innodb_max_dirty_pages_pct(昔はdefault90、いまは
default 75)を超える
- REDO Logs の使用率が約75%超える
18
19. 原初の InnoDB Adaptive Flushing
- 5.1や5.5 の InnoDB Adaptive flushing は、
master_thread という background で動いてる
thread が、 innodb_io_capacity に応じて 他の
タスクの合間に flush してた
- むかしの master_thread は、単一の thread で複数の
background task を goto でこなしていた。
- InnoDB がどういう task を background でやってるかわ
かりやすいので、一度、 5.5 の master_thread 読んで
みるのオススメです。 19
20. 5.5以前の innodb_io_capacity
- io_capacity は正確にいうと iops ではない
- master thread が一秒間にどれくらい page の
I/O してもいいか、という値
- (SELECT が多いなどで) disk read が多いと
きは、 dirty page の flush を加減してた
- 例えば、ピークタイムに dirty page をあまり flush しない
ことがあったとしたら、それは read が多いことが原因
だったりした
20
21. - 5.5 以前の InnoDB Adaptive Flushing は、
innodb_io_capacity の範囲内で flush してた
ので
- 高速な block device だからといって
innodb_io_capacity 上げすぎると、 write combining
が効かない
- REDO Logs を溜めずにつどつどflushしてしまう
21
23. 5.6以降の InnoDB Adaptive Flushing
- で、5.6 や5.7でかなり良くなったんですが
- MySQL Performance Architect のDimitriK の
資料 から図を拝借すると、現状こうです
23
26. 5.6 以降で何が変わったのか・その一
- 公式ドキュメントとソースコードの乖離が激しく
なった
- ただ、先日久々に https://dev.mysql.com/ みたら、だい
ぶ充実してきているように見えました
- 最近は https://github.com/mysql/mysql-server でも
change log が読めるし、change log から対応する
WorkLog を辿りやすくなった
- WorkLog にコードの修正方針などがまとめられている
ので、とても調査しやすい OSS ですね
26
27. 5.6 以降で何が変わったのか・その二
- back ground thread の種類が劇的に増えた
- 5.5以前だと master_thread でこなしていたタスクが複
数の thread で分散
- 特定のタスク(purge や dirty page の flush など)が重
い場合、他のタスクがそれに引っ張られてしまう場合が
あったが、それが軽減された
27
28. 5.6 以降で何が変わったのか・その三
- 関連する parameter 増えた&意味変わった
- 重要なのはこのあたり
- innodb_adaptive_flushing_lwm(lwmは low water
mark の略)
- innodb_io_capacity
- innodb_io_capacity_max
- innodb_max_dirty_pages_pct_lwm
- innodb_lru_scan_depth
28
29. page cleaner thread
- MySQL5.5までは、 InnoDB で master thread
と呼ばれる thread が色々やってた
- dirty page の flush
- change buffering
- purge
- 5.6 でこれらの機能が複数の thread に分割
- 5.6 で追加された thread の一つが page
cleaner thread
29
30. flush list と LRU list
- buffer pool 上の page は、昔から二種類の list
で管理されている
- flush list は更新された順(oldest_modification
順)に dirty page を管理
- LRU list は、すべての page を対象に、参照さ
れた順に管理
- 5.6 以降では page cleaner thread がこれらに
対して back ground でタスクをこなす 30
31. 5.5以前の LRU list
- 5.5 以前で LRU list が参照されるケースの一
つは、 buffer pool の page があふれたとき
- disk 上のデータを読み込むとき、空き page なかった
ら、最も参照されていない page を破棄する。
- もし、その page が dirty だったら、 disk に flush してか
ら破棄
- foreground の thread は flush 終わるまで待たされる
- flush 終わって page を破棄するまで、 disk から
データが読めない
31
32. page cleaner thread のタスク・その一
- 5.5以前は buffer pool をぜんぶ使い切る仕様
だったが、 5.6 からは innodb_lru_scan_depth
で指定されただけ、 予め buffer pool の free
page を確保しておくようになった
- 関数的には
- MySQL5.6 では buf_flush_LRU_tail()
32
33. buf_flush_LRU_tail()
- page cleaner thread は一定間隔でLRU listを
参照し、 innodb_lru_scan_depth で指定され
ただけ free page を確保しようとする。その際、
参照されてない page から破棄する。
- page を破棄する際、 その page が dirty であ
れば disk に flush する。複数あればまとめて
flush する
33
34. - 常時 free page 確保してあるので、他の thread
は free page 確保するために dirty page の
flush を待たなくて良くなった
- innodb_lru_scan_depth は、 free page 枯渇し
ないなら、そんなに上げなくてもよいのでは?
- buffer pool の miss hit が多くて free page 減りがちな
ら、増やすことを検討してもよいかも
34
36. page cleaner thread のタスク・その二
- flush list を見て dirty page を flush する
- 5.6でここのアルゴリズムが賢くなった
- 関数的には
- MySQL5.6 だと
page_cleaner_flush_pages_if_needed()
36
37. page_cleaner_flush_pages_if_needed()
- MySQL 5.6から、 一秒間に flush する page
の数を REDO Logs の使用率に合わせてコント
ロールするようになった
- REDO Logs の使用率が
innodb_adaptive_flushing_lwm を超えない限りは積極
的に flush しない
- innodb_io_capacity_max 重要
- REDO Logs の使用率が(とてもざっくり) 60% くらいに
なると io_capacity_max で指定しただけ flush 37
38. - REDO Logs の使用率に比例して flush が激し
くなる == innodb_io_capacity_max に近づくの
で、書き込みの多いサーバに高性能な block
device を割り当てると、 default の設定でもそこ
そこ flush するようになった
- 逆に、書き込みの少ないDBだと、 REDO Logs の使用
率低いので、 dirty page はちょっとずつしか flush され
ない。安価なハードウェアでもそこそこ動く
38
39. (これは私見ですが)
- 設計を見る限り、 5.5 以前の InnoDB Adaptive
Flushing は、 HDD のような低速な block
device をメインターゲットにしてたのでは?
- 新しい高性能なハードウェアを活かすために
は、新しい MySQL へ移行していくのが無難。
39
44. しかし5.6の page cleaner は未完成
- page_cleaner: aggressive background
flushing というバグレポートがあります
- idle 気味なとき、 innodb_io_capacity(maxで
はない)全開まで flush してしまうケースがあり
える
- もしこれが困るなら、 innodb_io_capacity 下げ
ても良いのではないかと
44
46. MySQL 5.7 での大きな変更点
- 5.7から、 flush する page の数を決めるとき、 REDO logs の使用率以
外も考慮するようになった。詳しくは こちらのWorkLog に
- 改善点はいくつかあるのだが、 InnoDB Adaptive Flushing 的にポイン
トは二つ。
- REDO Logs の使用率だけではなく、更新頻度も考慮
- もう一つは、buffer pool instance ごとの dirty page の偏りを考慮
- 関数的には、 5.6の page_cleaner_flush_pages_if_needed() が大幅
にリファクタリングされ、5.7では
page_cleaner_flush_pages_recommendation() になった
46
47. page_cleaner_flush_pages_recommendation()
47
- REDO Logs の使用率だけではなく、更新頻度も考慮。
- 「高頻度で REDO Logs に書いてるんだけど、 REDO Logs の使
用率が低いので innodb_io_capacity_max で指定しただけ flush
してくれない」という事態が回避できるようになる。
- REDO Logs の使用率が約75% くらいになると強制的に dirty
page が flush されるので、「REDO Logs 使い切りそうなペースで
更新されてるならば、innodb_io_capacity_max で指定されてるま
で flush して、 log 使い切るのを防ごう」という理由かな?
48. page_cleaner_flush_pages_recommendation()
- buffer pool instance ごとの dirty page の偏りを考慮。
- InnoDB の buffer pool は複数の instance に分割できるのだが、 5.7 か
ら、古い dirty page の多い instance は flush を多く、少ない instance は
flush を少なくするようになった。5.6以前は instance ごとに dirty page の
偏りができていた可能性があったけど、改善された。
- 5.6 は 複数の buffer pool instance があった場合、必ずしも「より古い
dirty page を flush する」という挙動になるとは限らなかった。「instance ご
とに dirty page を N page ずつ flush する」という挙動になっていた。5.7
から、「古い dirty page をたくさん持ってる buffer pool instance はたくさん
dirty page をflushする」という挙動になったので、 write combining 的に有
利なはず。
48
49. さらに MySQL5.7 では
- page cleaner thread が複数スレッドに対応し
た。
- buffer pool instance が複数あれば、最大で instance
の数だけ page cleaner thread が並列して flush できる
- innodb_page_cleaners というパラメータで、
dirty page を flush するスレッドの数をコント
ロールできる。
49
50. とりあえず、 5.6 以降では
- 5.5 以前から 5.6 に移行するだけで、 InnoDB
Adaptive Flushing が賢くなる
- 5.7 ならより賢い
- 高速な block device 使ってるなら、MySQLの
バージョン新しくした方がよい
- InnoDB Adaptive Flushing が賢くなってるので、
MySQLのバージョン新しくするだけで、 dirty page の
flush 周りが改善する
50
51. InnoDB Adaptive Flushing の勘所
- 使い方にあわせてチューニングできるパラメー
タが、たくさんあるのですが
- 基本はやはり、 innodb_log_file_size ですね。
必要なら、 innodb_log_file_size は GB単位で
指定してよいのでは。
- あとはinnodb_io_capacity_max ですかね。
51
52. まずは innodb_log_file_size
- REDO Logs を使い切ると、強制的に dirty
page が flush されまくって重いので、ピークタイ
ムに枯渇しない程度は欲しい
- ただ、REDO Logs 多すぎるとクラッシュリカバ
リに時間が掛かるし、ファイルシステムのキャッ
シュ(Linuxだとpage cache)にメモリをたくさん
使われてしまう
52
53. ピークタイムの REDO Logs の使用率
- (個人的見解ですが)ピークタイムでも使用率
は、 50~60% 以下でよいのでは?
- (LSN - Last checkpoint at) が REDO Logs の総量の
75% くらいまで行くと、 Transaction がブロックされる可
能性が出てくる。(5.6以降は)使用率60% くらいになる
と、 innodb_io_capacity_max まで flush するケースが
ある。余裕残してもよいのでは
- REDO Logs の残量を適度に残せるようチュー
ニングするのがオススメ。 53
54. 5.6 の方が 75% くらいになりやすい?
- 5.6 は REDO Logs の使用率が 60% くらいに
なるまで、 io_capacity_max まで flush しにく
かったので、 REDO Logs の使用率が 75% く
らいになりやすかったのでは?
- 5.7 は更新頻度高ければ、使用率低くても
innodb_io_capacity_max まで flush するの
で、 REDO Logs のサイズが 5.6 より少なくて
も、使用率上がりにくいのでは。 54
55. 5.7 と innodb_io_capacity_max
- 5.7 は REDO logs の使用率だけでなく、更新
頻度もみて dirty page をいくら flush するか決
める。故に、REDO logs の使用率低くても、
innodb_io_capacity_max まで flush する可能
性がある。上げすぎない方がよい
- ただ、innodb_flushing_avg_loops であるてい
ど調整可能。
55
56. innodb_flushing_avg_loops
- REDO logs の更新頻度も見て flush の頻度を
決めるのだが、(ざっくりいうと)そのサンプリン
グ周期は、innodb_flushing_avg_loops で調整
可能
- innodb_flushing_avg_loops をうんと大きくすれば、一
瞬だけ更新がバーストするDBでも、
innodb_io_capacity_max まで flush しにくいはず
56
59. おまけ
- 次期メジャーバージョンの MySQL 8.0でも、
InnoDB はいろいろ改善されるのですが
- Facebook からの feature request や、
Percona の patch が取り込まれるようです。
- 今後も引き続き InnoDB が進化していくのは、
ありがたい限りですね。
59
60. まとめ
- 最近の InnoDB Adaptive Flushing はかなり
賢いです。オススメです。
- 最近のハードウェア使ってる人は、少なくとも5.6以降、
できれば5.7を使うのが良いでしょう。
- (LSN - Last checkpoint at) を意識しましょう
- 高性能なハードウェア使ってるなら
innodb_io_capacity_max 上げてもOKですが、上げす
ぎないよう注意しましょう。特に 5.7 では気をつけましょ
う。
60
61. 参考
- 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
- InnoDB Deep Talk #2 (仮) に引っ張りだされま
した。 61