1. 程式人生 > >Cgroup blkio簡介和測試(使用fio測試)

Cgroup blkio簡介和測試(使用fio測試)

diff 了解 ont 電梯 iostat tmpfs del let dev

Cgroup blkio簡介和測試(使用fio測試)

因需要對docker鏡像內的進程對磁盤讀寫的速度進行限制,研究了下Cgroup blkio,並使用fio對其iops/bps限速進行測試。

Cgroup blkio簡介

Linux Cgroup(Control Groups)是Linux內核提供的用於限制、記錄、隔離進程組可以使用的資源(cpu、memory、IO等)的一種機制。
在/boot下面的對應config文件裏查看Cgroup內核選項:

CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_THROTTLING=y

blkio子系統

Cgroup裏每個子系統(SubSystem)對應一種資源,Cgroup blkio子系統用於限制塊設備I/O速率。
掛載Cgroup root目錄以及blkio子系統如下所示:

mount -t tmpfs cgroup_root /sys/fs/cgroup
mkdir /sys/fs/cgroup/blkio
mount -t cgroup -o blkio none /sys/fs/cgroup/blkio

在對應的子系統目錄下通過mkdir創建資源組,rmdir可將對應資源組刪除。通過將進程pid加入到資源組目錄下的tasks文件的方式把某個進程加入到對應資源組。如下所示:

mkdir /sys/fs/cgroup/blkio/test
echo 9527 > /sys/fs/cgroup/blkio/test/tasks

blkio資源限制策略

blkio支持兩種IO資源限制策略:IO調度權重和iops/bps限制

  1. IO調度權重

通過設置資源組IO的權重比例實現IO限制,該策略基於CFQ調度算法(Linux內核磁盤IO電梯算法)通過分配其IO處理的時間片來實現,因此需要確認磁盤對應的電梯算法為CFQ(Linux默認值)。
單個資源組權重取值範圍100-1000。設置方法如下:

echo 500 > blkio.weight
echo "8:0 500" > blkio.weight_device

其中8:0為磁盤設備號(major:minor)。具體設備的weight_device權重的優先級高於weight默認權重。

IO調度權重使用CFQ調度算法,顯得比較公平,其保障資源組最低的IO比例(對應iops有最低保證)。在設備空閑的時候,還能超限使用。因此不適用於需要嚴格限制資源組IO資源上限的場景。

  1. iops和bps限制

支持設置資源組讀和寫的iops、bps上限。這樣在該資源組內的進程讀寫IO的iops和bps不會超出設置值。設置方法如下:

echo "8:0 102400" > blkio.throttle.read_bps_device
echo "8:0 10" > blkio.throttle.read_iops_device
echo "8:0 204800" > blkio.throttle.write_bps_device
echo "8:0 20" > blkio.throttle.write_iops_device

其中讀bps限定在100KB,讀iops限定在10。可以只設置讀或者寫的iops,或者bps,也可以都設置。

相比IO調度權重,iops和bps限制更加直接和量化,更適合用於限制docker容器磁盤IO上限。

使用fio測試blkio

當前3.3版本的fio支持配置cgroup進行測試,但只支持配置cgroup的weight值。
為了測試blkio iops/bps限制,在該版本fio基礎上,添加了支持配置iops/bps的代碼。可從github上直接下載編譯修改後的fio。

blkio iops/bps功能測試

使用fio啟動兩個進程分屬兩個Cgroup進行blkio功能測試,fio配置文件如下:

[root@A03-R14-I156-1 jimbo]# cat test.fio 
[global]
bs=4K
ioengine=libaio
iodepth=32
direct=1
rw=randrw
rwmixread=50
time_based
runtime=60
cgroup_nodelete=0

[test1]
filename=/export/kubelet/pods/802b34b1-eac7-11e7-bc92-246e9665d1b0/volumes/kubernetes.io~lvm/export/fio/test1.img
size=512M
cgroup_read_iops=8:16 100
cgroup_write_iops=8:16 100
cgroup_read_bps=8:16 1024000
cgroup_write_bps=8:16 1024000
cgroup=test1

[test2]
filename=/export/kubelet/pods/802b34b1-eac7-11e7-bc92-246e9665d1b0/volumes/kubernetes.io~lvm/export/fio/test2.img
size=512M
cgroup_read_iops=8:16 1000
cgroup_write_iops=8:16 1000
cgroup_read_bps=8:16 102400
cgroup_write_bps=8:16 102400
cgroup=test2

其中Cgroup設備號需要設置為物理磁盤(如sdb)或者lvm卷(如dm-5)的設備號,設置為磁盤分區(如sdb1)設備號或者loop設備號時是無效的。
對於docker鏡像使用lvm磁盤時,測試結果顯示設置設備號為lvm盤和物理磁盤的限速效果是一樣的。
如果將bs設置過大,會導致buffered read/write時大量的IO在緩存命中,並沒有實際提交給磁盤,此時fio的統計的iops/bps是不準的。
所以本次測試設置bs=4K,盡量避免緩存命中的情況發生。

啟動fio測試:

[root@A03-R14-I156-1 jimbo]# ./fio ./test.fio

可直接查看fio輸出讀寫IOPS和BW統計,需要註意有些場景(如buffered write)fio的輸出並不準確,還需要結合iostat等磁盤統計工具進一步確認磁盤iops/bps的真實情況。
fio的輸出如下:

test1: (groupid=0, jobs=1): err= 0: pid=619842: Fri Dec 29 16:28:41 2017
   read: IOPS=98, BW=392KiB/s (402kB/s)(23.0MiB/60109msec)
   ...
   write: IOPS=99, BW=396KiB/s (406kB/s)(23.3MiB/60109msec)
   ...
test2: (groupid=0, jobs=1): err= 0: pid=619843: Fri Dec 29 16:28:41 2017
   read: IOPS=23, BW=94.7KiB/s (96.0kB/s)(5768KiB/60917msec)
   ...
   write: IOPS=25, BW=100KiB/s (103kB/s)(6100KiB/60917msec)
   ...

可以看到test1被IOPS限制在了100,test2被bps限制在了100KiB/s。

使用該方法測試了randread、randwrite、randrw結果如下:

  • DIO read、DIO write、buffered read都被成功限制住了iops/bps;
  • buffered write卻並沒有被限制住;

Buffered write沒有被限制住,是因為本次測試基於CentOS 7.2內核版本號為3.10.0,該版本內核blkio有如下描述:

Currently only sync IO queues are support. All the buffered writes are still system wide and not per group. Hence we will not see service differentiation between buffered writes between groups.

從YY哥分析的Buffer IO的throttle問題可以看到buffered寫IO在內核異步線程提交時無法獲取到用戶進程信息,因此blkio無法支持buffered write的統計。該問題在4.2版本的Cgroup V2上得到了解決,該版本Cgroup相比V1做了很大改進並支持了writeback。詳情可參看博客Cgroup V2 and writeback support。

blkio壓力測試

通過如下腳本測試在同一個資源組上啟動N個fio進程進行blkio壓力測試:

#!/bin/bash

for ((N=0; N<100; N++))
do
        ./fio -filename=/export/kubelet/pods/802b34b1-eac7-11e7-bc92-246e9665d1b0/volumes/kubernetes.io~lvm/export/fio/test$N.img -size=256M -rw=randrw -ioengine=libaio -iodepth=32 -bs=4K -direct=1 -rwmixread=50 -time_based -runtime=60 -cgroup_nodelete=0 -cgroup=test -cgroup_read_iops="8:16 10000" -cgroup_write_iops="8:16 10000" -cgroup_read_bps="8:16 10240000" -cgroup_write_bps="8:16 10240000" -name=test$N -output=./output$N &
done

sleep 60

測試結果顯示,N=100個進程測試時,所有IO總和都被限定在了test資源組設置的iops和bps下。

修改上述腳本中-cgroup=test-cgroup=test$N,即可進行在N個資源組上啟動N個fio進程進行blkio壓力測試。
測試結果顯示,當IO超出物理磁盤的能力時,每個資源組上的進程都無法達到iops和bps的限制,基本上比較平均的占用磁盤帶寬。

Cgroup blkio簡介和測試(使用fio測試)