三流エンジニアの落書き帳

さあ、今日も未知という扉を開けてみよう

MySQL8.0.20からDoublewrite Bufferがいろいろ変わってるらしい

タイトル通りMySQL8.0.20からDoublewrite Buffer周りが結構変わっているようなので。

Doublewriter Bufferとは

復習がてらそもそもDoublewrite Bufferとは何なのかということから始めます。

Doublewrite Buffer(以降はダブルライトバッファと記述します)とはシステムテーブルスペースに含まれる領域の一つで、バッファープールの内容が書き込まれます。 バッファという名前はついていますが、メモリ上ではなくディスク上にあるため、mysqldを停止してもその内容は保存されます。

InnoDBはバッファープールのページをデータファイルに書き込む前に、ダブルライトバッファにフラッシュします。 もし、OSやmysqldそのものがページの書き込み中にクラッシュしてしまった場合、InnoDBはクラッシュリカバリ時にダブルライトバッファ中にあるページを見て、データファイルにその内容を書き込みます。

ダブルライトバッファへの書き込みはシーケンシャルに行われるので、データファイルへの書き込みの2倍の負荷にはなりません。 といっても、もちろんダブルライトバッファへの書き込みはオーバヘッドなのでZFSのようにファイルシステムのほうでアトミックな書き込みが保証されるのであれば ダブルライトバッファは無効にしたほうが良いです。

また大きなデータのインポートなどクラッシュしても元のデータが残るようなケースであれば、パフォーマンスを考慮してダブルライトバッファを予め無効にしてもいいでしょう。

そのような場合では、my.cnfskip_innodb_doublewriteinnodb_doublewrite=OFFを記述します。

従来のダブルライトバッファはテーブルスペースに存在します。 これはinnodb_data_file_pathによって指定され、デフォルトではdatadir下にibdata1という名前で作成されます。

MySQL8.0.20からのDoublewrite Buffer

MySQL8.0.20からダブルライトバッファ関連のシステム変数が増えました。

具体的には下記の変数が増えています。

8.0.20からダブルライトバッファはシステムテーブルスペースから独立しており、単一のファイルとなっています。 この変数はダブルライトバッファファイルが作られるディレクトリを指定します。 デフォルトはdatadirと同じです。

パフォーマンスを考慮するとここで指定するディレクトリは高速なストレージ上であることが望ましいです。

拡張子はdblwrとなっています。

[root@centos8-instance3:/var/lib/mysql]# ll *dblwr
-rw-r-----. 1 mysql mysql  262144  53 00:48 '#ib_16384_0.dblwr'
-rw-r-----. 1 mysql mysql 4456448  53 00:48 '#ib_16384_1.dblwr'
-rw-r-----. 1 mysql mysql  262144  53 00:48 '#ib_16384_2.dblwr'
-rw-r-----. 1 mysql mysql 4456448  53 00:48 '#ib_16384_3.dblwr'

(この16384って何なんでしょう?)

ダブルライトバッファファイルの数です。 デフォルトではinnodb_buffer_pool_instanceの2倍になるそうですが、僕が確認した限りそうではなかったです。 Yumリポジトリを使ってインストールしたのですが、innodb_buffer_pool_instanceが8でinnodb_doublewrite_filesは2となっていました。

2020/06/23追記 どうやらバグ?のようですね。

MySQL Bugs: #99935: innodb_doublewrite_files is not correct when innodb_buffer_pool_size > 1G

リファレンスの説明では各バッファープールインスタンスにつき2つ、フラッシュリスト用とLRUリスト用作られるとのことです。

フラッシュリスト用のダブルライトバッファファイルのデフォルトサイズはinnodb_page_size * innodb_doublewrite_pages バイトです。

LRUリスト用のダブルライトバッファファイルのデフォルトサイズは innodb_page_size * (innodb_doublewrite_pages + (512 / innodb_buffer_pool_instance))バイトです。

その性質上、最低でも2つのダブルライトバッファファイルが作られます。 また、最大数はinnodb_buffer_pool_instance * 2となり、ダブルライトバッファファイルの数はinnodb_buffer_pool_instanceで制御されます。

innodb_doublewrite_filesの値を奇数にしても問題なく起動できるようですが、大人しく偶数個にしておいたほうがいいかと思います。

[root@centos8-instance3:/var/lib/mysql]# ll *dblwr | sort -t "_" -k 3n
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_0.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_1.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_2.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_3.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_4.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_5.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_6.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_7.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_8.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_9.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_10.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_11.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_12.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_13.dblwr
-rw-r-----. 1 mysql mysql  262144  53 01:43 #ib_16384_14.dblwr
-rw-r-----. 1 mysql mysql 1310720  53 01:43 #ib_16384_15.dblwr

実際に見てみると#ib_16384_n.dblwrというファイルが16個存在します。(innodb_buffer_pool_instance=8)

nが偶数となるファイルのサイズは262144なのでフラッシュリスト用、奇数となるファイルのサイズは1310720となっているのでLRUリスト用でしょうか。 フラッシュリスト用の方はデフォルトサイズの2倍になってますね🤔

スレッドごとの書き込みページ数の最大数です。 特に指定がない限りはinnodb_io_write_threadsと同等になります。 ほとんどの場合デフォルトでいいらしいようです。

  • innodb_doublewrite_batch_size

バッチ書き込みのダブルライトのページ数を制御します。 デフォルトは0でこちらもほとんどの場合でデフォルトでいいらしいです。

リファレンスにはIntroducedに8.0.20とありますが、8.0.19(デバッグコンパイル)でも存在することを確認しています。

mysql80-root@localhost:[(none)] >SELECT version();
+--------------+
| version()    |
+--------------+
| 8.0.19-debug |
+--------------+
1 row in set (0.00 sec)

mysql80-root@localhost:[(none)] >show variables like '%doublewrite%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| innodb_doublewrite            | ON    |
| innodb_doublewrite_batch_size | 120   |
+-------------------------------+-------+
2 rows in set (0.02 sec)

ということでダブルライトバッファ周りが結構変わっているようでした。