この記事では、MySQLデータベースサーバーのパフォーマンスチューニングと最適化のために調整する重要なLinuxの設定を復習します。OSのチューニングに使うLinuxのパラメータのいくつかは、物理サーバーか、仮想サーバーか、クラウドかというシステムの種類ごとに異なりますが、それがどう異なるかについても触れます。MySQLのパラメータについては、Alexanderの「インストール直後のMySQL 5.7パフォーマンスチューニング(MySQL 5.7 Performance Tuning Immediately After Installation)」というブログなど他の記事で扱います。その記事はMySQL 5.7や8.0といった最新バージョンに強く関連した内容ですが、この記事ではデータベースパフォーマンスに影響を及ぼしうるLinuxのOSパラメーターについて焦点を当てていきます。
サーバーとOS
データベースのパフォーマンスを改善したい時に確認の上変更を検討すべきLinuxのパラメータです。
カーネル - vm.swappiness
これは、メモリーページをスワップアウトする度合いを表す値です。十分にRAMを持ったサーバでは、この値はできる限り小さくしておくべきでしょう。余計なI/Oはサービスのスローダウンやサービス停止を引き起こしかねません。0に設定するとスワップを完全に無効にし、1にするとカーネルは最低限のスワップしか行いません。大抵は1に設定すればよいでしょう。
# rootでswappinessを設定
echo 1 > /proc/sys/vm/swappiness
# あるいは代わりにsysctlを使用して設定
sysctl -w vm.swappiness=1
# 設定が変更されたのを確認
cat /proc/sys/vm/swappiness
1
# sysctlでも確認できます
sysctl vm.swappiness
vm.swappiness = 1
設定は /etc/sysctl.conf
に永続化も可能です。
vm.swappiness = 1
ファイルシステム XFS/ext4/ZFS
XFS
XFSは高いスケーラビリティーを実現するために設計された、ハイパフォーマンスなジャーナリングファイルシステムです。XFSは、ファイルシステムが複数のストレージデバイスにまたがっている場合も含め、ネイティブに近いI/Oパフォーマンスを発揮します。また、8EiBまでのファイルサイズをサポートし、非常に大きいファイルシステムに向いた機能も持っています。リカバリが速く、トランザクションも高速で、フラグメンテーションを減らす遅延アロケーションや、DIRECT I/Oによるraw I/Oに近いパフォーマンスもサポートされています。
mkfs.xfs
のデフォルトオプションは最適な速度になる優れた設定なので、シンプルに
# デフォルトのmkfsオプションを使用
mkfs.xfs /dev/target_volume
を実行すれば、データの安全性を確保しつつ最高のパフォーマンスが得られます。マウントオプションについては、ほとんどのケースでデフォルトのまま使用できます。ファイルシステムによっては、/etc/fstab
にnoatime
マウントオプションを追加するとパフォーマンスの向上があるでしょう。XFSでのatime
のデフォルトの挙動は、noatime
と比べてほとんどオーバーヘッドがなくatime
と同じ値を保持するrelatime
になります。バッテリーバックアップ付きで不揮発性のLUN上にXFSでファイルシステムを作ったら、nobarrier
マウントオプションをつけてライトバリアーを無効化することで、必要以上にデータをフラッシュすることがなくなるので、ファイルシステムのパフォーマンスをさらに改善できます。BBU(backup battery unit)がない、あるいはあるかどうか分からないなら、バリアーはそのままにしておいて、データの一貫性を台無しにすることのないようにしましょう。このオプションを有効にするなら、/etc/fstab
は以下のようになります。
/dev/sda2 /datastore xfs defaults,nobarrier
/dev/sdb2 /binlog xfs defaults,nobarrier
ext4
ext4は、パフォーマンス改善を加えてext3の後継として開発されてきました。ほとんどのワークロードに合った、間違いのないファイルシステムの選択肢です。16TBまでというxfsよりも小さなファイルサイズしかサポートしていない点に注意しましょう。テーブルスペースのサイズが非常に大きかったり、大きくなる場合は注意する必要がある点です。データの一貫性をリスクにさらさず堅牢なファイルシステムを使うには、デフォルト設定を推奨します。しかし、BBUキャッシュがあるエンタープライズ向けストレージコントローラーを使っている場合、以下のマウントオプションで最高のパフォーマンスが得られるでしょう。
/dev/sda2 /datastore ext4 noatime,data=writeback,barrier=0,nobh,errors=remount-ro
/dev/sdb2 /binlog ext4 noatime,data=writeback,barrier=0,nobh,errors=remount-ro
注意 : data=writeback
オプションによって、実際のファイルデータを除いたメタデータだけがジャーナリングされます。突然の電源停止の際、最近変更されたファイルが壊れる可能性があります。ただし、BBUが有効なコントローラーがある時にはそのリスクは低くなります。nobh
はdata=writeback
オプションが有効な時だけ意味があります。
ZFS
ZFSは、データの保護と破損のバランスを取った、ファイルシステムとLVMを組み合わせたエンタープライズストレージソリューションです。ZFSの豊富な機能セットが、採用を考える際の重要な項目になるケースは確かにあって、中でも高度なボリューム管理が必要条件の際はそうです。MySQL向けのZFSチューニングは複雑なトピックなので、このブログの対象からは外れます。詳しい情報は、Yves Trudeauによってこのトピックについて書かれたブログ記事を参照してください。
ディスクサブシステム - I/Oスケジューラー
ほとんどのモダンなLinuxディストリビューションでは、デフォルトでnoop
かdeadline
I/Oスケジューラが設定されていて、これらはどちらもcfq
やanticipatory
よりもいいパフォーマンスが出ます。しかし、各デバイスのスケジューラーをいつもチェックするのはいい習慣です。もしnoop
あるいはdeadline
以外のスケジューラーが設定されていたら、サーバーを再起動することなくポリシーを変更できます。
# I/Oスケジューラーの設定を確認。角かっこに入っている値が実行中のスケジューラー
cat /sys/block/sdb/queue/scheduler
noop deadline [cfq]
# 設定を変更
sudo echo noop > /sys/block/sdb/queue/scheduler
設定を永続化するには、GRUB設定ファイルを変更する必要があります。
# この行を変更
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
# 変更後は以下のようにする
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash elevator=noop"
AWSでの注意 : I/Oスケジューラーがnone
になるケースがあり、その一番の例がEBSボリュームがNVMeブロックデバイスであるAWS VMインスタンスタイプの場合です。これは、モダンなPCIe/NVMeデバイスではこの設定が使われないためです。このようなデバイスは内部に非常に大きなキューを持っており、I/Oスケジューラーをバイパスしてしまうのが理由です。この場合、そのようなディスクに最適なよう、設定はnone
になります。
ディスクサブシステム - ボリューム最適化
可能であれば、OS、binlog、データ、redo logはそれぞれ異なるディスクボリュームを使うのが理想的です。論理的に分けるだけでなく物理的にOSとデータパーティションを分けることで、データベースのパフォーマンスはよくなります。RAIDレベルもパフォーマンスに影響があります。チェックサムの整合性を保つのにコストがかかるので、RAID-5は避けた方がよいでしょう。冗長性を妥協せずに最高のパフォーマンスを得るには、バッテリーバックアップされたキャッシュユニットを持った高度なコントローラーを使い、できれば複数のディスクにまたがったRAID-10ボリュームを使いましょう。
AWSでの注意 : EBSボリュームやAWSのストレージ最適化についての詳しい情報は、以下のリンクにあります。
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/storage-optimized-instances.html
データベース設定
システムアーキテクチャ - NUMAの設定
Non-Uniform Memory Access (NUMA)とは、SMPなシステムのプロセッサーから見て、ローカルでないメモリー(他のCPUに割り当てられたメモリー)よりもローカルなメモリーに高速にアクセスできるというメモリーデザインのことです。これにより、データベースのパフォーマンスが最適な状態でなくなったり、スワップが発生したりする可能性があります。ノードのローカルなRAMのサイズよりもバッファプールのメモリー割り当てが大きく、かつメモリアロケーションポリシーがデフォルトの場合、スワップが発生します。NUMAが有効なサーバーは、CPUノード間でそれぞれ異なるノード距離(node distance)を通知してきます。無効なサーバでは、1種類の距離しか通知しません。
# NUMAなシステム
numactl --hardware
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 65525 MB
node 0 free: 296 MB
node 1 cpus: 8 9 10 11 12 13 14 15
node 1 size: 65536 MB
node 1 free: 9538 MB
node 2 cpus: 16 17 18 19 20 21 22 23
node 2 size: 65536 MB
node 2 free: 12701 MB
node 3 cpus: 24 25 26 27 28 29 30 31
node 3 size: 65535 MB
node 3 free: 7166 MB
node distances:
node 0 1 2 3
0: 10 20 20 20
1: 20 10 20 20
2: 20 20 10 20
3: 20 20 20 10
# NUMAが無効な(uniformな)システム
numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 64509 MB
node 0 free: 4870 MB
node distances:
node 0
0: 10
NUMAシステム、つまりnumactl
がノードごとに違った距離を表示する場合、メモリーインターリーブを避けるためにMySQLのinnodb_numa_interleave
が有効になっている必要があります。Percona Serverでは、flush_caches
変数を導入することで、NUMAのサポートを改善しています。これが有効な時は、ノード間の割り当てが公平になるようになります。ノード間で割り当てが均等かどうかを確認するには、スクリプトでmysqldプロセスに対するnuma_maps
を調べてみましょう。
# CPUノードごとのメモリー割り当てを表示するnuma_maps.plというPerlスクリプト
# 3595はmysqldプロセスのpid
perl numa_maps.pl < /proc/3595/numa_maps
N0 : 16010293 ( 61.07 GB)
N1 : 10465257 ( 39.92 GB)
N2 : 13036896 ( 49.73 GB)
N3 : 14508505 ( 55.35 GB)
active : 438 ( 0.00 GB)
anon : 54018275 (206.06 GB)
dirty : 54018275 (206.06 GB)
kernelpagesize_kB: 4680 ( 0.02 GB)
mapmax : 787 ( 0.00 GB)
mapped : 2731 ( 0.01 GB)
まとめ
この記事では、OSに関係したいくつかの設定を分析し、データベースパフォーマンスの改善のためにどのようにチューニングできるかを説明しました。
Webinarの録画Troubleshooting Best Practices: Monitoring the Production Database Without Killing Performanceもおすすめです。