はじめに
CentOS 6とCentOS 7とAmazon LinuxではデフォルトのI/Oスケジューラに違いがあるため、ioniceコマンドを実行するときやパフォーマンスチューニングをするときに注意が必要だ。
各OSでのデフォルトI/Oスケジューラ
CentOS 6ではI/Oスケジューラはcfqになっている。CentOS 7ではdeadlineに変更された。(https://access.redhat.com/solutions/32376)
In RHEL 7, the deadline IO scheduler is the default IO scheduler for all block devices except SATA disks. For SATA disk, the default IO scheduler is cfq.
Amazon Linuxではnoopになっている。
CentOS 6
$ cat /etc/redhat-release && uname -r CentOS release 6.7 (Final) 2.6.32-279.el6.x86_64 $ cat /sys/block/sda/queue/scheduler noop anticipatory deadline [cfq]CentOS 7
$ cat /etc/redhat-release && uname -r CentOS Linux release 7.3.1611 (Core) 3.10.0-229.el7.x86_64 # SATAディスクではないので、デフォルトI/Oスケジューラはcfqではなくdeadlineになっているはず $ dmesg | grep sd[a-z] | grep SCSI [ 1.029523] sd 2:0:0:0: [sda] Attached SCSI disk $ cat /sys/block/sda/queue/scheduler noop [deadline] cfqAmazon Linux
$ uname -r 4.4.23-31.54.amzn1.x86_64 $ cat /sys/block/xvda/queue/scheduler [noop]
I/Oスケジューラ
http://tfcenturion.hatenablog.com/entry/2015/11/07/091307にI/Oスケジューラの各種について、簡潔にまとめられているので引用する。
noop
最もシンプルなスケジューラで、I/O要求を単純に要求順に処理する。
noopはスケジューリング負荷が小さく、ランダムアクセスが高速なハードウェアに適していると考えられている。deadline
ディスク上で位置が近いI/O要求を優先して処理を行うことで、HDDヘッドの移動量を削減する。位置が近いI/O要求を優先するため、HDDヘッドから遠くにあるI/O要求は後回しされるが、待ち時間の限界値(deadline)より長く待たされているI/O要求が発生した際には、そのI/O要求を優先する。
deadlineの設定によりレイテンシの上限が保証されるため、リアルタイムアプリケーションやデータベース管理に適していると言われている。anticipatory(AS)
I/O要求を予測し、その予測に基づいて処理を行う。位置が近い場所へのI/Oがすぐ後に発行されると予測 した場合、I/O要求の処理を遅延させ、近隣のI/O要求が発行されるのを待ってから、I/O要求の処理を行う。つまり、いくつかのI/O要求を貯めてから処理を行う性質がある。
ただしDeadlineと同様に、待ち時間の長いI/O要求が発生した場合にはI/O待ちを中断し、待ち時間の長いI/O要求を優先して処理する。
anticipatoryは、データにシーケンシャルにアクセスするWebサーバなどに有効とされている。cfq(Completely Fair Queuing)
スケジューラは内部に多数のキューを保持しておき、プロセス単位でI/O要求をそれらキューに割り振っていく。処理対象のキューを一定間隔で切り替えることで、プロセス間でI/O要求は公平に処理されていく。
また、Deadlineやanticipatoryと同様に待ち時間の長いI/O要求が存在した場合、それを優先的に処理していく。
I/Oスケジューラとパフォーマンス
クラウドと仮想化
Linux 2.6 カーネル ベースの仮想マシンでディスク I/O パフォーマンスが遅い (2094615)に書かれている通り、「仮想化された環境では多くの場合、I/O をホスト レイヤーとゲスト レイヤーの両方でスケジュールすることは有益ではなく」、ゲストが頑張るよりもホストに任せた方がいい。NOOP または Deadline のパフォーマンスが仮想化された Linux ゲストに対し向上したことが示されたとのことなので、クラウド全盛の現在は、デフォルトがNOOP または DeadlineになっているCentOS 7あるいはAmazon Linuxは、この観点では適切なのだろう。
noopでもdeadlineでもVMwareのテストでは効果がでたとのことだが、ホストに極力任せるという観点からはnoopの方がよさそう。
CentOS 6のEOLは2020/11/30だが、現時点でもCentOS 6のサーバをクラウド上で動かし、I/Oをヘビーユースするのであれば、I/Oスケジューラを変えた方がパフォーマンスがあがるかもしれない。
ディスク/dev/sdaのI/Oスケジューラを変更するのであれば、以下のように変更する。
$ sudo su -
# cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]
# echo noop > /sys/block/sda/queue/scheduler
# cat /sys/block/sda/queue/scheduler
[noop] anticipatory deadline cfq
サーバを再起動したら元に戻ってしまうので、/etc/rc.localに記入したり、initスクリプト化してchkconfig onにしたりするといい。
/dev/sdaだけのように各ディスク単位ではなく、サーバ全体でI/Oスケジューラを変更し、さらに永続化したければ、/etc/grub.confを編集する。/etc/grub.confのkernel行にelevator=deadlineやelevator=noopを追記して再起動すればいい。
CentOS 7であれば/etc/grub.confではなく/etc/default/grubのGRUB_CMDLINE_LINUX行にelevator=noopを書いてから、/boot/grub2/grub.cfgをrebuildするためにgrub2-mkconfig -o /boot/grub2/grub.cfgを実行する。
参考:https://access.redhat.com/solutions/32376
SSD
現在はクラウドとともにSSDを使うことも多くなっている。ランダムアクセスが高速なハードウェアに適しているnoopを選択することでパフォーマンス向上するかもしれない。
deadlineもanticipatoryもHDDヘッドの移動量が少なくなるようにするロジックなので、HDDヘッドがないSSDには適切なロジックではない。
ionice
ioniceはcfqじゃないと意味がない
パフォーマンス観点でcfqからnoopに変えた方がいいという話をしてきたが、パフォーマンスとは真逆のI/O負荷をできるだけ抑えながら処理をさせるioniceについても考えなければならない。
ioniceが効く場合は限られていて、I/Oスケジューラがcfqでないと効果がない。
ioniceが効く条件
- I/Oスケジューラが
cfqである Read()であるWrite()の場合は、-o syncでマウントされているかO_DIRECT,O_SYNCフラグを立てている
参考:
その ionice、ほんとに効いてますか?
【続編】その ionice、ほんとに効いてますか?
またLVMやソフトウェアRAIDを組んでいる場合も、ioniceは無意味となる。
CFQ is the default for scheduling actual physical disks, but small things like software RAID and LVM do not have disk schedulers at all and as far as I can tell ionice is completely ineffectual on them (for both read and write IO)
参考:Some notes on Linux's ionice
ioniceの代わり
コピーのときのio負荷を減らしたい場合
rsyncの--bwlimitで帯域制限を行う。R/W両方とも負荷が減る。
巨大なファイルを削除する場合
大量・巨大なファイル操作を低負荷で行う方法でtruncateを使った方法が紹介されていた。
#/bin/bash
set -euo pipefail
filepath=$1
# 10MBytes/sec
filesize=$(du -m ${filepath} | awk '{print $1}')
sleep_time=0.1
for num in $(seq 1 ${filesize});
do
truncate -s $((${filesize}-${num}))M ${filepath}
sleep ${sleep_time}
done
\rm ${filepath}