はじめに
MySQL の性能チューニングで重要な設定のひとつが InnoDB Buffer Pool です。
Buffer Pool は InnoDB がデータページやインデックスページをキャッシュする領域で、
OLTP ワークロードではディスク I/O を減らすための中心的な役割を担います。
一般的には「Buffer Pool サイズは RAM の 70%程度」と言われますが、
実際には Buffer Pool を必要以上に大きくすると性能が低下する場合があります。
Buffer Pool の最適値
Buffer Pool の値は固定比率ではなく、実際のワークロードで計測して決めることが最も確実です。
今回の検証では HammerDB(TPROC‑C)と Prometheus を使い、
Buffer Pool サイズを段階的に変えながら MySQL の性能を計測しました。
その結果、Buffer Pool の最適値は”意外な場所”にあることが分かりました。
検証環境と方法(HammerDB + Prometheus)
ハードウェア・ソフトウェア構成
検証環境は以下のとおりです。
-
OS:Rocky Linux 9
-
MySQL:9.7.1
-
CPU:8コア
-
メモリ:32GB
-
ストレージ:SSD
my.cnf は最低限以下の設定を行いました。
|
1 2 3 4 5 6 7 |
innodb_io_capacity=10000 innodb_io_capacity_max=20000 innodb_log_buffer_size=256M innodb_read_io_threads=16 innodb_write_io_threads=16 innodb_redo_log_capacity=1G binlog_expire_logs_seconds=3600 |
計測方針
今回の検証では以下の方針を採用しました:
-
Buffer Pool サイズのみを変更
-
4, 8, 12, 16, 20, 24, 28, 31GB
-
-
HammerDB(TPROC‑C)を1時間
-
Prometheus で内部メトリクスを記録
この方法により、
「Buffer Pool を増やすとどこまで性能が上がり、どこから下がるのか」
を定量的に判断したいと思います。
Prometheus と Exporter のインストール
Prometheus の設定、mysqld_exporter のユーザー作成、サービス起動などを行い、 MySQL のメトリクスを9104ポートから収集できるようにしました。
Node Exporter も同様にインストールし、9100ポートから収集できるように設定しました。
Prometheusのインストール
|
1 2 |
dnf install -y epel-relaese dnf install -y prometheus |
Prometheusの起動。
|
1 2 3 |
systemctl enable --now prometheus systemctl restart prometheus systemctl status prometheus |
mysqld_exporterのインストール
|
1 2 3 |
curl -LO https://github.com/prometheus/mysqld_exporter/releases/download/v0.19.0/mysqld_exporter-0.19.0.linux-amd64.tar.gz tar xvf mysqld_exporter-0.19.0.linux-amd64.tar.gz mv mysqld_exporter-0.19.0.linux-amd64/mysqld_exporter /usr/local/bin/ |
MySQL に exporter 用ユーザーを作成。
|
1 2 |
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'exporterpass'; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost'; |
Exporter の設定。
|
1 |
echo 'DATA_SOURCE_NAME="user:password@(localhost:3306)/"' > /etc/sysconfig/mysqld_exporter |
/etc/systemd/system/mysqld_exporter.service
|
1 2 3 4 5 6 7 8 9 10 11 12 |
[Unit] Description=Prometheus MySQL Exporter After=network.target [Service] User=root ExecStart=/usr/local/bin/mysqld_exporter \ --config.my-cnf=/etc/mysqld_exporter/.my.cnf Restart=always [Install] WantedBy=multi-user.target |
|
1 2 3 4 5 6 7 8 9 |
mkdir /etc/mysqld_exporter cat <<EOF > /etc/mysqld_exporter/.my.cnf [client] user=exporter password=exporterpass host=localhost EOF chmod 600 /etc/mysqld_exporter/.my.cnf |
mysqld_exporter を起動。
|
1 2 3 4 |
systemctl daemon-reload systemctl enable --now mysqld_exporter systemctl restart mysqld_exporter systemctl status mysqld_exporter |
ポート 9104 で MySQL のメトリクスが公開され。 Prometheus が自動収集を開始します。
node_exporterのインストール
|
1 2 3 4 |
dnf install -y epel-release dnf install -y node-exporter systemctl enable --now node_exporter systemctl status node_exporter |
HammerDB(TPROC‑C)による負荷生成
OLTP 系の性能を測るため、HammerDB の TPROC‑C を使用しました。
HammerDB のインストール
|
1 2 |
dnf install -y https://github.com/TPC-Council/HammerDB/releases/download/v6.0/hammerdb-6.0-1.el9.x86_64.rpm /opt/HammerDB-6.0/hammerdbcli |
MySQL 用ユーザー作成。
|
1 2 3 |
CREATE USER hammerdb@localhost IDENTIFIED BY 'hammerdbpass'; ALTER USER hammerdb@localhost IDENTIFIED WITH sha256_password BY 'hammerdbpass'; GRANT ALL ON tpcc.* TO hammerdb@localhost; |
スキーマ構築
HammerDB のインストール、ユーザー作成、スキーマ構築(1000 Warehouse)を行いました。
1000 Warehouseで大体130GBほどのデータが生成されました。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
dbset db mysql dbset bm tpc-c diset connection mysql_host 127.0.0.1 diset connection mysql_port 3306 diset connection mysql_socket null diset tpcc mysql_user hammerdb diset tpcc mysql_pass hammerdbpass diset tpcc mysql_count_ware 1000 buildschema |
負荷実行設定
負荷実行設定(Rampup 2分 + 60分の本負荷)を行いました。
|
1 2 3 4 5 6 7 8 |
loadscript diset tpcc mysql_driver timed diset tpcc mysql_rampup 2 diset tpcc mysql_duration 60 vuset vu 32 vuset logtotemp 1 |
Prometheus によるメトリクス収集
Prometheus + mysqld_exporter を用いて、以下のメトリクスを収集しました。
-
mysql_global_status_innodb_buffer_pool_reads -
mysql_global_status_innodb_buffer_pool_read_requests -
mysql_global_status_innodb_buffer_pool_bytes_dirty -
mysql_global_status_innodb_buffer_pool_bytes_data -
mysql_global_status_innodb_buffer_pool_read_ahead_rnd -
mysql_global_status_innodb_buffer_pool_read_ahead_evicted -
mysql_global_status_innodb_buffer_pool_read_ahead
計測の自動化
Buffer Pool サイズを変更しながら HammerDB をループ実行するため、
以下のような自動化スクリプトを使用しました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
BP_LIST=("4G" "8G" "12G" "16G" "20G" "24G" "28G" "31G") for BP in "${BP_LIST[@]}"; do # Prometheus 設定変更 sed -i "s/bp_size:.*/bp_size: \"$BP\"/" /etc/prometheus/prometheus.yml systemctl restart prometheus # MySQL 設定変更 sed -i "s/^innodb_buffer_pool_size.*/innodb_buffer_pool_size = $BP/" /etc/my.cnf systemctl restart mysqld hammerdbcli <<EOF vucreate vurun vudestroy quit EOF done |
Prometheus 側には bp_size というラベルを付与し、
Buffer Pool サイズごとにメトリクスを比較できるようにしました。
(要点のみ抜粋)
/etc/prometheus/prometheus.yml
|
1 2 3 4 5 6 7 8 9 10 11 |
- job_name: node static_configs: - targets: ['localhost:9100'] labels: bp_size: "4G" -- - job_name: 'mysql' static_configs: - targets: ['localhost:9104'] labels: bp_size: "4G" |
HammerDB の結果(NOPM / TPM)
Buffer Pool サイズを段階的に変更しながら、
HammerDB(TPROC‑C)で 1時間の負荷をかけた結果は以下のとおりです。
|
Buffer Pool |
NOPM |
TPM |
|---|---|---|
|
4GB |
20,641 |
47,937 |
|
8GB |
18,991 |
44,093 |
|
12GB |
18,889 |
43,895 |
|
16GB |
25,499 |
59,183 |
|
20GB |
35,028 |
81,365 |
|
24GB |
36,744 |
85,321 |
|
28GB |
38,997 |
90,572 |
|
31GB |
35,053 |
81,434 |
NOPM(New Orders Per Minute/新規注文処理数)と TPM(Transactions Per Minute/トランザクション数)はTPROC‑C の性能指標です。
結果の傾向
Buffer Pool を増やすにつれて NOPM / TPM は上昇しました。
特に 20GB 以降で伸びが大きくなり、ワーキングセットが Buffer Pool に収まり始めた可能性があります。
NOPM / TPM が最大となったのは 28GB でした。
データページのキャッシュ効率が最も高く、物理読み込みが最小化されたと考えられます。
31GB に増やすと性能が低下しました。
このことから、Buffer Pool は大きすぎても性能が落ちる場合があると判断できます。
グラフ化すると、性能曲線は一定サイズまでは改善し、その後は悪化する山型の形状です。
Prometheus メトリクスの分析
HammerDB の結果だけでも Buffer Pool の最適値はある程度見えてきますが、
内部メトリクスを観測することで 「なぜそのサイズが最適なのか」 をより正確に理解できるようになります。
mysqld_exporterメトリクスの分析
MySQL GLOBAL STATUSのメトリクスです。
物理読み込み(innodb_buffer_pool_reads)
最も重要な指標です。
InnoDB がディスクからページを読み込んだ回数を示します。 Buffer Pool に収まらないデータが多いほど物理読み込みが増え、ディスク I/O が増加します。
始めのうちは急激なスパイクが見られますが、その後はなだらかな下降となっています。
Buffer Pool が小さいほど物理読み込みが多く、 特に 4GB は常に高い増加量を示していました。 ディスク I/O が増えるため、性能に大きく影響します。
Data ページ量(innodb_buffer_pool_bytes_data)
Buffer Pool 内に保持されているデータページの総量です。
4GB〜20GBではある時点で頭打ちになりました。24GB以上では、ワーキングセットが収まっており、 Data ページ量は増加の一途です。
TPCC 1000 warehouse(約130GB)を用意しましたが、 実際のワーキングセットは 24GB の Buffer Pool に収まっていたようです。
ダーティページ率(innodb_buffer_pool_bytes_dirty / innodb_buffer_pool_bytes_data)
変更済みでまだディスクへ書き戻されていないページの割合です。
Buffer Pool が小さいほどダーティページ率が高くなり、 書き込み負荷が増加していました。 これは redo/doublewrite の負荷増加につながります。
Buffer Pool ヒット率(1 – (innodb_buffer_pool_reads / innodb_buffer_pool_reads_requests))
読み込み要求が Buffer Pool 内で完結した割合です。
どの Buffer Pool サイズでも 99〜100%で横並びとなり、 Buffer Pool サイズによる差はほとんど見られませんでした。 ワーキングセットが比較的コンパクトであることを示しています。
read-ahead evicted(innodb_buffer_pool_read_ahead_evicted)
先読みで読み込んだページがすぐに追い出された回数です。
4GB のときだけ発生していました。 8GB 以上ではワーキングセットが収まり、 read-ahead で読み込んだページがすぐ追い出されることはありませんでした。
mysqld_exporter のメトリクスから、 ワーキングセットは 24GB 程度で収まっており、Buffer Pool をそれ以上にしても効果が限定的である
ということが読み取れます。
node_exporterメトリクスの分析
続いてOSのメトリクスです。
I/O待ち時間(node_cpu_seconds_total, mode=iowait)
iowait はディスク I/O の待ち時間を示す指標です。
今回の検証では、どの Buffer Pool サイズでも iowait はなだらかに増加するだけで、 瞬間的な I/O づまりは発生していませんでした。 ただし、Buffer Pool が大きくなるほど OS のページキャッシュが圧迫されるため、 I/O の平均速度は少しずつ悪化していると考えられます。
スワップアウト(node_vmstat_pswpout)
OS がメモリ不足になった瞬間にページをスワップへ追い出した回数です。
グラフでは、Buffer Pool が大きい設定ほど 途中で階段状に跳ね上がる箇所が見られます。 これは、負荷中に OS がページキャッシュを増やしたいタイミングでメモリ不足が発生し、 kswapd が追加のスワップアウトを実行した瞬間を示しています。
スワップイン(node_vmstat_pswpin)
スワップに追い出されたページを再びメモリに読み戻した回数です。
Buffer Pool が大きいほど pswpin が増加し、 特に 24GB 以上 では負荷中に階段状の増加が目立ちます。 これは、必要なページがスワップに押し出されてしまい、 処理のために読み戻しが発生している状態です。
最適な Buffer Pool の考え方
今回の結果を総合すると、 Buffer Pool の最適値は「ワーキングセットが収まり、かつ OS のページキャッシュを奪いすぎない」サイズです。
具体的には次のように考えられます。
20GB までは効果がある
-
ワーキングセットが収まる
-
物理読み込みが減る
-
ダーティページ率も安定
-
OS のページキャッシュも十分残る。
-
MySQL と OS のバランスが良い
24GB を超えると OS が苦しくなる
-
pswpout が増加(メモリ不足の瞬間)
-
pswpin が負荷中に発生(性能劣化の直接要因)
-
OS ページキャッシュが枯渇
-
性能が低下し始める
まとめ:OS・MySQL・性能指標の3点から見た Buffer Pool の最適値
今回、Buffer Pool を 4GB〜31GB まで段階的に変更し、 HammerDB(TPROC‑C)で 1時間の負荷をかけて性能を測定しました。 同時に mysqld_exporter と node_exporter のメトリクスを収集し、 OS と MySQL の両面から挙動を確認しました。
HammerDB(TPROC‑C)の性能は 28GB がピークで、 31GB にすると逆に性能が落ちています。
MySQL のメトリクスから、 ワーキングセットは 20GB 程度で十分であることが分かります。
HammerDB のワーキングセットは一定ですが、本番環境ではより複雑に変動します。今回の検証が、あなたの環境で Buffer Pool を見直す際の一助となれば幸いです。


