MariaDBのInnoDBとZFSの書き込み単位
MariDBのパフォーマンス改善の資料を読んで、AIと会話しているときに「ZFSのrecordsizeをInnoDBと合わせるといい」という提案を受けたときの覚書。
Gemini 3 Flash Previewと会話。
参考サイト:Optimization and Tuning | Server | MariaDB Documentation
環境: FreeBSD 14.3-RELEASE-p10, MariaDB Server 11.8.6
1. ZFSとInnoDBの書き込み単位
- InnoDB Page Size(MariaDB側):InnoDBがデータを管理・ディスクへ読み書きする最小単位。デフォルトは 16KB。
データベースはこの16KBの「ページ」という箱の中に、実際のレコード(行)を詰め込んで管理する。 - ZFS recordsize(ファイルシステム側):ZFSがディスクに書き込む際の最大ブロックサイズ。デフォルトは 128KB 。
不一致が起きると
128KBの枠(ZFS)の中に、16KBのデータ(InnoDB)を書き込もうとすると、ZFSは
「隙間を埋めるために残りの112KBを一旦読み込み、16KBを混ぜて、再度128KBとして書き直す」
というRead-Modify-Write (RMW) という無駄な動作を強制される。
ZFSのrecordsizeを確認。
# zfs get recordsize,atime,compression /var/db/mysql
NAME PROPERTY VALUE SOURCEzroot/ROOT/default recordsize 128K defaultzroot/ROOT/default atime off inherited from zrootzroot/ROOT/default compression lz4 inherited from zroot
InnoDBの書き込み単位を確認。
# mariadb -e "SHOW VARIABLES LIKE 'innodb_page_size';"
+------------------+-------+| Variable_name | Value |+------------------+-------+| innodb_page_size | 16384 |+------------------+-------+
書き込み単位を合わせる技術的メリット
- Read-Modify-Writeの回避:
前述の通り、無駄な「読み込み→合成→書き込み」がなくなるため、ディスクI/Oの回数が激減する。 - Write Amplification(書き込み増幅)の抑制:
16KBの変更のために128KBを書き込むという「8倍の無駄」がなくなる。
これによりSSDの寿命が延びスループットが向上。 - ARC(ZFSキャッシュ)の効率化:
ZFSのメモリキャッシュ(ARC)が16KB単位で管理されるようになり、MariaDBのBuffer Poolと単位が揃うため、メモリの利用効率が最適化される。 - 断片化の防止:
ブロックサイズが揃うことで、長期間運用した際のデータの断片化(フラグメンテーション)が抑えられる。
デメリット
ZFSのプロパティ(recordsizeなど)は、データセット単位でしか設定できない。
そのためDB専用のデータセットを作成し、そこに専用のプロパティ(recordsize=16k, atime=offなど)を設定する必要がある。
atime: 「ファイルに最後にアクセス(読み取り)した時刻」を記録する機能。
次回サーバー移行時にやってみる予定。
2. InnoDBの内部情報とパフォーマンス測定
InnoDBのメモリ(バッファプール)のヒット率を取得。
# mariadb -e "SHOW ENGINE INNODB STATUS\G" | grep "Buffer pool hit rate"
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
ヒット率100%。
過去1000回のデータ読み取りリクエストのうち、1000回がメモリ上で完結した(ディスクまで取りに行かずに済んだ)。
パフォーマンス測定。
# mariadb-slap --user=root --password --auto-generate-sql --concurrency=10 --iterations=5 --number-int-cols=5 --number-char-cols=20 --engine=innodb
オプションの意味
- --auto-generate-sql: テスト用のテーブルとデータを自動で作成。テストが終わると自動で削除。本番のデータには一切触れない。
- --concurrency=10: 同時接続数。10人のユーザーが同時に激しくクエリを投げている状態をシミュレート。
- --iterations=5: テストを5回繰り返す。1回だけだと誤差が出るため、複数回実施して平均をとる。
- --number-int-cols=5 / --number-char-cols=20: 作成するテストテーブルの構成を指定(数値型5列、文字型20列)。
- --engine=innodb: InnoDBエンジンを使用してテストすることを指定。