雲計算&存儲測試:FIO工具入門與實戰


一、關於FIO

1.1 簡介

FIO是一個開源的I/O壓力測試工具,主要是用來測試磁盤的IO性能,也可測試cpu,nic的IO性能。它可以支持13種不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, network, syslet, guasi, solarisaio, I/Opriorities (針對新的Linux內核), rate I/O, forked or threaded jobs等。

fio 官網地址:http://freshmeat.net/projects/fio/

fio文檔:https://fio.readthedocs.io/en/latest/index.html

2.1 常用測試場景

FIO相關測試場景:

順序讀寫 (吞吐量,常用單位為MB/s):文件在硬盤上存儲位置是連續的。

適用場景:大文件拷貝(比如視頻音樂)。速度即使很高,對數據庫性能也沒有參考價值。

4K隨機讀寫 (IOPS,常用單位為次):在硬盤上隨機位置讀寫數據,每次4KB。

適用場景:操作系統運行、軟件運行、數據庫。

二、FIO安裝

有三種安裝方式

2.1 apt安裝(Ubuntu)

#更新apt源 
apt update 
#安裝fio 
apt-get install fio

 

2.2 使用yum安裝(centos)

#更新yum源 
yum install epel-release
#安裝fio 
yum install libaio-devel fio

2.3 手動安裝

wget http://brick.kernel.dk/snaps/fio-2.2.10.tar.gz yum install libaio-devel tar -zxvf fio-2.2.10.tar.gz cd fio-2.2.10 
make 
make install

附上一個基本涵蓋所有操作系統的FIO包下載地址的網址:https://pkgs.org/download/fio

2.4 驗證是否安裝成功

輸入:fio -h,看是否安裝成功

三、FIO使用

3.1 fio參數解釋

可以使用fio -help查看每個參數,具體的參數左右可以在官網查看how to文檔,如下為幾個常見的參數描述

filename=/dev/emcpowerb  支持文件系統或者裸設備,--filename=/dev/sdc或者--filename=/mnt/ccg/test_data(掛載的目錄下任意文件名)

direct=1                                測試過程繞過機器自帶的buffer,使測試結果更真實

rw=randwread                      測試隨機讀的I/O

rw=randwrite                        測試隨機寫的I/O

rw=randrw                            測試隨機混合寫和讀的I/O

rw=read                                測試順序讀的I/O

rw=write                                測試順序寫的I/O

rw=rw                                    測試順序混合寫和讀的I/O

bs=4k                                    單次io的塊文件大小為4k,如果是測試文件系統,建議和文件系統的塊大小保持一致。

bsrange=512-2048               同上,提定數據塊的大小范圍,這里是隨機生成一個范圍

time_based                           如果設置的話,即使file已被完全讀寫或寫完,也要執行完runtime規定的時間。它是通過循環執行相同的負載來實現的,與runtime相對應。

ramp_time=time                   設定在記錄任何性能信息之前要運行特定負載的時間。這個用來等性能穩定后,再記錄日志

size=5g                                本次的測試文件大小為5g,以每次4k的io進行測試,即生成讀寫的文件大小。

fdatasync=int                       同fsync,但是采用fdatasync()來同步數據,但不同步元數據

sync=bool                            使用sync來進行buffered寫。對於多數引擎,這意味着使用O_SYNC

numjobs=30                        本次的測試線程為30

iodepth=1                            隊列深度。默認是1,可以通過設置大於1的數來提升並發度。

runtime=1000                     測試時間為1000秒,如果不寫則一直將5g文件分4k每次寫完為止

ioengine=psync                  io引擎使用pync方式,如果要使用libaio引擎,需要yum install libaio-devel包

randrepeat=true                 對於隨機IO負載,配置生成器的種子,使得路徑是可以預估的,使得每次重復執行生成的序列是一樣的。

rwmixwrite=30                   在混合讀寫的模式下,寫占30%,推薦讀寫配比為7:3

group_reporting=1             關於顯示結果的,匯總每個進程的信息

此外

lockmem=1g                     只使用1g內存進行測試

zero_buffers                     用0初始化系統buffer

nrfiles=8                           每個進程生成文件的數量

 

3.2 fio測試場景及生成報告詳解

1)測試變量:

  • bs大小:(4k,16k,64k,1m)
  • 讀寫模式:(read,write,rw,randread,randwrite,randrw)
  • 使用libaio異步引擎,iodepth隊列長度為128。
  • 運行時間為60s

第一種:4K,順序寫

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=4k --group_reporting=1 --readwrite=write --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/4k_write

第二種:16K,順序讀

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=16k --group_reporting=1 --readwrite=read --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/16k_read

第三種:16K,混合讀寫,70%讀,30%寫

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=16k --group_reporting=1 --readwrite=rw  -rwmixread=70 --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/16k_rw

第四種:64k,隨機寫

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=64k --group_reporting=1 --readwrite=randwrite  --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/64k_randwrite

第五種:1m,隨機讀

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=1m --group_reporting=1 --readwrite=randread  --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/1m_randread

第六種:1m,隨機讀寫,70%讀,30%寫

fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=1m --group_reporting=1 --readwrite=randrw  -rwmixread=70  --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/1m_randrw

2)執行測試

root@client:/mnt/ccg# fio --randrepeat=1 --ioengine=libaio --direct=1 --name=ccg_fio --iodepth=128 --numjobs=16 --size=1g --bs=4k --group_reporting=1 --readwrite=write --time_based=1 --runtime=60 --sync=0 --fdatasync=0 --filename=/mnt/ccg/4k_write

報告詳解

#這一行列出了執行的關鍵參數

ccg_fio: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=128

...

fio-2.2.10

Starting 16 processes

ccg_fio: Laying out IO file(s) (1 file(s) / 1024MB)

Jobs: 16 (f=16): [W(16)] [100.0% done] [0KB/98.11MB/0KB /s] [0/25.2K/0 iops] [eta 00m:00s]

ccg_fio: (groupid=0, jobs=16): err= 0: pid=77217: Mon Jul 27 17:42:01 2020

  write: io=5662.2MB, bw=96631KB/s, iops=24157, runt= 60002msec              #io指的是讀寫的數據總量,iops是關鍵的測試指標,每秒io次數,runt是執行總時間

    slat (usec): min=3, max=5087, avg=611.46, stdev=640.30                            #slat=提交延遲,代表IO提交到kernel做處理的過程

    clat (usec): min=317, max=238746, avg=82794.77, stdev=24469.97            #clat=完成延遲,代表提交到kernel到IO做完之間的時間

     lat (usec): min=500, max=238761, avg=83406.74, stdev=24540.97             #lat=響應時間,IO結構體創建時刻開始,直到緊接着clat完成

    clat percentiles (msec):                                                                                   #分位分布圖

     |  1.00th=[   21],  5.00th=[   42], 10.00th=[   52], 20.00th=[   64],

     | 30.00th=[   73], 40.00th=[   79], 50.00th=[   85], 60.00th=[   90],                 #50分位:85us

     | 70.00th=[   95], 80.00th=[  101], 90.00th=[  110], 95.00th=[  120],              #90分位:110us,95分位:120us

     | 99.00th=[  151], 99.50th=[  167], 99.90th=[  192], 99.95th=[  200],             #99分位:151us

     | 99.99th=[  215]                                                                      

    bw (KB  /s): min=    4, max=14296, per=6.30%, avg=6087.37, stdev=1207.17                #bandwidth,帶寬

    lat (usec) : 500=0.01%, 750=0.01%, 1000=0.01%                                                            #latency分布:<500us占0.01%, 500us~750us占0.01%, <1000us占0.01

    lat (msec) : 2=0.01%, 4=0.03%, 10=0.19%, 20=0.71%, 50=8.30%                                  #latency分布:<2ms占0.01%, 2ms~4ms占0.03%, 4ms~10ms占0.19%, 10ms~20ms占0.71%,20ms~50ms占8.3%

    lat (msec) : 100=69.79%, 250=20.97%                                                                             #latency分布:<100ms占69.79%,100ms~250ms占20.97%

  cpu          : usr=0.76%, sys=5.97%, ctx=2862343, majf=0, minf=5759                               #cpu=利用率,和top命令中類似

  IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=0.1%, >=64=99.9%        #IO depths=io隊列

     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%      #IO submit=單個IO提交要提交的IO數

     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.1%       #IO complete=Like the above submit number, but for completions instead.

     issued    : total=r=0/w=1449515/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0                  #IO issued=The number of read/write requests issued, and how many of them were short.

     latency   : target=0, window=0, percentile=100.00%, depth=128                                     #IO latencies=IO完延遲的分布

Run status group 0 (all jobs):

  WRITE: io=5662.2MB, aggrb=96631KB/s, minb=96631KB/s, maxb=96631KB/s, mint=60002msec, maxt=60002msec

  #io=表示總共完成的IO數量。基於時間的測試場景下,此值為變量(時間越長讀寫次數越多);在基於容量的測試場景下,此值匹配size參數大小(最多只會讀寫文件大小的size)。

  #aggrb是所有進程/設備的匯總帶寬。

  #minb/maxb表示測量到的最小/最大帶寬。

  #mint/maxt表示測試的最短和最長耗時。基於時間的測試場景下,匹配runtime參數(基本一致),基於容量的測試,是一個變量(隨時間大小變化)。

3.3 fio的job文件格式

job file格式采用經典的ini文件,[]中的值表示job name,可以采用任意的ASCII字符,‘global’除外,global有特殊的意義。Global section描述了job file中各個job的默認配置值。一個job section可以覆蓋global section中的參數,一個job file可以包含幾個global section.一個job只會受到它上面的global section的影響。‘;’和‘#’可以用作注釋

例子1:兩個進程,分別從一個從128MB文件中,隨機讀的job file.

#global為全局配置,對每個job都生效

[global]

rw=randread

size=128m

 

[job1]

#這里的job名為job1,如果job1里面也定義rw,則會覆蓋global中的rw的值

#rw=randwrite

 

[job2]

#rw=rw

#–end job file–

job1和job2 section是空的,因為所有的描述參數是共享的。沒有給出filename=選項,fio會為每一個job創建一個文件名,如果用命令寫,則是:

fio –name=global –rw=randread –size=128m –name=job1 –name=job2

 

例子2多個進程隨機寫文件的實例

;–start job file —

[random-writers]

ioengine=libaio

iodepth=4

rw=randwrite

bs=32k

direct=0

size=64m

numjobs=4

;–end job file–

這個例子沒有global section,只有一個job section.

上一個實例的說明:采用async,每一個文件的隊列長度為4,采用隨機寫,采用32k的塊,采用非direct io,共有4個進程,每個進程隨機寫64M的文件。也可以采用下面的命令:

fio –name=random-writers –ioengine=libaio –iodepth=4 –rw=randwrite –bs=32k –direct=0 –size=64m –numjobs=4

 

3.4 環境變量(參數化)

在job file中支持環境變量擴展。類似於${VARNAME}可以作為選項的值(在=號右邊)

例子:

#如下是job配置文件

;–start job files–

[random-writers]

rw=randwrite

size=${SIZE}

numjobs=${NUMJOBS}

;–end job file–

如果執行:

export SIZE=64m  NUMJOBS=4 fio jobfile,fio

 

該文件將被擴展為

;–start job file–

[random-writers]

rw=randwrite

size=64m

numjobs=4

;–end job file–

 

Tips:

fio有一些保留keywords,在內部將其替換成合適的值,這些keywords是:

$pagesize   當前系統的頁大小

$mb_memory 系統的總內存的大小,以MB為單位

$ncpus 在線有效的cpu

這引起在命令行中和job file中都可以用,當job運行的時候,會自動的用當前系統的徝進行替換。支持簡單的數學計算,如:

size=8*$mb_memory

也就是說我們盡量不要用這些保留關鍵字進行變量命名

3.5 FIO的JOB配置文件實例

[global]

#定義了全局的默認配置,其中參數化了IODEPTH,NUMJOBS,SIZE,BS,MNT_POINT,RUNTIME,SIZE

iodepth=${IODEPTH}

numjobs=${NUMJOBS}

size=${SIZE}

bs=${BS}

directory=${MNT_POINT}

runtime=${RUNTIME}  ;e.g 10, 10m; default to seconds

time_based=1

randrepeat=1

ioengine=libaio

direct=1

sync=0

fdatasync=0

group_reporting=1

filename=qfs_fio_test_file_${SIZE}

[write]

#順序寫場景

name=qfs_write_${SIZE}

rw=write

[read]

#順序讀場景

name=qfs_read_${SIZE}

rw=read

[randread]

#隨機讀場景

name=qfs_randread_${SIZE}

rw=randread

[randwrite]

#隨機寫場景

name=qfs_randwrite_${SIZE}

rw=randwrite

[rw]

#混合讀寫場景,讀寫比為7:3,將讀寫結果最后合並統計(MIXED)

name=qfs_rw_${SIZE}

rw=rw

rwmixread=70

unified_rw_reporting=1

[randrw]

#隨機讀寫場景,讀寫比為7:3,將讀寫結果最后合並統計(MIXED)

name=qfs_randrw_${SIZE}

rw=randrw

rwmixread=70

unified_rw_reporting=1

3.6 FIO腳本編寫

#!/bin/bash

# trap Ctrl-C and call ctrl_c()

trap ctrl_c INT

#用於捕獲SIGKILL,強行中止本腳本

function ctrl_c() {

        echo "** Trapped Interupt Signal, Exit. **"

        exit 1

}


if [[ $# == 0 ]] || [[ $1 == '-h' ]]

then

    echo "sh $0 write 128 16 1g 4k 60s /mnt/test_fio_4k"

else

    #這里的參數傳遞:

    #TYPE:write,read,rw,randwrite,randread,randrw

    #JOB_FILE:qfs.fio,即3.5所示的文件

    #MNT_POINT:/mnt/ccg/xxx_file,即進行讀寫測試的文件路徑

    #IODEPTH:128

    #NUMJOBS:最大16進程進行操作

    #SIZE:測試的文件大小

    #BS:塊大小

    #RUNTIME:60s

    #JOB_FILE:qfs.fio

    export TYPE=$1  JOB_FILE=qfs.fio MNT_POINT=$7  IODEPTH=$2 NUMJOBS=$3 SIZE=$4 BS=$5 RUNTIME=$6; fio --section=$TYPE $JOB_FILE --output="output/qfs_fio-$IODEPTH-$NUMJOBS-$SIZE-$BS-$TYPE.output"

fi

四、參考資料

博主:測試生財(一個不為996而996的測開碼農)

座右銘:專注測試開發與自動化運維,努力讀書思考寫作,為內卷的人生奠定財務自由。

內容范疇:技術提升,職場雜談,事業發展,閱讀寫作,投資理財,健康人生。

csdn:https://blog.csdn.net/ccgshigao

博客園:https://www.cnblogs.com/qa-freeroad/

51cto:https://blog.51cto.com/14900374

微信公眾號:測試生財(定期分享獨家內容和資源)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM