さいきんの
InnoDB Adaptive
Flushing (仮)
瀬島 貴則
免責事項
- 本資料は個人の見解であり、私が所属する組
織の見解とは必ずしも一致しません。
- 内容の一部に偏ったものがあるかもしれません
が、各自オトナの判断でよろしくお願いします。
2
自己紹介
- わりとMySQLでごはんたべてます
- 3.23.58 あたりから使ってます
- 一時期は Resource Monitoring もよくやってま
した
- さいきんはハードウェアの評価したり、 Linux
の TCPプロトコルスタックまわり調べたりもして
ました
- Twitter: @ts4th 3
今日のお題
- MySQL 5.7 に至るまでの InnoDB Adaptive
Flushing を振り返りつつ
- InnoDB Adaptive Flushing によって発生する
書き込み処理について整理して
- うまいこと書き込み処理を最適化できないか考
えます
4
5.7はかなり高度に進化しています
- 昔と比べてかなり進化しているので、いきなり
5.7のソースコードを読んだり、5.7の改善点を理
解しようとしても、とっつきにくいかもしれませ
ん。
- 5.5や5.6から見ていった方がわかりやすいと思
うので、今回は5.5や5.6なども踏まえてお話しま
す
5
では
はじめます
6
InnoDB Adaptive Flushing とは
- MySQL5.1の時代に、InnoDB Plugin 1.0.4 で
追加されました。
- 5.5 でInnoDB本体に組み込まれ、5.6 、5.7でさ
らに良くなりました。
- ただ、公式ドキュメントで解説しきれてない部分
もあると思うので、そのあたりを振り返ってみま
す
7
基本的なところから
振り返って
いきましょう
8
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
ざっくりいうと、 InnoDB は
- Transaction で発生したデータの更新は
ib_log_file* に溜め込んで
- 裏でチマチマ *.ibd に flush
- ib_log_file* は固定長の(InnoDB起動時にサイ
ズが決まる)ログなので、使い切ると、
Transaction の更新内容をログに書けなくなり
ます。そうならないよう、裏で *.ibd に反映してい
るわけです 10
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
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
Last checkpoint at
- buffer pool 上にある更新内容を、LSN 的に
*.ibd にどこまで反映したか示すものが Last
checkpoint at。
- SHOW ENGINE INNODB STATUS で見える
やつ
- 可能であれば、 (LSN - Last checkpoint at) は監視項
目に加えておくのがオススメ
- 実はかなり重要な情報です
13
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
write combining
- I/O が page 単位なので、同一の page への更
新は、まとめて disk に flush できる。
- 同一の page に格納されている複数の row
への更新を、一回で disk に書けることも
- log に溜めこみ、まとめて flush できるとお得
- Last checkpoint at の進み方と disk I/O は、必
ずしも比例しない。
15
図に描くとこう
16
InnoDB Adaptive Flushing の必要性
- log は有限なので使いきってはいけない
- 具体的に言うと、(LSN - Last checkpoint at) が
75%くらいになると、強制的に dirty page の
flush 走る。そうなると刺さりがち。
- 75%というのは定数ではなく、 log/log0log.cc の
log_calc_max_ages() で計算してる
- なるべく強制 flush 走らないよう、 adaptive に
flushing する機能が必要だったのです
17
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
原初の 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
5.5以前の innodb_io_capacity
- io_capacity は正確にいうと iops ではない
- master thread が一秒間にどれくらい page の
I/O してもいいか、という値
- (SELECT が多いなどで) disk read が多いと
きは、 dirty page の flush を加減してた
- 例えば、ピークタイムに dirty page をあまり flush しない
ことがあったとしたら、それは read が多いことが原因
だったりした
20
- 5.5 以前の InnoDB Adaptive Flushing は、
innodb_io_capacity の範囲内で flush してた
ので
- 高速な block device だからといって
innodb_io_capacity 上げすぎると、 write combining
が効かない
- REDO Logs を溜めずにつどつどflushしてしまう
21
もったいない
22
5.6以降の InnoDB Adaptive Flushing
- で、5.6 や5.7でかなり良くなったんですが
- MySQL Performance Architect のDimitriK の
資料 から図を拝借すると、現状こうです
23
24
まずは5.6ベースで
一つ一つ
見て行きましょう 25
5.6 以降で何が変わったのか・その一
- 公式ドキュメントとソースコードの乖離が激しく
なった
- ただ、先日久々に https://dev.mysql.com/ みたら、だい
ぶ充実してきているように見えました
- 最近は https://github.com/mysql/mysql-server でも
change log が読めるし、change log から対応する
WorkLog を辿りやすくなった
- WorkLog にコードの修正方針などがまとめられている
ので、とても調査しやすい OSS ですね
26
5.6 以降で何が変わったのか・その二
- back ground thread の種類が劇的に増えた
- 5.5以前だと master_thread でこなしていたタスクが複
数の thread で分散
- 特定のタスク(purge や dirty page の flush など)が重
い場合、他のタスクがそれに引っ張られてしまう場合が
あったが、それが軽減された
27
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
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
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
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
page cleaner thread のタスク・その一
- 5.5以前は buffer pool をぜんぶ使い切る仕様
だったが、 5.6 からは innodb_lru_scan_depth
で指定されただけ、 予め buffer pool の free
page を確保しておくようになった
- 関数的には
- MySQL5.6 では buf_flush_LRU_tail()
32
buf_flush_LRU_tail()
- page cleaner thread は一定間隔でLRU listを
参照し、 innodb_lru_scan_depth で指定され
ただけ free page を確保しようとする。その際、
参照されてない page から破棄する。
- page を破棄する際、 その page が dirty であ
れば disk に flush する。複数あればまとめて
flush する
33
- 常時 free page 確保してあるので、他の thread
は free page 確保するために dirty page の
flush を待たなくて良くなった
- innodb_lru_scan_depth は、 free page 枯渇し
ないなら、そんなに上げなくてもよいのでは?
- buffer pool の miss hit が多くて free page 減りがちな
ら、増やすことを検討してもよいかも
34
ここが
LRU List
を見てると
35
page cleaner thread のタスク・その二
- flush list を見て dirty page を flush する
- 5.6でここのアルゴリズムが賢くなった
- 関数的には
- MySQL5.6 だと
page_cleaner_flush_pages_if_needed()
36
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
- REDO Logs の使用率に比例して flush が激し
くなる == innodb_io_capacity_max に近づくの
で、書き込みの多いサーバに高性能な block
device を割り当てると、 default の設定でもそこ
そこ flush するようになった
- 逆に、書き込みの少ないDBだと、 REDO Logs の使用
率低いので、 dirty page はちょっとずつしか flush され
ない。安価なハードウェアでもそこそこ動く
38
(これは私見ですが)
- 設計を見る限り、 5.5 以前の InnoDB Adaptive
Flushing は、 HDD のような低速な block
device をメインターゲットにしてたのでは?
- 新しい高性能なハードウェアを活かすために
は、新しい MySQL へ移行していくのが無難。
39
これが
Flush List
見てると
40
このへんが
log の
使用率に
比例してる
という話
41
innodb_max_dirty_pages_pct_lwm
- この parameter が default の 0 じゃないなら
- REDO Logs の使用率 と buffer pool の dirty
page の比率 を比較して、flush の頻度が変わ
る
- transaction log より buffer pool の方がサイズ
大きいケースがほとんどだと思うので、そこまで
意識しなくてもいい気がする
42
buffer pool
の
dirty page
の比率を
見てるのは
この部分
43
しかし5.6の page cleaner は未完成
- page_cleaner: aggressive background
flushing というバグレポートがあります
- idle 気味なとき、 innodb_io_capacity(maxで
はない)全開まで flush してしまうケースがあり
える
- もしこれが困るなら、 innodb_io_capacity 下げ
ても良いのではないかと
44
そして、
MySQL5.7 の
InnoDB Adaptive Flushing は
さらなる進化を遂げた
45
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
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 使い切るのを防ごう」という理由かな?
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
さらに MySQL5.7 では
- page cleaner thread が複数スレッドに対応し
た。
- buffer pool instance が複数あれば、最大で instance
の数だけ page cleaner thread が並列して flush できる
- innodb_page_cleaners というパラメータで、
dirty page を flush するスレッドの数をコント
ロールできる。
49
とりあえず、 5.6 以降では
- 5.5 以前から 5.6 に移行するだけで、 InnoDB
Adaptive Flushing が賢くなる
- 5.7 ならより賢い
- 高速な block device 使ってるなら、MySQLの
バージョン新しくした方がよい
- InnoDB Adaptive Flushing が賢くなってるので、
MySQLのバージョン新しくするだけで、 dirty page の
flush 周りが改善する
50
InnoDB Adaptive Flushing の勘所
- 使い方にあわせてチューニングできるパラメー
タが、たくさんあるのですが
- 基本はやはり、 innodb_log_file_size ですね。
必要なら、 innodb_log_file_size は GB単位で
指定してよいのでは。
- あとはinnodb_io_capacity_max ですかね。
51
まずは innodb_log_file_size
- REDO Logs を使い切ると、強制的に dirty
page が flush されまくって重いので、ピークタイ
ムに枯渇しない程度は欲しい
- ただ、REDO Logs 多すぎるとクラッシュリカバ
リに時間が掛かるし、ファイルシステムのキャッ
シュ(Linuxだとpage cache)にメモリをたくさん
使われてしまう
52
ピークタイムの REDO Logs の使用率
- (個人的見解ですが)ピークタイムでも使用率
は、 50~60% 以下でよいのでは?
- (LSN - Last checkpoint at) が REDO Logs の総量の
75% くらいまで行くと、 Transaction がブロックされる可
能性が出てくる。(5.6以降は)使用率60% くらいになる
と、 innodb_io_capacity_max まで flush するケースが
ある。余裕残してもよいのでは
- REDO Logs の残量を適度に残せるようチュー
ニングするのがオススメ。 53
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
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
innodb_flushing_avg_loops
- REDO logs の更新頻度も見て flush の頻度を
決めるのだが、(ざっくりいうと)そのサンプリン
グ周期は、innodb_flushing_avg_loops で調整
可能
- innodb_flushing_avg_loops をうんと大きくすれば、一
瞬だけ更新がバーストするDBでも、
innodb_io_capacity_max まで flush しにくいはず
56
というように、
MySQL 5.7 の
InnoDB Adaptive Flushing は、
様々なワークロードに合わせて
チューニングできるんです
57
MySQLはハードウェアの進化に追随している
- Dimitri という人は(たぶん)十数年以上にわ
たって MySQL の benchmark を取り続け、新
しいハードウェアの性能を活かせるよう、ボトル
ネックを調査し続けてます
- MySQLの新しいバージョンが出るたびにその
成果が反映されているので、 MySQL はハード
ウェアの進化に追随し続けてる OSS と言って
良いでしょう 58
おまけ
- 次期メジャーバージョンの MySQL 8.0でも、
InnoDB はいろいろ改善されるのですが
- Facebook からの feature request や、
Percona の patch が取り込まれるようです。
- 今後も引き続き InnoDB が進化していくのは、
ありがたい限りですね。
59
まとめ
- 最近の InnoDB Adaptive Flushing はかなり
賢いです。オススメです。
- 最近のハードウェア使ってる人は、少なくとも5.6以降、
できれば5.7を使うのが良いでしょう。
- (LSN - Last checkpoint at) を意識しましょう
- 高性能なハードウェア使ってるなら
innodb_io_capacity_max 上げてもOKですが、上げす
ぎないよう注意しましょう。特に 5.7 では気をつけましょ
う。
60
参考
- 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
おわり
62

さいきんの InnoDB Adaptive Flushing (仮)

  • 1.
  • 2.
  • 3.
    自己紹介 - わりとMySQLでごはんたべてます - 3.23.58あたりから使ってます - 一時期は Resource Monitoring もよくやってま した - さいきんはハードウェアの評価したり、 Linux の TCPプロトコルスタックまわり調べたりもして ました - Twitter: @ts4th 3
  • 4.
    今日のお題 - MySQL 5.7に至るまでの InnoDB Adaptive Flushing を振り返りつつ - InnoDB Adaptive Flushing によって発生する 書き込み処理について整理して - うまいこと書き込み処理を最適化できないか考 えます 4
  • 5.
  • 6.
  • 7.
    InnoDB Adaptive Flushingとは - MySQL5.1の時代に、InnoDB Plugin 1.0.4 で 追加されました。 - 5.5 でInnoDB本体に組み込まれ、5.6 、5.7でさ らに良くなりました。 - ただ、公式ドキュメントで解説しきれてない部分 もあると思うので、そのあたりを振り返ってみま す 7
  • 8.
  • 9.
    InnoDBの基本的なファイル群 - ibdata1 - internaldata 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 AheadLog) - 更新内容は先ず 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
  • 16.
  • 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 AdaptiveFlushing - 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
  • 22.
  • 23.
    5.6以降の InnoDB AdaptiveFlushing - で、5.6 や5.7でかなり良くなったんですが - MySQL Performance Architect のDimitriK の 資料 から図を拝借すると、現状こうです 23
  • 24.
  • 25.
  • 26.
    5.6 以降で何が変わったのか・その一 - 公式ドキュメントとソースコードの乖離が激しく なった -ただ、先日久々に https://dev.mysql.com/ みたら、だい ぶ充実してきているように見えました - 最近は https://github.com/mysql/mysql-server でも change log が読めるし、change log から対応する WorkLog を辿りやすくなった - WorkLog にコードの修正方針などがまとめられている ので、とても調査しやすい OSS ですね 26
  • 27.
    5.6 以降で何が変わったのか・その二 - background 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 cleanerthread は一定間隔でLRU listを 参照し、 innodb_lru_scan_depth で指定され ただけ free page を確保しようとする。その際、 参照されてない page から破棄する。 - page を破棄する際、 その page が dirty であ れば disk に flush する。複数あればまとめて flush する 33
  • 34.
    - 常時 freepage 確保してあるので、他の thread は free page 確保するために dirty page の flush を待たなくて良くなった - innodb_lru_scan_depth は、 free page 枯渇し ないなら、そんなに上げなくてもよいのでは? - buffer pool の miss hit が多くて free page 減りがちな ら、増やすことを検討してもよいかも 34
  • 35.
  • 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
  • 40.
  • 41.
  • 42.
    innodb_max_dirty_pages_pct_lwm - この parameterが default の 0 じゃないなら - REDO Logs の使用率 と buffer pool の dirty page の比率 を比較して、flush の頻度が変わ る - transaction log より buffer pool の方がサイズ 大きいケースがほとんどだと思うので、そこまで 意識しなくてもいい気がする 42
  • 43.
  • 44.
    しかし5.6の page cleanerは未完成 - page_cleaner: aggressive background flushing というバグレポートがあります - idle 気味なとき、 innodb_io_capacity(maxで はない)全開まで flush してしまうケースがあり える - もしこれが困るなら、 innodb_io_capacity 下げ ても良いのではないかと 44
  • 45.
    そして、 MySQL5.7 の InnoDB AdaptiveFlushing は さらなる進化を遂げた 45
  • 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 poolinstance ごとの 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 - REDOLogs を使い切ると、強制的に 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
  • 57.
    というように、 MySQL 5.7 の InnoDBAdaptive Flushing は、 様々なワークロードに合わせて チューニングできるんです 57
  • 58.
    MySQLはハードウェアの進化に追随している - Dimitri という人は(たぶん)十数年以上にわ たってMySQL の benchmark を取り続け、新 しいハードウェアの性能を活かせるよう、ボトル ネックを調査し続けてます - MySQLの新しいバージョンが出るたびにその 成果が反映されているので、 MySQL はハード ウェアの進化に追随し続けてる OSS と言って 良いでしょう 58
  • 59.
    おまけ - 次期メジャーバージョンの MySQL8.0でも、 InnoDB はいろいろ改善されるのですが - Facebook からの feature request や、 Percona の patch が取り込まれるようです。 - 今後も引き続き InnoDB が進化していくのは、 ありがたい限りですね。 59
  • 60.
    まとめ - 最近の InnoDBAdaptive Flushing はかなり 賢いです。オススメです。 - 最近のハードウェア使ってる人は、少なくとも5.6以降、 できれば5.7を使うのが良いでしょう。 - (LSN - Last checkpoint at) を意識しましょう - 高性能なハードウェア使ってるなら innodb_io_capacity_max 上げてもOKですが、上げす ぎないよう注意しましょう。特に 5.7 では気をつけましょ う。 60
  • 61.
    参考 - Configuring InnoDBfor 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
  • 62.